floatguard/f32/guarded/
convert.rs

1use super::GuardedF32;
2use crate::FloatError;
3
4impl TryFrom<f32> for GuardedF32 {
5    type Error = FloatError;
6
7    /// Converts a `f32` to `GuardedF32`.
8    ///
9    /// # Returns
10    ///
11    /// Returns a `GuardedF32` if the value is valid (finite), otherwise returns an error.
12    ///
13    /// # Errors
14    ///
15    /// Returns `FloatError` if the value is NaN or infinite.
16    ///
17    /// # Example
18    ///
19    /// ```rust
20    /// use floatguard::{GuardedF32, FloatError};
21    ///
22    /// let valid_value = GuardedF32::new(2.0);
23    /// assert!(valid_value.is_ok());
24    ///
25    /// let invalid_value = GuardedF32::new(f32::NAN);
26    /// assert!(invalid_value.is_err());
27    ///
28    /// let inf_value = GuardedF32::new(f32::INFINITY);
29    /// assert!(inf_value.is_err());
30    /// ```
31    fn try_from(value: f32) -> Result<Self, Self::Error> {
32        Self::new(value)
33    }
34}
35
36/// Implementing the ability to convert `GuardedF32` to `f32` safely.
37///
38/// This conversion will return an error if the value is NaN or infinite.
39impl From<GuardedF32> for f32 {
40    /// Converts a `GuardedF32` to `f32`.
41    ///
42    /// # Returns
43    ///
44    /// Returns the inner `f32` value if it is valid (finite), otherwise returns an error.
45    ///
46    /// # Errors
47    ///
48    /// Returns `FloatError` if the value is NaN or infinite.
49    ///
50    /// # Example
51    ///
52    /// ```rust
53    /// use floatguard::{GuardedF32, FloatError};
54    ///
55    /// let valid_value = GuardedF32::new(2.0).unwrap();
56    /// assert_eq!(valid_value.try_into(), Ok(2.0));
57    ///
58    /// let invalid_value = GuardedF32::try_from(f32::NAN);
59    /// assert_eq!(invalid_value, Err(FloatError::NaN));
60    ///
61    /// let inf_value = GuardedF32::try_from(f32::INFINITY);
62    /// assert_eq!(inf_value, Err(FloatError::Infinity));
63    /// ```
64    fn from(value: GuardedF32) -> Self {
65        value.0
66    }
67}
68
69impl std::ops::Deref for GuardedF32 {
70    type Target = f32;
71
72    /// Dereferences `GuardedF32` to its inner `f32` value.
73    ///
74    /// # Returns
75    ///
76    /// Returns a reference to the inner `f32` value.
77    ///
78    /// # Example
79    ///
80    /// ```rust
81    /// use floatguard::GuardedF32;
82    ///
83    /// let value = GuardedF32::new(2.0).unwrap();
84    /// assert_eq!(*value, 2.0);
85    /// ```
86    fn deref(&self) -> &Self::Target {
87        &self.0
88    }
89}
90
91#[cfg(test)]
92mod tests {
93    #![allow(clippy::float_cmp)]
94
95    use super::*;
96    use crate::f32::tests::{invalid_f32, valid_f32};
97    use proptest::prelude::*;
98
99    proptest! {
100        #[test]
101        fn test_from_valid(a in valid_f32()) {
102            prop_assert_eq!(GuardedF32::new(a), Ok(GuardedF32(a)));
103            prop_assert_eq!(GuardedF32::new(a).map(f32::from), Ok(a));
104            prop_assert_eq!(*GuardedF32::new(a).unwrap(), a);
105
106            prop_assert_eq!(GuardedF32::try_from(a), Ok(GuardedF32(a)));
107        }
108
109        #[test]
110        fn test_from_invalid(a in invalid_f32()) {
111            let float_error = if a.is_nan() {
112                FloatError::NaN
113            } else if a.is_infinite() {
114                FloatError::Infinity
115            } else {
116                unreachable!()
117            };
118            prop_assert_eq!(GuardedF32::new(a), Err(float_error));
119
120            prop_assert_eq!(GuardedF32::try_from(a), Err(float_error));
121        }
122    }
123}