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::ClosedRange;
9use crate::Endpoint;
10use crate::RangeVec;
11
12/// Some functions don't care whether their input is normalized; they
13/// take `impl Into<RangeCase<...>>`.
14///
15/// When a function doesn't care about normalisation *and* doesn't want
16/// ownership, it can simply accept slices `&[(T, T)]`.
17#[derive(Clone, Debug)]
18pub struct RangeCase<T: Endpoint> {
19    inner: Backing<T>,
20    normalized: bool,
21}
22
23impl<T: Endpoint> RangeCase<T> {
24    /// Creates a [`RangeCase`] from a (not necessarily normalized) vector of ranges.
25    ///
26    /// This operation takes constant time.
27    #[inline(always)]
28    pub fn from_vec(inner: Vec<(T, T)>) -> Self {
29        Self {
30            inner: inner.into(),
31            normalized: false,
32        }
33    }
34
35    /// Creates a [`RangeCase`] from a (not necessarily normalized) smallvec of ranges.
36    ///
37    /// This operation takes constant time.
38    pub fn from_smallvec<const N: usize>(inner: SmallVec<[(T, T); N]>) -> Self {
39        // `INLINE_SIZE == 0` unless inline storage is enabled.
40        #[cfg_attr(
41            not(feature = "inline_storage"),
42            allow(clippy::absurd_extreme_comparisons)
43        )]
44        let inner: Backing<T> = if inner.len() <= crate::INLINE_SIZE {
45            inner.into_iter().collect()
46        } else {
47            inner.into_vec().into()
48        };
49
50        Self {
51            inner,
52            normalized: false,
53        }
54    }
55
56    /// Creates a [`RangeCase`] from a (not necessarily normalized) slice of ranges.
57    ///
58    /// This operation takes time linear in the length of the slice.
59    pub fn from_slice(slice: impl AsRef<[(T, T)]>) -> Self {
60        Self::from_smallvec::<{ crate::INLINE_SIZE }>(SmallVec::from_slice(slice.as_ref()))
61    }
62
63    /// Creates a [`RangeCase`] from a (normalized) [`RangeVec`]
64    ///
65    /// This operation takes constant time.
66    #[inline(always)]
67    pub fn from_range_vec(set: RangeVec<T>) -> Self {
68        Self {
69            inner: set.into_inner(),
70            normalized: true,
71        }
72    }
73
74    /// Returns the underlying vector
75    ///
76    /// This operation takes constant time.
77    #[inline(always)]
78    pub fn into_inner(self) -> Backing<T> {
79        self.inner
80    }
81
82    /// Returns a [`RangeVec`] if the underlying vector is known to be
83    /// normalized, and a [`Vec`] of ranges otherwise.
84    ///
85    /// This operation takes constant time.
86    #[inline(always)]
87    pub fn unerase(self) -> Result<RangeVec<T>, Backing<T>> {
88        if self.normalized {
89            Ok(unsafe { RangeVec::new_unchecked(self.inner) })
90        } else {
91            Err(self.inner)
92        }
93    }
94}
95
96impl<T: Endpoint> From<RangeVec<T>> for RangeCase<T> {
97    #[inline(always)]
98    fn from(item: RangeVec<T>) -> RangeCase<T> {
99        RangeCase::from_range_vec(item)
100    }
101}
102
103impl<T: Endpoint> From<Vec<(T, T)>> for RangeCase<T> {
104    #[inline(always)]
105    fn from(item: Vec<(T, T)>) -> RangeCase<T> {
106        RangeCase::from_vec(item)
107    }
108}
109
110impl<T: Endpoint, const N: usize> From<SmallVec<[(T, T); N]>> for RangeCase<T> {
111    #[inline(always)]
112    fn from(item: SmallVec<[(T, T); N]>) -> RangeCase<T> {
113        RangeCase::from_smallvec(item)
114    }
115}
116
117impl<T: Endpoint> From<&[(T, T)]> for RangeCase<T> {
118    #[inline(always)]
119    fn from(item: &[(T, T)]) -> RangeCase<T> {
120        RangeCase::from_slice(item)
121    }
122}
123
124impl<T: Endpoint, const N: usize> From<&[(T, T); N]> for RangeCase<T> {
125    #[inline(always)]
126    fn from(item: &[(T, T); N]) -> RangeCase<T> {
127        RangeCase::from_slice(item)
128    }
129}
130
131impl<T: Endpoint, const N: usize> From<[(T, T); N]> for RangeCase<T> {
132    #[inline(always)]
133    fn from(item: [(T, T); N]) -> RangeCase<T> {
134        RangeCase::from_slice(item)
135    }
136}
137
138impl<T: Endpoint> From<(T, T)> for RangeCase<T> {
139    #[inline(always)]
140    fn from(item: (T, T)) -> RangeCase<T> {
141        RangeCase::from_slice([item])
142    }
143}
144
145impl<T: Endpoint> From<Option<(T, T)>> for RangeCase<T> {
146    #[inline(always)]
147    fn from(item: Option<(T, T)>) -> RangeCase<T> {
148        RangeCase::from_slice(item.as_slice())
149    }
150}
151
152impl<T: Endpoint, Item> core::iter::FromIterator<Item> for RangeCase<T>
153where
154    Item: ClosedRange<EndT = T>,
155{
156    fn from_iter<It: IntoIterator<Item = Item>>(iter: It) -> Self {
157        Self::from_smallvec::<{ crate::INLINE_SIZE }>(iter.into_iter().map(|x| x.get()).collect())
158    }
159}
160
161#[cfg_attr(coverage_nightly, coverage(off))]
162#[test]
163fn test_smoke() {
164    use alloc::vec;
165    use smallvec::smallvec;
166
167    {
168        let empty_1: RangeCase<u8> = RangeCase::from_slice([]);
169        let empty_2: RangeCase<_> = None.into();
170        assert_eq!(empty_1.into_inner(), empty_2.into_inner());
171    }
172
173    let x: RangeCase<_> = vec![(1u8, 2u8)].into();
174    assert_eq!(x.clone().into_inner().into_vec(), vec![(1u8, 2u8)]);
175
176    // Test other 1-item conversions
177    {
178        let y: RangeCase<_> = (1u8, 2u8).into();
179        assert_eq!(x.clone().into_inner(), y.into_inner());
180
181        let y: RangeCase<_> = Some((1u8, 2u8)).into();
182        assert_eq!(x.clone().into_inner(), y.into_inner());
183    }
184
185    {
186        let x: RangeCase<_> = (&[(1u8, 2u8), (3u8, 4u8), (10u8, 255u8)][..]).into();
187        assert_eq!(
188            x.into_inner().into_vec(),
189            vec![(1u8, 2u8), (3u8, 4u8), (10u8, 255u8)]
190        );
191
192        let x: RangeCase<_> = [(1u8, 2u8)].into();
193        assert_eq!(x.into_inner().into_vec(), vec![(1u8, 2u8)]);
194
195        let x: RangeCase<_> = (&[(1u8, 2u8)]).into();
196        assert_eq!(x.into_inner().into_vec(), vec![(1u8, 2u8)]);
197    }
198
199    {
200        let smallvec: Backing<u8> = smallvec![(1u8, 2u8)];
201        let x: RangeCase<_> = smallvec.into();
202        assert_eq!(x.unerase().unwrap_err().into_vec(), vec![(1u8, 2u8)]);
203
204        let smallvec: Backing<u8> = smallvec![(1u8, 2u8), (10u8, 12u8), (20u8, 30u8)];
205        let x: RangeCase<_> = smallvec.into();
206        assert_eq!(
207            x.unerase().unwrap_err().into_vec(),
208            vec![(1u8, 2u8), (10u8, 12u8), (20u8, 30u8)]
209        );
210    }
211
212    {
213        let smallervec: SmallVec<[(u8, u8); 0]> = smallvec![(1u8, 2u8)];
214        let x: RangeCase<_> = smallervec.into();
215        assert_eq!(x.unerase().unwrap_err().into_vec(), vec![(1u8, 2u8)]);
216
217        let smallervec: SmallVec<[(u8, u8); 0]> = smallvec![(1u8, 2u8), (3u8, 4u8), (10u8, 11u8)];
218        let x: RangeCase<_> = smallervec.into();
219        assert_eq!(
220            x.unerase().unwrap_err().into_vec(),
221            vec![(1u8, 2u8), (3u8, 4u8), (10u8, 11u8)]
222        );
223    }
224
225    {
226        let largervec: SmallVec<[(u8, u8); crate::INLINE_SIZE + 1]> = smallvec![(1u8, 2u8)];
227        let x: RangeCase<_> = largervec.into();
228        assert_eq!(x.unerase().unwrap_err().into_vec(), vec![(1u8, 2u8)]);
229
230        let largervec: SmallVec<[(u8, u8); crate::INLINE_SIZE + 1]> =
231            smallvec![(1u8, 2u8), (3u8, 4u8), (10u8, 11u8)];
232        let x: RangeCase<_> = largervec.into();
233        assert_eq!(
234            x.unerase().unwrap_err().into_vec(),
235            vec![(1u8, 2u8), (3u8, 4u8), (10u8, 11u8)]
236        );
237    }
238
239    let itcase: RangeCase<u8> = RangeCase::from_iter(&[(1u8, 2u8)]);
240    assert_eq!(itcase.unerase().unwrap_err().into_vec(), vec![(1u8, 2u8)]);
241
242    let vec = unsafe { RangeVec::new_unchecked(smallvec![(1u8, 2u8)]) };
243    let x: RangeCase<_> = vec.clone().into();
244    assert_eq!(x.unerase().unwrap(), vec);
245}