axiolid_contracts/
displacement.rs1#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
7pub struct DisplacementBound(f64);
8
9impl Eq for DisplacementBound {}
10
11impl DisplacementBound {
12 pub const ZERO: Self = Self(0.0);
14
15 #[must_use]
18 pub fn new(value: f64) -> Option<Self> {
19 (value.is_finite() && value >= 0.0).then_some(Self(value + 0.0))
20 }
21
22 #[must_use]
24 pub const fn get(self) -> f64 {
25 self.0
26 }
27
28 #[must_use]
30 pub fn max(self, other: Self) -> Self {
31 if other.0 > self.0 {
32 other
33 } else {
34 self
35 }
36 }
37}
38
39#[cfg(test)]
40mod tests {
41 use super::*;
42
43 #[test]
44 fn only_finite_non_negative_values_are_bounds() {
45 for bad in [f64::NAN, f64::INFINITY, f64::NEG_INFINITY, -1.0, -1e-300] {
46 assert_eq!(DisplacementBound::new(bad), None, "{bad}");
47 }
48 assert_eq!(
49 DisplacementBound::new(0.5).map(DisplacementBound::get),
50 Some(0.5)
51 );
52 }
53
54 #[test]
55 fn negative_zero_becomes_positive_zero() {
56 let zero = DisplacementBound::new(-0.0).unwrap();
57 assert!(zero.get().is_sign_positive());
58 assert_eq!(zero, DisplacementBound::ZERO);
59 assert_eq!(DisplacementBound::default(), DisplacementBound::ZERO);
60 }
61
62 #[test]
63 fn max_takes_the_larger() {
64 let a = DisplacementBound::new(1.0).unwrap();
65 let b = DisplacementBound::new(2.0).unwrap();
66 assert_eq!(a.max(b), b);
67 assert_eq!(b.max(a), b);
68 assert_eq!(DisplacementBound::ZERO.max(a), a);
69 }
70
71 #[test]
72 fn bounds_are_eq_and_ordered() {
73 fn is_eq<T: Eq>() {}
74 is_eq::<DisplacementBound>();
75 assert!(DisplacementBound::ZERO < DisplacementBound::new(1e-300).unwrap());
76 }
77}