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