1use std::cmp::Ordering;
2use std::error::Error;
3use std::hash::{Hash, Hasher};
4use std::num::ParseFloatError;
5use std::str::FromStr;
6use std::{fmt, ops};
7
8use serde::{Deserialize, Serialize};
9
10#[derive(Clone, Copy, Default, PartialEq, Deserialize, Serialize)]
14#[serde(try_from = "f64")]
15#[repr(transparent)]
16pub struct FiniteF64(f64);
17
18impl FiniteF64 {
19 pub const MAX: Self = Self(f64::MAX);
21 pub const MIN: Self = Self(f64::MIN);
23 pub const EPSILON: Self = Self(f64::EPSILON);
25
26 #[must_use]
33 #[inline]
34 pub const unsafe fn new_unchecked(value: f64) -> Self {
35 Self(value)
36 }
37
38 #[must_use]
40 #[inline]
41 pub fn new(value: f64) -> Option<Self> {
42 if value.is_finite() {
43 Some(Self(value))
44 } else {
45 None
46 }
47 }
48
49 #[inline]
51 pub const fn to_f64(self) -> f64 {
52 self.0
53 }
54
55 pub fn abs(self) -> Self {
57 Self(self.0.abs())
58 }
59
60 pub fn max(self, other: Self) -> Self {
62 Self(self.0.max(other.0))
63 }
64
65 pub fn min(self, other: Self) -> Self {
67 Self(self.0.min(other.0))
68 }
69
70 pub fn saturating_add(self, other: Self) -> Self {
72 Self((self.0 + other.0).clamp(f64::MIN, f64::MAX))
73 }
74
75 pub fn saturating_sub(self, other: Self) -> Self {
77 Self((self.0 - other.0).clamp(f64::MIN, f64::MAX))
78 }
79
80 pub fn saturating_mul(self, other: Self) -> Self {
82 Self((self.0 * other.0).clamp(f64::MIN, f64::MAX))
83 }
84
85 pub fn saturating_div(self, other: Self) -> Self {
87 Self((self.0 / other.0).clamp(f64::MIN, f64::MAX))
88 }
89
90 }
92
93impl Eq for FiniteF64 {}
94
95impl PartialOrd for FiniteF64 {
96 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
97 Some(self.cmp(other))
98 }
99}
100
101impl Ord for FiniteF64 {
102 fn cmp(&self, other: &Self) -> Ordering {
103 self.0.partial_cmp(&other.0).unwrap_or(Ordering::Less)
105 }
106}
107
108impl Hash for FiniteF64 {
109 fn hash<H: Hasher>(&self, state: &mut H) {
110 self.0.to_bits().hash(state)
112 }
113}
114
115impl fmt::Debug for FiniteF64 {
116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117 self.0.fmt(f)
118 }
119}
120
121impl fmt::Display for FiniteF64 {
122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123 self.0.fmt(f)
124 }
125}
126
127impl ops::Add for FiniteF64 {
128 type Output = Option<Self>;
129
130 fn add(self, other: Self) -> Option<Self> {
131 Self::new(self.0 + other.0)
132 }
133}
134
135impl ops::Sub for FiniteF64 {
136 type Output = Option<Self>;
137
138 fn sub(self, other: Self) -> Option<Self> {
139 Self::new(self.0 - other.0)
140 }
141}
142
143impl ops::Mul for FiniteF64 {
144 type Output = Option<Self>;
145
146 fn mul(self, other: Self) -> Option<Self> {
147 Self::new(self.0 * other.0)
148 }
149}
150
151impl ops::Div for FiniteF64 {
152 type Output = Option<Self>;
153
154 fn div(self, other: Self) -> Option<Self> {
155 Self::new(self.0 / other.0)
156 }
157}
158
159impl ops::Rem for FiniteF64 {
160 type Output = Option<Self>;
161
162 fn rem(self, other: Self) -> Option<Self> {
163 Self::new(self.0 % other.0)
164 }
165}
166
167#[derive(Debug, thiserror::Error)]
169#[error("float is nan or infinite")]
170pub struct TryFromFloatError;
171
172impl TryFrom<f64> for FiniteF64 {
173 type Error = TryFromFloatError;
174
175 fn try_from(value: f64) -> Result<Self, Self::Error> {
176 Self::new(value).ok_or(TryFromFloatError)
177 }
178}
179
180impl TryFrom<f32> for FiniteF64 {
181 type Error = TryFromFloatError;
182
183 fn try_from(value: f32) -> Result<Self, Self::Error> {
184 f64::from(value).try_into()
185 }
186}
187
188impl From<i8> for FiniteF64 {
189 fn from(value: i8) -> Self {
190 unsafe { Self::new_unchecked(value.into()) }
191 }
192}
193
194impl From<i16> for FiniteF64 {
195 fn from(value: i16) -> Self {
196 unsafe { Self::new_unchecked(value.into()) }
197 }
198}
199
200impl From<i32> for FiniteF64 {
201 fn from(value: i32) -> Self {
202 unsafe { Self::new_unchecked(value.into()) }
203 }
204}
205
206impl From<u8> for FiniteF64 {
207 fn from(value: u8) -> Self {
208 unsafe { Self::new_unchecked(value.into()) }
209 }
210}
211
212impl From<u16> for FiniteF64 {
213 fn from(value: u16) -> Self {
214 unsafe { Self::new_unchecked(value.into()) }
215 }
216}
217
218impl From<u32> for FiniteF64 {
219 fn from(value: u32) -> Self {
220 unsafe { Self::new_unchecked(value.into()) }
221 }
222}
223
224impl From<FiniteF64> for f64 {
225 fn from(value: FiniteF64) -> Self {
226 value.to_f64()
227 }
228}
229
230#[derive(Debug)]
231enum ParseFiniteFloatErrorKind {
232 Invalid(ParseFloatError),
233 NonFinite(TryFromFloatError),
234}
235
236#[derive(Debug)]
238pub struct ParseFiniteFloatError(ParseFiniteFloatErrorKind);
239
240impl fmt::Display for ParseFiniteFloatError {
241 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242 match &self.0 {
243 ParseFiniteFloatErrorKind::Invalid(err) => err.fmt(f),
244 ParseFiniteFloatErrorKind::NonFinite(err) => err.fmt(f),
245 }
246 }
247}
248
249impl Error for ParseFiniteFloatError {
250 fn source(&self) -> Option<&(dyn Error + 'static)> {
251 match &self.0 {
252 ParseFiniteFloatErrorKind::Invalid(err) => Some(err),
253 ParseFiniteFloatErrorKind::NonFinite(err) => Some(err),
254 }
255 }
256}
257
258impl From<ParseFloatError> for ParseFiniteFloatError {
259 fn from(err: ParseFloatError) -> Self {
260 Self(ParseFiniteFloatErrorKind::Invalid(err))
261 }
262}
263
264impl From<TryFromFloatError> for ParseFiniteFloatError {
265 fn from(err: TryFromFloatError) -> Self {
266 Self(ParseFiniteFloatErrorKind::NonFinite(err))
267 }
268}
269
270impl FromStr for FiniteF64 {
271 type Err = ParseFiniteFloatError;
272
273 fn from_str(s: &str) -> Result<Self, Self::Err> {
274 Ok(s.parse::<f64>()?.try_into()?)
275 }
276}
277
278#[cfg(test)]
279mod tests {
280 use super::*;
281
282 #[test]
283 fn test_new() {
284 assert_eq!(FiniteF64::new(0.0), Some(FiniteF64(0.0)));
285 assert_eq!(FiniteF64::new(1.0), Some(FiniteF64(1.0)));
286 assert_eq!(FiniteF64::new(-1.0), Some(FiniteF64(-1.0)));
287 assert_eq!(FiniteF64::new(f64::MIN), Some(FiniteF64(f64::MIN)));
288 assert_eq!(FiniteF64::new(f64::MAX), Some(FiniteF64(f64::MAX)));
289 assert_eq!(FiniteF64::new(f64::NAN), None);
290 assert_eq!(FiniteF64::new(f64::INFINITY), None);
291 assert_eq!(FiniteF64::new(f64::NEG_INFINITY), None);
292 }
293
294 #[test]
295 fn test_arithmetics() {
296 assert_eq!(FiniteF64(1.0) + FiniteF64(1.0), Some(FiniteF64(2.0)));
297 assert_eq!(FiniteF64(f64::MAX) + FiniteF64(f64::MAX), None);
298 assert_eq!(FiniteF64(f64::MIN) + FiniteF64(f64::MIN), None);
299
300 assert_eq!(FiniteF64(1.0) - FiniteF64(1.0), Some(FiniteF64(0.0)));
301 assert_eq!(
302 FiniteF64(f64::MAX) - FiniteF64(f64::MAX),
303 Some(FiniteF64(0.0))
304 );
305 assert_eq!(
306 FiniteF64(f64::MIN) - FiniteF64(f64::MIN),
307 Some(FiniteF64(0.0))
308 );
309
310 assert_eq!(FiniteF64(2.0) * FiniteF64(2.0), Some(FiniteF64(4.0)));
311 assert_eq!(FiniteF64(f64::MAX) * FiniteF64(f64::MAX), None);
312 assert_eq!(FiniteF64(f64::MIN) * FiniteF64(f64::MIN), None);
313
314 assert_eq!(FiniteF64(2.0) / FiniteF64(2.0), Some(FiniteF64(1.0)));
315 assert_eq!(FiniteF64(2.0) / FiniteF64(0.0), None); assert_eq!(FiniteF64(-2.0) / FiniteF64(0.0), None); assert_eq!(FiniteF64(0.0) / FiniteF64(0.0), None); }
319
320 #[test]
321 fn test_saturating_add() {
322 assert_eq!(
323 FiniteF64(1.0).saturating_add(FiniteF64(1.0)),
324 FiniteF64(2.0)
325 );
326 assert_eq!(
327 FiniteF64(f64::MAX).saturating_add(FiniteF64(1.0)),
328 FiniteF64(f64::MAX)
329 );
330 assert_eq!(
331 FiniteF64(f64::MIN).saturating_add(FiniteF64(-1.0)),
332 FiniteF64(f64::MIN)
333 );
334 }
335
336 #[test]
337 fn test_saturating_sub() {
338 assert_eq!(
339 FiniteF64(1.0).saturating_sub(FiniteF64(1.0)),
340 FiniteF64(0.0)
341 );
342 assert_eq!(
343 FiniteF64(f64::MAX).saturating_sub(FiniteF64(-1.0)),
344 FiniteF64(f64::MAX)
345 );
346 assert_eq!(
347 FiniteF64(f64::MIN).saturating_sub(FiniteF64(1.0)),
348 FiniteF64(f64::MIN)
349 );
350 }
351
352 #[test]
353 fn test_saturating_mul() {
354 assert_eq!(
355 FiniteF64::from(2).saturating_mul(FiniteF64::from(2)),
356 FiniteF64::from(4)
357 );
358 assert_eq!(
359 FiniteF64(f64::MAX).saturating_mul(FiniteF64::from(2)),
360 FiniteF64(f64::MAX)
361 );
362 assert_eq!(
363 FiniteF64(f64::MIN).saturating_mul(FiniteF64::from(2)),
364 FiniteF64(f64::MIN)
365 );
366 }
367
368 #[test]
369 fn teste_parse() {
370 assert_eq!("0".parse::<FiniteF64>().unwrap(), FiniteF64(0.0));
371 assert_eq!("0.0".parse::<FiniteF64>().unwrap(), FiniteF64(0.0));
372
373 assert!("bla".parse::<FiniteF64>().is_err());
374 assert!("inf".parse::<FiniteF64>().is_err());
375 assert!("-inf".parse::<FiniteF64>().is_err());
376 assert!("NaN".parse::<FiniteF64>().is_err());
377 }
378}