Skip to main content

unsigned_float/
convert.rs

1use core::fmt;
2
3#[cfg(feature = "f128")]
4use crate::Uf64;
5use crate::{Uf8, Uf8E5M3, Uf16, Uf16E6M10, Uf32};
6
7#[derive(Clone, Copy, Debug, PartialEq, Eq)]
8/// Error returned by fallible conversions into unsigned float types.
9pub enum ConversionError {
10    /// The source value was less than zero.
11    Negative,
12    /// The source value was NaN.
13    Nan,
14    /// The source value was infinite.
15    Infinite,
16    /// The source value was too large for the target format.
17    Overflow,
18    /// The positive source value was too small for the target format.
19    Underflow,
20}
21
22impl fmt::Display for ConversionError {
23    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24        match self {
25            Self::Negative => f.write_str("value is negative"),
26            Self::Nan => f.write_str("value is NaN"),
27            Self::Infinite => f.write_str("value is infinite"),
28            Self::Overflow => f.write_str("value is too large"),
29            Self::Underflow => f.write_str("positive value is too small"),
30        }
31    }
32}
33
34pub(crate) fn check_finite_non_negative(value: f64) -> Result<(), ConversionError> {
35    if value.is_nan() {
36        Err(ConversionError::Nan)
37    } else if value.is_infinite() {
38        Err(ConversionError::Infinite)
39    } else if value < 0.0 {
40        Err(ConversionError::Negative)
41    } else {
42        Ok(())
43    }
44}
45
46pub(crate) fn check_encoded(
47    value: f64,
48    is_zero: bool,
49    is_infinite: bool,
50) -> Result<(), ConversionError> {
51    if is_infinite {
52        Err(ConversionError::Overflow)
53    } else if value != 0.0 && is_zero {
54        Err(ConversionError::Underflow)
55    } else {
56        Ok(())
57    }
58}
59
60macro_rules! impl_try_from_float {
61    ($float:ty, $($uf:ty),* $(,)?) => {
62        $(
63            impl TryFrom<$float> for $uf {
64                type Error = ConversionError;
65
66                fn try_from(value: $float) -> Result<Self, Self::Error> {
67                    Self::try_from_f64(value as f64)
68                }
69            }
70        )*
71    };
72}
73
74macro_rules! impl_try_from_unsigned_int {
75    ($($int:ty),* $(,)?) => {
76        $(
77            impl TryFrom<$int> for Uf8 {
78                type Error = ConversionError;
79
80                fn try_from(value: $int) -> Result<Self, Self::Error> {
81                    Self::try_from_f64(value as f64)
82                }
83            }
84
85            impl TryFrom<$int> for Uf16 {
86                type Error = ConversionError;
87
88                fn try_from(value: $int) -> Result<Self, Self::Error> {
89                    Self::try_from_f64(value as f64)
90                }
91            }
92
93            impl TryFrom<$int> for Uf8E5M3 {
94                type Error = ConversionError;
95
96                fn try_from(value: $int) -> Result<Self, Self::Error> {
97                    Self::try_from_f64(value as f64)
98                }
99            }
100
101            impl TryFrom<$int> for Uf16E6M10 {
102                type Error = ConversionError;
103
104                fn try_from(value: $int) -> Result<Self, Self::Error> {
105                    Self::try_from_f64(value as f64)
106                }
107            }
108
109            impl TryFrom<$int> for Uf32 {
110                type Error = ConversionError;
111
112                fn try_from(value: $int) -> Result<Self, Self::Error> {
113                    Self::try_from_f64(value as f64)
114                }
115            }
116        )*
117    };
118}
119
120macro_rules! impl_try_from_signed_int {
121    ($($int:ty),* $(,)?) => {
122        $(
123            impl TryFrom<$int> for Uf8 {
124                type Error = ConversionError;
125
126                fn try_from(value: $int) -> Result<Self, Self::Error> {
127                    if value < 0 {
128                        Err(ConversionError::Negative)
129                    } else {
130                        Self::try_from_f64(value as f64)
131                    }
132                }
133            }
134
135            impl TryFrom<$int> for Uf16 {
136                type Error = ConversionError;
137
138                fn try_from(value: $int) -> Result<Self, Self::Error> {
139                    if value < 0 {
140                        Err(ConversionError::Negative)
141                    } else {
142                        Self::try_from_f64(value as f64)
143                    }
144                }
145            }
146
147            impl TryFrom<$int> for Uf8E5M3 {
148                type Error = ConversionError;
149
150                fn try_from(value: $int) -> Result<Self, Self::Error> {
151                    if value < 0 {
152                        Err(ConversionError::Negative)
153                    } else {
154                        Self::try_from_f64(value as f64)
155                    }
156                }
157            }
158
159            impl TryFrom<$int> for Uf16E6M10 {
160                type Error = ConversionError;
161
162                fn try_from(value: $int) -> Result<Self, Self::Error> {
163                    if value < 0 {
164                        Err(ConversionError::Negative)
165                    } else {
166                        Self::try_from_f64(value as f64)
167                    }
168                }
169            }
170
171            impl TryFrom<$int> for Uf32 {
172                type Error = ConversionError;
173
174                fn try_from(value: $int) -> Result<Self, Self::Error> {
175                    if value < 0 {
176                        Err(ConversionError::Negative)
177                    } else {
178                        Self::try_from_f64(value as f64)
179                    }
180                }
181            }
182        )*
183    };
184}
185
186impl_try_from_float!(f64, Uf8, Uf8E5M3, Uf16, Uf16E6M10, Uf32);
187
188impl_try_from_unsigned_int!(u8, u16, u32, u64, u128, usize);
189impl_try_from_signed_int!(i8, i16, i32, i64, i128, isize);
190
191#[cfg(feature = "f128")]
192macro_rules! impl_try_from_unsigned_int_uf64 {
193    ($($int:ty),* $(,)?) => {
194        $(
195            impl TryFrom<$int> for Uf64 {
196                type Error = ConversionError;
197
198                fn try_from(value: $int) -> Result<Self, Self::Error> {
199                    Self::try_from_f128(value as f128)
200                }
201            }
202        )*
203    };
204}
205
206#[cfg(feature = "f128")]
207macro_rules! impl_try_from_signed_int_uf64 {
208    ($($int:ty),* $(,)?) => {
209        $(
210            impl TryFrom<$int> for Uf64 {
211                type Error = ConversionError;
212
213                fn try_from(value: $int) -> Result<Self, Self::Error> {
214                    if value < 0 {
215                        Err(ConversionError::Negative)
216                    } else {
217                        Self::try_from_f128(value as f128)
218                    }
219                }
220            }
221        )*
222    };
223}
224
225#[cfg(feature = "f128")]
226impl_try_from_unsigned_int_uf64!(u8, u16, u32, u64, u128, usize);
227
228#[cfg(feature = "f128")]
229impl_try_from_signed_int_uf64!(i8, i16, i32, i64, i128, isize);