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