locator.rs

  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}