twine_core/constraint/
non_zero.rs

1use std::cmp::Ordering;
2
3use num_traits::Zero;
4
5use super::{Constrained, Constraint, ConstraintError};
6
7/// Marker type enforcing that a value is non-zero (not equal to zero).
8///
9/// Use this type with [`Constrained<T, NonZero>`] to encode a non-zero
10/// constraint at the type level.
11///
12/// You can construct a value constrained to be non-zero using either the
13/// generic [`Constrained::new`] method or the convenient [`NonZero::new`]
14/// associated function.
15///
16/// # Examples
17///
18/// ```
19/// use twine_core::constraint::{Constrained, NonZero};
20///
21/// // Generic constructor:
22/// let x = Constrained::<_, NonZero>::new(1).unwrap();
23/// assert_eq!(x.into_inner(), 1);
24///
25/// // Associated constructor:
26/// let y = NonZero::new(-5.0).unwrap();
27/// assert_eq!(y.into_inner(), -5.0);
28///
29/// // Error cases:
30/// assert!(NonZero::new(0).is_err());
31/// assert!(NonZero::new(0.0).is_err());
32/// assert!(NonZero::new(f64::NAN).is_err());
33/// ```
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub struct NonZero;
36
37impl NonZero {
38    /// Constructs a [`Constrained<T, NonZero>`] if the value is not zero.
39    ///
40    /// # Errors
41    ///
42    /// Returns an error if the value is zero or not a number (`NaN`).
43    pub fn new<T: PartialOrd + Zero>(value: T) -> Result<Constrained<T, NonZero>, ConstraintError> {
44        Constrained::<T, NonZero>::new(value)
45    }
46}
47
48impl<T: PartialOrd + Zero> Constraint<T> for NonZero {
49    fn check(value: &T) -> Result<(), ConstraintError> {
50        match value.partial_cmp(&T::zero()) {
51            Some(Ordering::Greater | Ordering::Less) => Ok(()),
52            Some(Ordering::Equal) => Err(ConstraintError::Zero),
53            None => Err(ConstraintError::NotANumber),
54        }
55    }
56}
57
58#[cfg(test)]
59mod tests {
60    use super::*;
61
62    #[test]
63    fn integers() {
64        let one = Constrained::<_, NonZero>::new(1).unwrap();
65        assert_eq!(one.into_inner(), 1);
66
67        let neg_one = NonZero::new(-1).unwrap();
68        assert_eq!(neg_one.as_ref(), &-1);
69
70        assert!(NonZero::new(0).is_err());
71    }
72
73    #[test]
74    fn floats() {
75        assert!(Constrained::<f64, NonZero>::new(2.0).is_ok());
76        assert!(NonZero::new(-3.5).is_ok());
77        assert!(NonZero::new(0.0).is_err());
78        assert!(NonZero::new(f64::NAN).is_err());
79    }
80}