Skip to main content

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

1// SPDX-License-Identifier: MIT
2// Copyright (c) 2026 ReifyDB
3
4use bigdecimal::BigDecimal as BigDecimalInner;
5
6use super::*;
7
8macro_rules! impl_safe_convert_uint_to_signed {
9    ($($dst:ty),*) => {
10        $(
11            impl SafeConvert<$dst> for Uint {
12                fn checked_convert(self) -> Option<$dst> {
13                    <$dst>::try_from(&self.0).ok()
14                }
15
16                fn saturating_convert(self) -> $dst {
17                    if let Ok(val) = <$dst>::try_from(&self.0) {
18                        val
19                    } else {
20                        <$dst>::MAX
21                    }
22                }
23
24                fn wrapping_convert(self) -> $dst {
25                    if let Ok(val) = u64::try_from(&self.0) {
26                        val as $dst
27                    } else {
28                        self.saturating_convert()
29                    }
30                }
31            }
32        )*
33    };
34}
35
36macro_rules! impl_safe_convert_uint_to_unsigned {
37    ($($dst:ty),*) => {
38        $(
39            impl SafeConvert<$dst> for Uint {
40                fn checked_convert(self) -> Option<$dst> {
41                    <$dst>::try_from(&self.0).ok()
42                }
43
44                fn saturating_convert(self) -> $dst {
45                    if let Ok(val) = <$dst>::try_from(&self.0) {
46                        val
47                    } else {
48                        <$dst>::MAX
49                    }
50                }
51
52                fn wrapping_convert(self) -> $dst {
53                    if let Ok(val) = u64::try_from(&self.0) {
54                        val as $dst
55                    } else {
56                        self.saturating_convert()
57                    }
58                }
59            }
60        )*
61    };
62}
63
64macro_rules! impl_safe_convert_uint_to_float {
65    ($($dst:ty),*) => {
66        $(
67            impl SafeConvert<$dst> for Uint {
68                fn checked_convert(self) -> Option<$dst> {
69                    self.0.to_f64().and_then(|f| {
70                        if f.is_finite() {
71                            Some(f as $dst)
72                        } else {
73                            None
74                        }
75                    })
76                }
77
78                fn saturating_convert(self) -> $dst {
79                    if let Some(f) = self.0.to_f64() {
80                        if f.is_finite() {
81                            f as $dst
82                        } else {
83                            <$dst>::MAX
84                        }
85                    } else {
86                        <$dst>::MAX
87                    }
88                }
89
90                fn wrapping_convert(self) -> $dst {
91                    self.saturating_convert()
92                }
93            }
94        )*
95    };
96}
97
98impl_safe_convert_uint_to_signed!(i8, i16, i32, i64, i128);
99impl_safe_convert_uint_to_unsigned!(u8, u16, u32, u64, u128);
100impl_safe_convert_uint_to_float!(f32, f64);
101
102impl SafeConvert<Int> for Uint {
103	fn checked_convert(self) -> Option<Int> {
104		Some(Int(self.0))
105	}
106
107	fn saturating_convert(self) -> Int {
108		Int(self.0)
109	}
110
111	fn wrapping_convert(self) -> Int {
112		Int(self.0)
113	}
114}
115
116impl SafeConvert<Decimal> for Uint {
117	fn checked_convert(self) -> Option<Decimal> {
118		let big_decimal = BigDecimalInner::from(self.0);
119		Some(Decimal::from(big_decimal))
120	}
121
122	fn saturating_convert(self) -> Decimal {
123		let big_decimal = BigDecimalInner::from(self.0);
124		Decimal::from(big_decimal)
125	}
126
127	fn wrapping_convert(self) -> Decimal {
128		self.saturating_convert()
129	}
130}
131
132#[cfg(test)]
133pub mod tests {
134	use super::*;
135	mod i8 {
136		use super::*;
137
138		#[test]
139		fn test_checked_convert() {
140			let x = Uint::from(127u8);
141			let y: Option<i8> = x.checked_convert();
142			assert_eq!(y, Some(127i8));
143		}
144
145		#[test]
146		fn test_checked_convert_overflow() {
147			let x = Uint::from(128u8);
148			let y: Option<i8> = x.checked_convert();
149			assert_eq!(y, None);
150		}
151
152		#[test]
153		fn test_saturating_convert() {
154			let x = Uint::from(200u8);
155			let y: i8 = x.saturating_convert();
156			assert_eq!(y, i8::MAX);
157		}
158	}
159
160	mod i32 {
161		use super::*;
162
163		#[test]
164		fn test_checked_convert() {
165			let x = Uint::from(2147483647u32);
166			let y: Option<i32> = x.checked_convert();
167			assert_eq!(y, Some(2147483647i32));
168		}
169
170		#[test]
171		fn test_saturating_convert() {
172			let x = Uint::from(2147483648u32);
173			let y: i32 = x.saturating_convert();
174			assert_eq!(y, i32::MAX);
175		}
176	}
177
178	mod u8 {
179		use super::*;
180
181		#[test]
182		fn test_checked_convert() {
183			let x = Uint::from(255u16);
184			let y: Option<u8> = x.checked_convert();
185			assert_eq!(y, Some(255u8));
186		}
187
188		#[test]
189		fn test_checked_convert_overflow() {
190			let x = Uint::from(256u16);
191			let y: Option<u8> = x.checked_convert();
192			assert_eq!(y, None);
193		}
194
195		#[test]
196		fn test_saturating_convert() {
197			let x = Uint::from(1000u16);
198			let y: u8 = x.saturating_convert();
199			assert_eq!(y, u8::MAX);
200		}
201	}
202
203	mod u32 {
204		use super::*;
205
206		#[test]
207		fn test_checked_convert() {
208			let x = Uint::from(4294967295u64);
209			let y: Option<u32> = x.checked_convert();
210			assert_eq!(y, Some(4294967295u32));
211		}
212
213		#[test]
214		fn test_saturating_convert() {
215			let x = Uint::from(4294967296u64);
216			let y: u32 = x.saturating_convert();
217			assert_eq!(y, u32::MAX);
218		}
219	}
220
221	mod f32 {
222		use super::*;
223
224		#[test]
225		fn test_checked_convert() {
226			let x = Uint::from(42u32);
227			let y: Option<f32> = x.checked_convert();
228			assert_eq!(y, Some(42.0f32));
229		}
230
231		#[test]
232		fn test_saturating_convert() {
233			let x = Uint::from(1000u32);
234			let y: f32 = x.saturating_convert();
235			assert_eq!(y, 1000.0f32);
236		}
237	}
238
239	mod f64 {
240		use super::*;
241
242		#[test]
243		fn test_checked_convert() {
244			let x = Uint::from(42u32);
245			let y: Option<f64> = x.checked_convert();
246			assert_eq!(y, Some(42.0f64));
247		}
248
249		#[test]
250		fn test_saturating_convert() {
251			let x = Uint::from(1000u32);
252			let y: f64 = x.saturating_convert();
253			assert_eq!(y, 1000.0f64);
254		}
255	}
256
257	mod int {
258		use super::*;
259
260		#[test]
261		fn test_checked_convert() {
262			let x = Uint::from(42u32);
263			let y: Option<Int> = x.checked_convert();
264			assert!(y.is_some());
265			assert_eq!(y.unwrap().to_string(), "42");
266		}
267
268		#[test]
269		fn test_saturating_convert() {
270			let x = Uint::from(100u32);
271			let y: Int = x.saturating_convert();
272			assert_eq!(y.to_string(), "100");
273		}
274
275		#[test]
276		fn test_wrapping_convert() {
277			let x = Uint::from(0u32);
278			let y: Int = x.wrapping_convert();
279			assert_eq!(y.to_string(), "0");
280		}
281	}
282
283	mod decimal {
284		use super::*;
285
286		#[test]
287		fn test_checked_convert() {
288			let x = Uint::from(12345u32);
289			let y: Option<Decimal> = x.checked_convert();
290			assert!(y.is_some());
291			let decimal = y.unwrap();
292			assert_eq!(decimal.to_string(), "12345");
293		}
294
295		#[test]
296		fn test_checked_convert_zero() {
297			let x = Uint::from(0u32);
298			let y: Option<Decimal> = x.checked_convert();
299			assert!(y.is_some());
300			let decimal = y.unwrap();
301			assert_eq!(decimal.to_string(), "0");
302		}
303
304		#[test]
305		fn test_checked_convert_large() {
306			// Test with a very large unsigned number
307			let x = Uint::from(u128::MAX);
308			let y: Option<Decimal> = x.checked_convert();
309			assert!(y.is_some());
310			let decimal = y.unwrap();
311			assert_eq!(decimal.to_string(), "340282366920938463463374607431768211455");
312		}
313
314		#[test]
315		fn test_saturating_convert() {
316			let x = Uint::from(999999u32);
317			let y: Decimal = x.saturating_convert();
318			assert_eq!(y.to_string(), "999999");
319		}
320
321		#[test]
322		fn test_wrapping_convert() {
323			let x = Uint::from(100u32);
324			let y: Decimal = x.wrapping_convert();
325			assert_eq!(y.to_string(), "100");
326		}
327	}
328
329	mod self_conversion {
330		use super::*;
331
332		#[test]
333		fn test_checked_convert() {
334			let x = Uint::from(42u32);
335			let y: Option<Uint> = x.clone().checked_convert();
336			assert_eq!(y, Some(x));
337		}
338
339		#[test]
340		fn test_saturating_convert() {
341			let x = Uint::from(100u32);
342			let y: Uint = x.clone().saturating_convert();
343			assert_eq!(y, x);
344		}
345
346		#[test]
347		fn test_wrapping_convert() {
348			let x = Uint::from(999u32);
349			let y: Uint = x.clone().wrapping_convert();
350			assert_eq!(y, x);
351		}
352	}
353}