Skip to main content

allen_intervals/
non_empty.rs

1use core::cmp::Ordering;
2
3use crate::{Interval, IntervalError, IntervalFrom, IntervalFull, IntervalTo};
4
5/// An interval that is known not to be empty.
6///
7/// # Layout
8///
9/// `NonEmpty<T>` is guaranteed to have the same layout and bit validity as `T`
10/// with the exception that non-empty instances are valid.
11#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
12#[repr(transparent)]
13pub struct NonEmpty<T>(pub(crate) T);
14
15impl<T> NonEmpty<T> {
16    /// Creates a non-empty without checking whether the value is non-empty.
17    /// This results in undefined behavior if the value is empty.
18    ///
19    /// # Safety
20    ///
21    /// The value must not be empty.
22    #[inline]
23    pub unsafe fn new_unchecked(value: T) -> Self {
24        Self(value)
25    }
26}
27
28impl<T> TryFrom<Interval<T>> for NonEmpty<Interval<T>>
29where
30    T: PartialOrd,
31{
32    type Error = IntervalError;
33
34    fn try_from(value: Interval<T>) -> Result<Self, Self::Error> {
35        match value.start.partial_cmp(&value.end) {
36            Some(Ordering::Less) => Ok(Self(value)),
37            Some(Ordering::Equal) => Err(IntervalError::EmptyInterval),
38            Some(Ordering::Greater) => Err(IntervalError::EmptyInterval),
39            None => Err(IntervalError::AmbiguousOrder),
40        }
41    }
42}
43
44impl<T> From<IntervalTo<T>> for NonEmpty<IntervalTo<T>> {
45    #[inline]
46    fn from(value: IntervalTo<T>) -> Self {
47        Self(value)
48    }
49}
50
51impl<T> From<IntervalFrom<T>> for NonEmpty<IntervalFrom<T>> {
52    #[inline]
53    fn from(value: IntervalFrom<T>) -> Self {
54        Self(value)
55    }
56}
57
58impl From<IntervalFull> for NonEmpty<IntervalFull> {
59    #[inline]
60    fn from(value: IntervalFull) -> Self {
61        Self(value)
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn non_empty() {
71        let min = isize::min_value();
72        let mid = 0;
73        let max = isize::max_value();
74
75        assert_eq!(
76            NonEmpty::try_from(Interval {
77                start: min,
78                end: min
79            }),
80            Err(IntervalError::EmptyInterval)
81        );
82        assert_eq!(
83            NonEmpty::try_from(Interval {
84                start: mid,
85                end: mid
86            }),
87            Err(IntervalError::EmptyInterval)
88        );
89        assert_eq!(
90            NonEmpty::try_from(Interval {
91                start: max,
92                end: max
93            }),
94            Err(IntervalError::EmptyInterval)
95        );
96
97        assert_eq!(
98            NonEmpty::try_from(Interval {
99                start: max,
100                end: mid
101            }),
102            Err(IntervalError::EmptyInterval)
103        );
104        assert_eq!(
105            NonEmpty::try_from(Interval {
106                start: mid,
107                end: min
108            }),
109            Err(IntervalError::EmptyInterval)
110        );
111
112        assert_eq!(
113            NonEmpty::try_from(Interval {
114                start: min,
115                end: mid
116            }),
117            Ok(NonEmpty(Interval {
118                start: min,
119                end: mid
120            }))
121        );
122        assert_eq!(
123            NonEmpty::try_from(Interval {
124                start: mid,
125                end: max
126            }),
127            Ok(NonEmpty(Interval {
128                start: mid,
129                end: max
130            }))
131        );
132    }
133}