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