location.rs

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