cola/
utils.rs

1use core::cmp::Ord;
2use core::fmt::{Debug, Formatter, Result as FmtResult};
3use core::ops::{Add, Range as StdRange, RangeBounds, Sub};
4
5use crate::Length;
6
7#[derive(Clone, Copy, PartialEq, Eq, Hash)]
8#[cfg_attr(feature = "encode", derive(serde::Serialize, serde::Deserialize))]
9pub(crate) struct Range<T> {
10    pub start: T,
11    pub end: T,
12}
13
14impl<T: Debug> Debug for Range<T> {
15    fn fmt(&self, f: &mut Formatter) -> FmtResult {
16        write!(f, "{:?}..{:?}", self.start, self.end)
17    }
18}
19
20impl<T> From<StdRange<T>> for Range<T> {
21    #[inline]
22    fn from(range: StdRange<T>) -> Self {
23        Range { start: range.start, end: range.end }
24    }
25}
26
27impl<T> From<Range<T>> for StdRange<T> {
28    #[inline]
29    fn from(range: Range<T>) -> Self {
30        StdRange { start: range.start, end: range.end }
31    }
32}
33
34impl<T: Sub<T, Output = T> + Copy> Sub<T> for Range<T> {
35    type Output = Range<T>;
36
37    #[inline]
38    fn sub(self, value: T) -> Self::Output {
39        Range { start: self.start - value, end: self.end - value }
40    }
41}
42
43impl<T: Add<T, Output = T> + Copy> Add<T> for Range<T> {
44    type Output = Range<T>;
45
46    #[inline]
47    fn add(self, value: T) -> Self::Output {
48        Range { start: self.start + value, end: self.end + value }
49    }
50}
51
52impl<T> Range<T> {
53    #[inline]
54    pub fn len(&self) -> T
55    where
56        T: Sub<T, Output = T> + Copy,
57    {
58        self.end - self.start
59    }
60}
61
62pub(crate) trait RangeExt<T> {
63    fn contains_range(&self, range: Range<T>) -> bool;
64}
65
66impl<T: Ord> RangeExt<T> for StdRange<T> {
67    #[inline]
68    fn contains_range(&self, other: Range<T>) -> bool {
69        self.start <= other.start && self.end >= other.end
70    }
71}
72
73/// TODO: docs
74#[inline]
75pub(crate) fn get_two_mut<T>(
76    slice: &mut [T],
77    first_idx: usize,
78    second_idx: usize,
79) -> (&mut T, &mut T) {
80    debug_assert!(first_idx != second_idx);
81
82    if first_idx < second_idx {
83        debug_assert!(second_idx < slice.len());
84        let split_at = first_idx + 1;
85        let (first, second) = slice.split_at_mut(split_at);
86        (&mut first[first_idx], &mut second[second_idx - split_at])
87    } else {
88        debug_assert!(first_idx < slice.len());
89        let split_at = second_idx + 1;
90        let (first, second) = slice.split_at_mut(split_at);
91        (&mut second[first_idx - split_at], &mut first[second_idx])
92    }
93}
94
95/// TODO: docs
96#[inline]
97pub(crate) fn insert_in_slice<T>(slice: &mut [T], elem: T, at_offset: usize) {
98    debug_assert!(at_offset < slice.len());
99    slice[at_offset..].rotate_right(1);
100    slice[at_offset] = elem;
101}
102
103/// TODO: docs
104#[inline(always)]
105pub(crate) fn range_bounds_to_start_end<R>(
106    range: R,
107    lo: Length,
108    hi: Length,
109) -> (Length, Length)
110where
111    R: RangeBounds<Length>,
112{
113    use core::ops::Bound;
114
115    let start = match range.start_bound() {
116        Bound::Included(&n) => n,
117        Bound::Excluded(&n) => n + 1,
118        Bound::Unbounded => lo,
119    };
120
121    let end = match range.end_bound() {
122        Bound::Included(&n) => n + 1,
123        Bound::Excluded(&n) => n,
124        Bound::Unbounded => hi,
125    };
126
127    (start, end)
128}
129
130pub mod panic_messages {
131    use crate::Length;
132
133    #[track_caller]
134    #[cold]
135    #[inline(never)]
136    pub(crate) fn offset_out_of_bounds(offset: Length, len: Length) -> ! {
137        debug_assert!(offset > len);
138        panic!(
139            "offset out of bounds: the offset is {offset} but the length is \
140             {len}"
141        );
142    }
143
144    #[track_caller]
145    #[cold]
146    #[inline(never)]
147    pub(crate) fn replica_id_is_zero() -> ! {
148        panic!("invalid ReplicaId: must not be zero");
149    }
150
151    #[track_caller]
152    #[cold]
153    #[inline(never)]
154    pub(crate) fn start_greater_than_end(start: Length, end: Length) -> ! {
155        debug_assert!(start > end);
156        panic!(
157            "offset range's start is greater than its end: the start is \
158             {start} but the end is {end}"
159        );
160    }
161}