1use smallvec::{SmallVec, smallvec};
2use std::iter;
3use std::sync::LazyLock;
4
5static MIN: LazyLock<Locator> = LazyLock::new(Locator::min);
6static MAX: LazyLock<Locator> = LazyLock::new(Locator::max);
7
8/// An identifier for a position in a ordered collection.
9///
10/// Allows prepending and appending without needing to renumber existing locators
11/// using `Locator::between(lhs, rhs)`.
12///
13/// The initial location for a collection should be `Locator::between(Locator::min(), Locator::max())`,
14/// leaving room for items to be inserted before and after it.
15#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
16pub struct Locator(SmallVec<[u64; 4]>);
17
18impl Locator {
19 pub fn min() -> Self {
20 Self(smallvec![u64::MIN])
21 }
22
23 pub fn max() -> Self {
24 Self(smallvec![u64::MAX])
25 }
26
27 pub fn min_ref() -> &'static Self {
28 &MIN
29 }
30
31 pub fn max_ref() -> &'static Self {
32 &MAX
33 }
34
35 pub fn assign(&mut self, other: &Self) {
36 self.0.resize(other.0.len(), 0);
37 self.0.copy_from_slice(&other.0);
38 }
39
40 pub fn between(lhs: &Self, rhs: &Self) -> Self {
41 let lhs = lhs.0.iter().copied().chain(iter::repeat(u64::MIN));
42 let rhs = rhs.0.iter().copied().chain(iter::repeat(u64::MAX));
43 let mut location = SmallVec::new();
44 for (lhs, rhs) in lhs.zip(rhs) {
45 let mid = lhs + ((rhs.saturating_sub(lhs)) >> 48);
46 location.push(mid);
47 if mid > lhs {
48 break;
49 }
50 }
51 Self(location)
52 }
53
54 pub fn len(&self) -> usize {
55 self.0.len()
56 }
57
58 pub fn is_empty(&self) -> bool {
59 self.len() == 0
60 }
61}
62
63impl Default for Locator {
64 fn default() -> Self {
65 Self::min()
66 }
67}
68
69impl sum_tree::Item for Locator {
70 type Summary = Locator;
71
72 fn summary(&self, _cx: &()) -> Self::Summary {
73 self.clone()
74 }
75}
76
77impl sum_tree::KeyedItem for Locator {
78 type Key = Locator;
79
80 fn key(&self) -> Self::Key {
81 self.clone()
82 }
83}
84
85impl sum_tree::Summary for Locator {
86 type Context = ();
87
88 fn zero(_cx: &()) -> Self {
89 Default::default()
90 }
91
92 fn add_summary(&mut self, summary: &Self, _: &()) {
93 self.assign(summary);
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100 use rand::prelude::*;
101 use std::mem;
102
103 #[gpui::test(iterations = 100)]
104 fn test_locators(mut rng: StdRng) {
105 let mut lhs = Default::default();
106 let mut rhs = Default::default();
107 while lhs == rhs {
108 lhs = Locator(
109 (0..rng.random_range(1..=5))
110 .map(|_| rng.random_range(0..=100))
111 .collect(),
112 );
113 rhs = Locator(
114 (0..rng.random_range(1..=5))
115 .map(|_| rng.random_range(0..=100))
116 .collect(),
117 );
118 }
119
120 if lhs > rhs {
121 mem::swap(&mut lhs, &mut rhs);
122 }
123
124 let middle = Locator::between(&lhs, &rhs);
125 assert!(middle > lhs);
126 assert!(middle < rhs);
127 for ix in 0..middle.0.len() - 1 {
128 assert!(
129 middle.0[ix] == *lhs.0.get(ix).unwrap_or(&0)
130 || middle.0[ix] == *rhs.0.get(ix).unwrap_or(&0)
131 );
132 }
133 }
134}