1use lazy_static::lazy_static;
2use smallvec::{smallvec, SmallVec};
3use std::iter;
4
5lazy_static! {
6 pub static ref MIN: Locator = Locator::min();
7 pub static ref MAX: Locator = Locator::max();
8}
9
10#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
11pub struct Locator(SmallVec<[u64; 4]>);
12
13impl Locator {
14 pub fn min() -> Self {
15 Self(smallvec![u64::MIN])
16 }
17
18 pub fn max() -> Self {
19 Self(smallvec![u64::MAX])
20 }
21
22 pub fn from_index(ix: usize, count: usize) -> Self {
23 let id = (1 + ix as u64) * (u64::MAX / (count as u64 + 2));
24 Self(smallvec![id])
25 }
26
27 pub fn assign(&mut self, other: &Self) {
28 self.0.resize(other.0.len(), 0);
29 self.0.copy_from_slice(&other.0);
30 }
31
32 pub fn between(lhs: &Self, rhs: &Self) -> Self {
33 let lhs = lhs.0.iter().copied().chain(iter::repeat(u64::MIN));
34 let rhs = rhs.0.iter().copied().chain(iter::repeat(u64::MAX));
35 let mut location = SmallVec::new();
36 for (lhs, rhs) in lhs.zip(rhs) {
37 let mid = lhs + ((rhs.saturating_sub(lhs)) >> 48);
38 location.push(mid);
39 if mid > lhs {
40 break;
41 }
42 }
43 Self(location)
44 }
45
46 pub fn len(&self) -> usize {
47 self.0.len()
48 }
49}
50
51impl Default for Locator {
52 fn default() -> Self {
53 Self::min()
54 }
55}
56
57#[cfg(test)]
58mod tests {
59 use super::*;
60 use rand::prelude::*;
61 use std::mem;
62
63 #[gpui::test(iterations = 100)]
64 fn test_locators(mut rng: StdRng) {
65 let mut lhs = Default::default();
66 let mut rhs = Default::default();
67 while lhs == rhs {
68 lhs = Locator(
69 (0..rng.gen_range(1..=5))
70 .map(|_| rng.gen_range(0..=100))
71 .collect(),
72 );
73 rhs = Locator(
74 (0..rng.gen_range(1..=5))
75 .map(|_| rng.gen_range(0..=100))
76 .collect(),
77 );
78 }
79
80 if lhs > rhs {
81 mem::swap(&mut lhs, &mut rhs);
82 }
83
84 let middle = Locator::between(&lhs, &rhs);
85 assert!(middle > lhs);
86 assert!(middle < rhs);
87 for ix in 0..middle.0.len() - 1 {
88 assert!(
89 middle.0[ix] == *lhs.0.get(ix).unwrap_or(&0)
90 || middle.0[ix] == *rhs.0.get(ix).unwrap_or(&0)
91 );
92 }
93 }
94}