twine_models/support/constraint/unit_interval/
open.rs1use std::cmp::Ordering;
2
3use crate::support::constraint::{Constrained, Constraint, ConstraintError};
4
5use crate::support::constraint::UnitBounds;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
47pub struct UnitIntervalOpen;
48
49impl UnitIntervalOpen {
50 pub fn new<T: UnitBounds>(
60 value: T,
61 ) -> Result<Constrained<T, UnitIntervalOpen>, ConstraintError> {
62 Constrained::<T, UnitIntervalOpen>::new(value)
63 }
64}
65
66impl<T: UnitBounds> Constraint<T> for UnitIntervalOpen {
67 fn check(value: &T) -> Result<(), ConstraintError> {
68 match (value.partial_cmp(&T::zero()), value.partial_cmp(&T::one())) {
69 (None, _) | (_, None) => Err(ConstraintError::NotANumber),
70 (Some(Ordering::Less | Ordering::Equal), _) => Err(ConstraintError::BelowMinimum),
71 (_, Some(Ordering::Greater | Ordering::Equal)) => Err(ConstraintError::AboveMaximum),
72 _ => Ok(()),
73 }
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use crate::support::constraint::*;
80
81 use uom::si::{f64::Ratio, ratio::ratio};
82
83 #[test]
84 #[allow(clippy::float_cmp)]
85 fn floats_valid() {
86 assert!(Constrained::<f64, UnitIntervalOpen>::new(0.1).is_ok());
87 assert!(Constrained::<f64, UnitIntervalOpen>::new(0.9).is_ok());
88 assert!(UnitIntervalOpen::new(0.5).is_ok());
89 }
90
91 #[test]
92 fn floats_out_of_range() {
93 assert!(matches!(
94 UnitIntervalOpen::new(0.0),
95 Err(ConstraintError::BelowMinimum)
96 ));
97 assert!(matches!(
98 UnitIntervalOpen::new(-1.0),
99 Err(ConstraintError::BelowMinimum)
100 ));
101 assert!(matches!(
102 UnitIntervalOpen::new(1.0),
103 Err(ConstraintError::AboveMaximum)
104 ));
105 assert!(matches!(
106 UnitIntervalOpen::new(2.0),
107 Err(ConstraintError::AboveMaximum)
108 ));
109 }
110
111 #[test]
112 fn floats_nan_is_not_a_number() {
113 assert!(matches!(
114 UnitIntervalOpen::new(f64::NAN),
115 Err(ConstraintError::NotANumber)
116 ));
117 }
118
119 #[test]
120 #[allow(clippy::float_cmp)]
121 fn uom_ratio_valid() {
122 assert!(Constrained::<Ratio, UnitIntervalOpen>::new(Ratio::new::<ratio>(0.01)).is_ok());
123 assert!(Constrained::<Ratio, UnitIntervalOpen>::new(Ratio::new::<ratio>(0.99)).is_ok());
124 assert!(UnitIntervalOpen::new(Ratio::new::<ratio>(0.5)).is_ok());
125 }
126
127 #[test]
128 fn uom_ratio_out_of_range() {
129 assert!(matches!(
130 UnitIntervalOpen::new(Ratio::new::<ratio>(0.0)),
131 Err(ConstraintError::BelowMinimum)
132 ));
133 assert!(matches!(
134 UnitIntervalOpen::new(Ratio::new::<ratio>(1.0)),
135 Err(ConstraintError::AboveMaximum)
136 ));
137 }
138}