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    pub fn from_smallvec<const N: usize>(inner: SmallVec<[(T, T); N]>) -> Self {
37        // `INLINE_SIZE == 0` unless inline storage is enabled.
38        #[cfg_attr(
39            not(feature = "inline_storage"),
40            allow(clippy::absurd_extreme_comparisons)
41        )]
42        let inner: Backing<T> = if inner.len() <= crate::INLINE_SIZE {
43            inner.into_iter().collect()
44        } else {
45            inner.into_vec().into()
46        };
47
48        Self {
49            inner,
50            normalized: false,
51        }
52    }
53
54    /// Creates a [`RangeCase`] from a (normalized) [`RangeVec`]
55    ///
56    /// This operation takes constant time.
57    #[inline(always)]
58    pub fn from_range_vec(set: RangeVec<T>) -> Self {
59        Self {
60            inner: set.into_inner(),
61            normalized: true,
62        }
63    }
64
65    /// Returns the underlying vector
66    ///
67    /// This operation takes constant time.
68    #[inline(always)]
69    pub fn into_inner(self) -> Backing<T> {
70        self.inner
71    }
72
73    /// Returns a [`RangeVec`] if the underlying vector is known to be
74    /// normalized, and a [`Vec`] of ranges otherwise.
75    ///
76    /// This operation takes constant time.
77    #[inline(always)]
78    pub fn unerase(self) -> Result<RangeVec<T>, Backing<T>> {
79        if self.normalized {
80            Ok(unsafe { RangeVec::new_unchecked(self.inner) })
81        } else {
82            Err(self.inner)
83        }
84    }
85}
86
87impl<T: Endpoint> From<RangeVec<T>> for RangeCase<T> {
88    #[inline(always)]
89    fn from(item: RangeVec<T>) -> RangeCase<T> {
90        RangeCase::from_range_vec(item)
91    }
92}
93
94impl<T: Endpoint> From<Vec<(T, T)>> for RangeCase<T> {
95    #[inline(always)]
96    fn from(item: Vec<(T, T)>) -> RangeCase<T> {
97        RangeCase::from_vec(item)
98    }
99}
100
101impl<T: Endpoint, const N: usize> From<SmallVec<[(T, T); N]>> for RangeCase<T> {
102    #[inline(always)]
103    fn from(item: SmallVec<[(T, T); N]>) -> RangeCase<T> {
104        RangeCase::from_smallvec(item)
105    }
106}
107
108#[cfg_attr(coverage_nightly, coverage(off))]
109#[test]
110fn test_smoke() {
111    use alloc::vec;
112    use smallvec::smallvec;
113
114    let x: RangeCase<_> = vec![(1u8, 2u8)].into();
115    assert_eq!(x.into_inner().into_vec(), vec![(1u8, 2u8)]);
116
117    let smallvec: Backing<u8> = smallvec![(1u8, 2u8)];
118    let x: RangeCase<_> = smallvec.into();
119    assert_eq!(x.unerase().unwrap_err().into_vec(), vec![(1u8, 2u8)]);
120
121    let smallervec: SmallVec<[(u8, u8); 0]> = smallvec![(1u8, 2u8)];
122    let x: RangeCase<_> = smallervec.into();
123    assert_eq!(x.unerase().unwrap_err().into_vec(), vec![(1u8, 2u8)]);
124
125    let largervec: SmallVec<[(u8, u8); crate::INLINE_SIZE + 1]> = smallvec![(1u8, 2u8)];
126    let x: RangeCase<_> = largervec.into();
127    assert_eq!(x.unerase().unwrap_err().into_vec(), vec![(1u8, 2u8)]);
128
129    let vec = unsafe { RangeVec::new_unchecked(smallvec![(1u8, 2u8)]) };
130    let x: RangeCase<_> = vec.clone().into();
131    assert_eq!(x.unerase().unwrap(), vec);
132}