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}