closed_interval_set/
range_case.rs

1//! Sometimes we don't care about whether data comes in normalized or
2//! as arbitrary ranges.  This module defines traits and types to help
3//! reduce the burden on callers in such cases.
4use alloc::vec::Vec;
5use smallvec::SmallVec;
6
7use crate::Backing;
8use crate::Endpoint;
9use crate::RangeVec;
10
11/// Some functions don't care whether their input is normalized; they
12/// take `impl Into<RangeCase<...>>`.
13///
14/// When a function doesn't care about normalisation *and* doesn't want
15/// ownership, it can simply accept slices `&[(T, T)]`.
16pub struct RangeCase<T: Endpoint> {
17    inner: Backing<T>,
18    normalized: bool,
19}
20
21impl<T: Endpoint> RangeCase<T> {
22    /// Creates a [`RangeCase`] from a (not necessarily normalized) vector of ranges.
23    ///
24    /// This operation takes constant time.
25    #[inline(always)]
26    pub fn from_vec(inner: Vec<(T, T)>) -> Self {
27        Self {
28            inner: inner.into(),
29            normalized: false,
30        }
31    }
32
33    /// Creates a [`RangeCase`] from a (not necessarily normalized) smallvec of ranges.
34    ///
35    /// This operation takes constant time.
36    #[inline(always)]
37    pub fn from_smallvec<const N: usize>(inner: SmallVec<[(T, T); N]>) -> Self {
38        // `INLINE_SIZE == 0` unless inline storage is enabled.
39        #[cfg_attr(
40            not(feature = "inline_storage"),
41            allow(clippy::absurd_extreme_comparisons)
42        )]
43        let inner: Backing<T> = if inner.len() <= crate::INLINE_SIZE {
44            inner.into_iter().collect()
45        } else {
46            inner.into_vec().into()
47        };
48
49        Self {
50            inner,
51            normalized: false,
52        }
53    }
54
55    /// Creates a [`RangeCase`] from a (normalized) [`RangeVec`]
56    ///
57    /// This operation takes constant time.
58    #[inline(always)]
59    pub fn from_range_vec(set: RangeVec<T>) -> Self {
60        Self {
61            inner: set.into_inner(),
62            normalized: true,
63        }
64    }
65
66    /// Returns the underlying vector
67    ///
68    /// This operation takes constant time.
69    #[inline(always)]
70    pub fn into_inner(self) -> Backing<T> {
71        self.inner
72    }
73
74    /// Returns a [`RangeVec`] if the underlying vector is known to be
75    /// normalized, and a [`Vec`] of ranges otherwise.
76    ///
77    /// This operation takes constant time.
78    #[inline(always)]
79    pub fn unerase(self) -> Result<RangeVec<T>, Backing<T>> {
80        if self.normalized {
81            Ok(unsafe { RangeVec::new_unchecked(self.inner) })
82        } else {
83            Err(self.inner)
84        }
85    }
86}
87
88impl<T: Endpoint> From<RangeVec<T>> for RangeCase<T> {
89    #[inline(always)]
90    fn from(item: RangeVec<T>) -> RangeCase<T> {
91        RangeCase::from_range_vec(item)
92    }
93}
94
95impl<T: Endpoint> From<Vec<(T, T)>> for RangeCase<T> {
96    #[inline(always)]
97    fn from(item: Vec<(T, T)>) -> RangeCase<T> {
98        RangeCase::from_vec(item)
99    }
100}
101
102impl<T: Endpoint, const N: usize> From<SmallVec<[(T, T); N]>> for RangeCase<T> {
103    #[inline(always)]
104    fn from(item: SmallVec<[(T, T); N]>) -> RangeCase<T> {
105        RangeCase::from_smallvec(item)
106    }
107}
108
109#[cfg_attr(coverage_nightly, coverage(off))]
110#[test]
111fn test_smoke() {
112    use alloc::vec;
113    use smallvec::smallvec;
114
115    let x: RangeCase<_> = vec![(1u8, 2u8)].into();
116    assert_eq!(x.into_inner().into_vec(), vec![(1u8, 2u8)]);
117
118    let smallvec: Backing<u8> = smallvec![(1u8, 2u8)];
119    let x: RangeCase<_> = smallvec.into();
120    assert_eq!(x.unerase().unwrap_err().into_vec(), vec![(1u8, 2u8)]);
121
122    let smallervec: SmallVec<[(u8, u8); 0]> = smallvec![(1u8, 2u8)];
123    let x: RangeCase<_> = smallervec.into();
124    assert_eq!(x.unerase().unwrap_err().into_vec(), vec![(1u8, 2u8)]);
125
126    let largervec: SmallVec<[(u8, u8); crate::INLINE_SIZE + 1]> = smallvec![(1u8, 2u8)];
127    let x: RangeCase<_> = largervec.into();
128    assert_eq!(x.unerase().unwrap_err().into_vec(), vec![(1u8, 2u8)]);
129
130    let vec = unsafe { RangeVec::new_unchecked(smallvec![(1u8, 2u8)]) };
131    let x: RangeCase<_> = vec.clone().into();
132    assert_eq!(x.unerase().unwrap(), vec);
133}