Skip to main content

reifydb_value/value/number/safe/convert/
f32.rs

1// SPDX-License-Identifier: MIT
2// Copyright (c) 2026 ReifyDB
3
4use super::*;
5
6impl_safe_convert_promote!(f32 => f64);
7
8impl_safe_convert_float_to_signed!(f32 => i8, i16, i32, i64, i128);
9
10impl_safe_convert_float_to_unsigned!(f32 => u8, u16, u32, u64, u128);
11
12impl_safe_convert_float_to_int!(f32);
13impl_safe_convert_float_to_uint!(f32);
14
15impl_safe_convert_to_decimal_from_float!(f32);
16
17#[cfg(test)]
18pub mod tests {
19	mod f64 {
20		use super::*;
21		use crate::value::number::safe::convert::SafeConvert;
22
23		#[test]
24		fn test_checked_convert() {
25			let x: f32 = 123.456;
26			let y: Option<f64> = x.checked_convert();
27			assert_eq!(y, Some(x as f64));
28		}
29
30		#[test]
31		fn test_saturating_convert() {
32			let x: f32 = f32::MAX;
33			let y: f64 = x.saturating_convert();
34			assert_eq!(y, f32::MAX as f64);
35		}
36
37		#[test]
38		fn test_wrapping_convert() {
39			let x: f32 = f32::NEG_INFINITY;
40			let y: f64 = x.wrapping_convert();
41			assert_eq!(y, f64::NEG_INFINITY);
42		}
43	}
44
45	mod i8 {
46		use crate::value::number::safe::convert::SafeConvert;
47
48		#[test]
49		fn test_checked_convert_happy() {
50			let x: f32 = 42.0;
51			let y: Option<i8> = x.checked_convert();
52			assert_eq!(y, Some(42i8));
53		}
54
55		#[test]
56		fn test_checked_convert_unhappy() {
57			let x: f32 = 300.0;
58			let y: Option<i8> = x.checked_convert();
59			assert_eq!(y, None);
60		}
61
62		#[test]
63		fn test_checked_convert_negative() {
64			let x: f32 = -42.0;
65			let y: Option<i8> = x.checked_convert();
66			assert_eq!(y, Some(-42i8));
67		}
68
69		#[test]
70		fn test_checked_convert_nan() {
71			let x: f32 = f32::NAN;
72			let y: Option<i8> = x.checked_convert();
73			assert_eq!(y, None);
74		}
75
76		#[test]
77		fn test_checked_convert_infinity() {
78			let x: f32 = f32::INFINITY;
79			let y: Option<i8> = x.checked_convert();
80			assert_eq!(y, None);
81		}
82
83		#[test]
84		fn test_saturating_convert_overflow() {
85			let x: f32 = 300.0;
86			let y: i8 = x.saturating_convert();
87			assert_eq!(y, i8::MAX);
88		}
89
90		#[test]
91		fn test_saturating_convert_underflow() {
92			let x: f32 = -300.0;
93			let y: i8 = x.saturating_convert();
94			assert_eq!(y, i8::MIN);
95		}
96
97		#[test]
98		fn test_saturating_convert_nan() {
99			let x: f32 = f32::NAN;
100			let y: i8 = x.saturating_convert();
101			assert_eq!(y, 0);
102		}
103
104		#[test]
105		fn test_saturating_convert_infinity() {
106			let x: f32 = f32::INFINITY;
107			let y: i8 = x.saturating_convert();
108			assert_eq!(y, i8::MAX);
109		}
110
111		#[test]
112		fn test_saturating_convert_neg_infinity() {
113			let x: f32 = f32::NEG_INFINITY;
114			let y: i8 = x.saturating_convert();
115			assert_eq!(y, i8::MIN);
116		}
117
118		#[test]
119		fn test_wrapping_convert() {
120			let x: f32 = 42.0;
121			let y: i8 = x.wrapping_convert();
122			assert_eq!(y, 42i8);
123		}
124
125		#[test]
126		fn test_wrapping_convert_nan() {
127			let x: f32 = f32::NAN;
128			let y: i8 = x.wrapping_convert();
129			assert_eq!(y, 0);
130		}
131	}
132
133	mod i16 {
134		use crate::value::number::safe::convert::SafeConvert;
135
136		#[test]
137		fn test_checked_convert_happy() {
138			let x: f32 = 42.0;
139			let y: Option<i16> = x.checked_convert();
140			assert_eq!(y, Some(42i16));
141		}
142
143		#[test]
144		fn test_checked_convert_unhappy() {
145			let x: f32 = 40000.0;
146			let y: Option<i16> = x.checked_convert();
147			assert_eq!(y, None);
148		}
149
150		#[test]
151		fn test_checked_convert_negative() {
152			let x: f32 = -42.0;
153			let y: Option<i16> = x.checked_convert();
154			assert_eq!(y, Some(-42i16));
155		}
156
157		#[test]
158		fn test_checked_convert_nan() {
159			let x: f32 = f32::NAN;
160			let y: Option<i16> = x.checked_convert();
161			assert_eq!(y, None);
162		}
163
164		#[test]
165		fn test_saturating_convert_overflow() {
166			let x: f32 = 40000.0;
167			let y: i16 = x.saturating_convert();
168			assert_eq!(y, i16::MAX);
169		}
170
171		#[test]
172		fn test_saturating_convert_underflow() {
173			let x: f32 = -40000.0;
174			let y: i16 = x.saturating_convert();
175			assert_eq!(y, i16::MIN);
176		}
177
178		#[test]
179		fn test_wrapping_convert() {
180			let x: f32 = 42.0;
181			let y: i16 = x.wrapping_convert();
182			assert_eq!(y, 42i16);
183		}
184	}
185
186	mod i32 {
187		use crate::value::number::safe::convert::SafeConvert;
188
189		#[test]
190		fn test_checked_convert_happy() {
191			let x: f32 = 42.0;
192			let y: Option<i32> = x.checked_convert();
193			assert_eq!(y, Some(42i32));
194		}
195
196		#[test]
197		fn test_checked_convert_unhappy() {
198			let x: f32 = 3e38;
199			let y: Option<i32> = x.checked_convert();
200			assert_eq!(y, None);
201		}
202
203		#[test]
204		fn test_checked_convert_negative() {
205			let x: f32 = -42.0;
206			let y: Option<i32> = x.checked_convert();
207			assert_eq!(y, Some(-42i32));
208		}
209
210		#[test]
211		fn test_saturating_convert_overflow() {
212			let x: f32 = 3e38;
213			let y: i32 = x.saturating_convert();
214			assert_eq!(y, i32::MAX);
215		}
216
217		#[test]
218		fn test_saturating_convert_underflow() {
219			let x: f32 = -3e38;
220			let y: i32 = x.saturating_convert();
221			assert_eq!(y, i32::MIN);
222		}
223
224		#[test]
225		fn test_wrapping_convert() {
226			let x: f32 = 42.0;
227			let y: i32 = x.wrapping_convert();
228			assert_eq!(y, 42i32);
229		}
230	}
231
232	mod i64 {
233		use crate::value::number::safe::convert::SafeConvert;
234
235		#[test]
236		fn test_checked_convert_happy() {
237			let x: f32 = 42.0;
238			let y: Option<i64> = x.checked_convert();
239			assert_eq!(y, Some(42i64));
240		}
241
242		#[test]
243		fn test_checked_convert_unhappy() {
244			let x: f32 = 3e38;
245			let y: Option<i64> = x.checked_convert();
246			assert_eq!(y, None);
247		}
248
249		#[test]
250		fn test_checked_convert_negative() {
251			let x: f32 = -42.0;
252			let y: Option<i64> = x.checked_convert();
253			assert_eq!(y, Some(-42i64));
254		}
255
256		#[test]
257		fn test_saturating_convert_overflow() {
258			let x: f32 = 3e38;
259			let y: i64 = x.saturating_convert();
260			assert_eq!(y, i64::MAX);
261		}
262
263		#[test]
264		fn test_saturating_convert_underflow() {
265			let x: f32 = -3e38;
266			let y: i64 = x.saturating_convert();
267			assert_eq!(y, i64::MIN);
268		}
269
270		#[test]
271		fn test_wrapping_convert() {
272			let x: f32 = 42.0;
273			let y: i64 = x.wrapping_convert();
274			assert_eq!(y, 42i64);
275		}
276	}
277
278	mod i128 {
279		use crate::value::number::safe::convert::SafeConvert;
280
281		#[test]
282		fn test_checked_convert_happy() {
283			let x: f32 = 42.0;
284			let y: Option<i128> = x.checked_convert();
285			assert_eq!(y, Some(42i128));
286		}
287
288		#[test]
289		fn test_checked_convert_unhappy() {
290			let x: f32 = 3e38;
291			let y: Option<i128> = x.checked_convert();
292			assert_eq!(y, None);
293		}
294
295		#[test]
296		fn test_checked_convert_negative() {
297			let x: f32 = -42.0;
298			let y: Option<i128> = x.checked_convert();
299			assert_eq!(y, Some(-42i128));
300		}
301
302		#[test]
303		fn test_saturating_convert_overflow() {
304			let x: f32 = 3e38;
305			let y: i128 = x.saturating_convert();
306			assert_eq!(y, i128::MAX);
307		}
308
309		#[test]
310		fn test_saturating_convert_underflow() {
311			let x: f32 = -3e38;
312			let y: i128 = x.saturating_convert();
313			assert_eq!(y, i128::MIN);
314		}
315
316		#[test]
317		fn test_wrapping_convert() {
318			let x: f32 = 42.0;
319			let y: i128 = x.wrapping_convert();
320			assert_eq!(y, 42i128);
321		}
322	}
323
324	mod u8 {
325		use crate::value::number::safe::convert::SafeConvert;
326
327		#[test]
328		fn test_checked_convert_happy() {
329			let x: f32 = 42.0;
330			let y: Option<u8> = x.checked_convert();
331			assert_eq!(y, Some(42u8));
332		}
333
334		#[test]
335		fn test_checked_convert_unhappy() {
336			let x: f32 = 300.0;
337			let y: Option<u8> = x.checked_convert();
338			assert_eq!(y, None);
339		}
340
341		#[test]
342		fn test_checked_convert_negative() {
343			let x: f32 = -42.0;
344			let y: Option<u8> = x.checked_convert();
345			assert_eq!(y, None);
346		}
347
348		#[test]
349		fn test_checked_convert_nan() {
350			let x: f32 = f32::NAN;
351			let y: Option<u8> = x.checked_convert();
352			assert_eq!(y, None);
353		}
354
355		#[test]
356		fn test_checked_convert_infinity() {
357			let x: f32 = f32::INFINITY;
358			let y: Option<u8> = x.checked_convert();
359			assert_eq!(y, None);
360		}
361
362		#[test]
363		fn test_saturating_convert_overflow() {
364			let x: f32 = 300.0;
365			let y: u8 = x.saturating_convert();
366			assert_eq!(y, u8::MAX);
367		}
368
369		#[test]
370		fn test_saturating_convert_underflow() {
371			let x: f32 = -42.0;
372			let y: u8 = x.saturating_convert();
373			assert_eq!(y, 0);
374		}
375
376		#[test]
377		fn test_saturating_convert_nan() {
378			let x: f32 = f32::NAN;
379			let y: u8 = x.saturating_convert();
380			assert_eq!(y, 0);
381		}
382
383		#[test]
384		fn test_saturating_convert_infinity() {
385			let x: f32 = f32::INFINITY;
386			let y: u8 = x.saturating_convert();
387			assert_eq!(y, u8::MAX);
388		}
389
390		#[test]
391		fn test_wrapping_convert() {
392			let x: f32 = 42.0;
393			let y: u8 = x.wrapping_convert();
394			assert_eq!(y, 42u8);
395		}
396
397		#[test]
398		fn test_wrapping_convert_negative() {
399			let x: f32 = -42.0;
400			let y: u8 = x.wrapping_convert();
401			assert_eq!(y, 0);
402		}
403	}
404
405	mod u16 {
406		use crate::value::number::safe::convert::SafeConvert;
407
408		#[test]
409		fn test_checked_convert_happy() {
410			let x: f32 = 42.0;
411			let y: Option<u16> = x.checked_convert();
412			assert_eq!(y, Some(42u16));
413		}
414
415		#[test]
416		fn test_checked_convert_unhappy() {
417			let x: f32 = 70000.0;
418			let y: Option<u16> = x.checked_convert();
419			assert_eq!(y, None);
420		}
421
422		#[test]
423		fn test_checked_convert_negative() {
424			let x: f32 = -42.0;
425			let y: Option<u16> = x.checked_convert();
426			assert_eq!(y, None);
427		}
428
429		#[test]
430		fn test_saturating_convert_overflow() {
431			let x: f32 = 70000.0;
432			let y: u16 = x.saturating_convert();
433			assert_eq!(y, u16::MAX);
434		}
435
436		#[test]
437		fn test_saturating_convert_underflow() {
438			let x: f32 = -42.0;
439			let y: u16 = x.saturating_convert();
440			assert_eq!(y, 0);
441		}
442
443		#[test]
444		fn test_wrapping_convert() {
445			let x: f32 = 42.0;
446			let y: u16 = x.wrapping_convert();
447			assert_eq!(y, 42u16);
448		}
449	}
450
451	mod u32 {
452		use crate::value::number::safe::convert::SafeConvert;
453
454		#[test]
455		fn test_checked_convert_happy() {
456			let x: f32 = 42.0;
457			let y: Option<u32> = x.checked_convert();
458			assert_eq!(y, Some(42u32));
459		}
460
461		#[test]
462		fn test_checked_convert_unhappy() {
463			let x: f32 = 3e38;
464			let y: Option<u32> = x.checked_convert();
465			assert_eq!(y, None);
466		}
467
468		#[test]
469		fn test_checked_convert_negative() {
470			let x: f32 = -42.0;
471			let y: Option<u32> = x.checked_convert();
472			assert_eq!(y, None);
473		}
474
475		#[test]
476		fn test_saturating_convert_overflow() {
477			let x: f32 = 3e38;
478			let y: u32 = x.saturating_convert();
479			assert_eq!(y, u32::MAX);
480		}
481
482		#[test]
483		fn test_saturating_convert_underflow() {
484			let x: f32 = -42.0;
485			let y: u32 = x.saturating_convert();
486			assert_eq!(y, 0);
487		}
488
489		#[test]
490		fn test_wrapping_convert() {
491			let x: f32 = 42.0;
492			let y: u32 = x.wrapping_convert();
493			assert_eq!(y, 42u32);
494		}
495	}
496
497	mod u64 {
498		use crate::value::number::safe::convert::SafeConvert;
499
500		#[test]
501		fn test_checked_convert_happy() {
502			let x: f32 = 42.0;
503			let y: Option<u64> = x.checked_convert();
504			assert_eq!(y, Some(42u64));
505		}
506
507		#[test]
508		fn test_checked_convert_unhappy() {
509			let x: f32 = 3e38;
510			let y: Option<u64> = x.checked_convert();
511			assert_eq!(y, None);
512		}
513
514		#[test]
515		fn test_checked_convert_negative() {
516			let x: f32 = -42.0;
517			let y: Option<u64> = x.checked_convert();
518			assert_eq!(y, None);
519		}
520
521		#[test]
522		fn test_saturating_convert_overflow() {
523			let x: f32 = 3e38;
524			let y: u64 = x.saturating_convert();
525			assert_eq!(y, u64::MAX);
526		}
527
528		#[test]
529		fn test_saturating_convert_underflow() {
530			let x: f32 = -42.0;
531			let y: u64 = x.saturating_convert();
532			assert_eq!(y, 0);
533		}
534
535		#[test]
536		fn test_wrapping_convert() {
537			let x: f32 = 42.0;
538			let y: u64 = x.wrapping_convert();
539			assert_eq!(y, 42u64);
540		}
541	}
542
543	mod u128 {
544		use crate::value::number::safe::convert::SafeConvert;
545
546		#[test]
547		fn test_checked_convert_happy() {
548			let x: f32 = 42.0;
549			let y: Option<u128> = x.checked_convert();
550			assert_eq!(y, Some(42u128));
551		}
552
553		#[test]
554		fn test_checked_convert_negative() {
555			let x: f32 = -42.0;
556			let y: Option<u128> = x.checked_convert();
557			assert_eq!(y, None);
558		}
559
560		#[test]
561		fn test_saturating_convert_underflow() {
562			let x: f32 = -42.0;
563			let y: u128 = x.saturating_convert();
564			assert_eq!(y, 0);
565		}
566
567		#[test]
568		fn test_wrapping_convert() {
569			let x: f32 = 42.0;
570			let y: u128 = x.wrapping_convert();
571			assert_eq!(y, 42u128);
572		}
573	}
574
575	mod decimal {
576		use crate::value::{decimal::Decimal, number::safe::convert::SafeConvert};
577
578		#[test]
579		fn test_checked_convert() {
580			let x: f32 = 42.5;
581			let y: Option<Decimal> = x.checked_convert();
582			assert!(y.is_some());
583			let decimal = y.unwrap();
584			assert_eq!(decimal.to_string(), "42.5");
585		}
586
587		#[test]
588		fn test_checked_convert_integer() {
589			let x: f32 = 100.0;
590			let y: Option<Decimal> = x.checked_convert();
591			assert!(y.is_some());
592			let decimal = y.unwrap();
593			assert_eq!(decimal.to_string(), "100");
594		}
595
596		#[test]
597		fn test_checked_convert_small_decimal() {
598			let x: f32 = 0.125;
599			let y: Option<Decimal> = x.checked_convert();
600			assert!(y.is_some());
601			let decimal = y.unwrap();
602			assert_eq!(decimal.to_string(), "0.125");
603		}
604
605		#[test]
606		fn test_checked_convert_negative() {
607			let x: f32 = -123.456;
608			let y: Option<Decimal> = x.checked_convert();
609			assert!(y.is_some());
610			let decimal = y.unwrap();
611			// f32 has limited precision, so the value might not be
612			// exact
613			assert!(decimal.to_string().starts_with("-123.45"));
614			// Precision includes all significant digits
615		}
616
617		#[test]
618		fn test_checked_convert_zero() {
619			let x: f32 = 0.0;
620			let y: Option<Decimal> = x.checked_convert();
621			assert!(y.is_some());
622			let decimal = y.unwrap();
623			assert_eq!(decimal.to_string(), "0");
624		}
625
626		#[test]
627		fn test_checked_convert_nan() {
628			let x: f32 = f32::NAN;
629			let y: Option<Decimal> = x.checked_convert();
630			assert!(y.is_none());
631		}
632
633		#[test]
634		fn test_checked_convert_infinity() {
635			let x: f32 = f32::INFINITY;
636			let y: Option<Decimal> = x.checked_convert();
637			assert!(y.is_none());
638		}
639
640		#[test]
641		fn test_checked_convert_neg_infinity() {
642			let x: f32 = f32::NEG_INFINITY;
643			let y: Option<Decimal> = x.checked_convert();
644			assert!(y.is_none());
645		}
646
647		#[test]
648		fn test_saturating_convert() {
649			let x: f32 = 999.99;
650			let y: Decimal = x.saturating_convert();
651			// f32 precision affects the exact value
652			assert!(y.to_string().starts_with("999.9"));
653		}
654
655		#[test]
656		fn test_saturating_convert_nan() {
657			let x: f32 = f32::NAN;
658			let y: Decimal = x.saturating_convert();
659			assert_eq!(y.to_string(), "0");
660		}
661
662		#[test]
663		fn test_saturating_convert_infinity() {
664			let x: f32 = f32::INFINITY;
665			let y: Decimal = x.saturating_convert();
666			assert_eq!(y.to_string(), "0");
667		}
668
669		#[test]
670		fn test_wrapping_convert() {
671			let x: f32 = 42.0;
672			let y: Decimal = x.wrapping_convert();
673			assert_eq!(y.to_string(), "42");
674		}
675	}
676}