Skip to main content

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

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