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}