reifydb_type/value/uint/
mod.rs

1// Copyright (c) reifydb.com 2025
2// This file is licensed under the MIT, see license.md file
3
4use std::{
5	cmp::Ordering,
6	fmt::{Display, Formatter},
7	hash::{Hash, Hasher},
8	ops::Deref,
9};
10
11use num_bigint::BigInt as StdBigInt;
12use num_traits::Signed;
13use serde::{Deserialize, Serialize};
14
15pub mod parse;
16pub use parse::parse_uint;
17
18/// A wrapper type for arbitrary-precision unsigned integers (Uint)
19#[repr(transparent)]
20#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
21pub struct Uint(pub StdBigInt);
22
23impl Uint {
24	/// Create a new Uint from a u64
25	pub fn from_u64(value: u64) -> Self {
26		Uint(StdBigInt::from(value))
27	}
28
29	/// Create a new Uint from a u128
30	pub fn from_u128(value: u128) -> Self {
31		Uint(StdBigInt::from(value))
32	}
33
34	/// Create a Uint representing zero
35	pub fn zero() -> Self {
36		Uint(StdBigInt::from(0))
37	}
38
39	/// Create a Uint representing one
40	pub fn one() -> Self {
41		Uint(StdBigInt::from(1))
42	}
43
44	/// Ensure the value is non-negative, converting negative values to zero
45	fn ensure_non_negative(value: StdBigInt) -> StdBigInt {
46		if value.is_negative() {
47			StdBigInt::from(0)
48		} else {
49			value
50		}
51	}
52}
53
54impl Default for Uint {
55	fn default() -> Self {
56		Self::zero()
57	}
58}
59
60impl Deref for Uint {
61	type Target = StdBigInt;
62
63	fn deref(&self) -> &Self::Target {
64		&self.0
65	}
66}
67
68impl Hash for Uint {
69	fn hash<H: Hasher>(&self, state: &mut H) {
70		self.0.hash(state);
71	}
72}
73
74impl PartialOrd for Uint {
75	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
76		Some(self.cmp(other))
77	}
78}
79
80impl Ord for Uint {
81	fn cmp(&self, other: &Self) -> Ordering {
82		self.0.cmp(&other.0)
83	}
84}
85
86impl From<u8> for Uint {
87	fn from(value: u8) -> Self {
88		Uint(StdBigInt::from(value))
89	}
90}
91
92impl From<u16> for Uint {
93	fn from(value: u16) -> Self {
94		Uint(StdBigInt::from(value))
95	}
96}
97
98impl From<u32> for Uint {
99	fn from(value: u32) -> Self {
100		Uint(StdBigInt::from(value))
101	}
102}
103
104impl From<u64> for Uint {
105	fn from(value: u64) -> Self {
106		Uint(StdBigInt::from(value))
107	}
108}
109
110impl From<u128> for Uint {
111	fn from(value: u128) -> Self {
112		Uint(StdBigInt::from(value))
113	}
114}
115
116// Handle signed integer conversions by ensuring non-negative values
117impl From<i8> for Uint {
118	fn from(value: i8) -> Self {
119		Uint(Self::ensure_non_negative(StdBigInt::from(value)))
120	}
121}
122
123impl From<i16> for Uint {
124	fn from(value: i16) -> Self {
125		Uint(Self::ensure_non_negative(StdBigInt::from(value)))
126	}
127}
128
129impl From<i32> for Uint {
130	fn from(value: i32) -> Self {
131		Uint(Self::ensure_non_negative(StdBigInt::from(value)))
132	}
133}
134
135impl From<i64> for Uint {
136	fn from(value: i64) -> Self {
137		Uint(Self::ensure_non_negative(StdBigInt::from(value)))
138	}
139}
140
141impl From<i128> for Uint {
142	fn from(value: i128) -> Self {
143		Uint(Self::ensure_non_negative(StdBigInt::from(value)))
144	}
145}
146
147impl From<StdBigInt> for Uint {
148	fn from(value: StdBigInt) -> Self {
149		Uint(Self::ensure_non_negative(value))
150	}
151}
152
153impl From<Uint> for StdBigInt {
154	fn from(uint: Uint) -> Self {
155		uint.0
156	}
157}
158
159impl Display for Uint {
160	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
161		write!(f, "{}", self.0)
162	}
163}
164
165#[cfg(test)]
166mod tests {
167	use super::*;
168
169	#[test]
170	fn test_uint_create() {
171		let uint = Uint::from_u64(42);
172		assert_eq!(format!("{}", uint), "42");
173	}
174
175	#[test]
176	fn test_uint_equality() {
177		let a = Uint::from_u64(100);
178		let b = Uint::from_u64(100);
179		let c = Uint::from_u64(200);
180
181		assert_eq!(a, b);
182		assert_ne!(a, c);
183	}
184
185	#[test]
186	fn test_uint_ordering() {
187		let a = Uint::from_u64(10);
188		let b = Uint::from_u64(20);
189		let c = Uint::from_u64(20);
190
191		assert!(a < b);
192		assert!(b > a);
193		assert_eq!(b.cmp(&c), Ordering::Equal);
194	}
195
196	#[test]
197	fn test_uint_large_values() {
198		let large = Uint::from_u128(u128::MAX);
199		let larger = Uint::from(StdBigInt::from(u128::MAX) + 1);
200
201		assert!(large < larger);
202	}
203
204	#[test]
205	fn test_uint_display() {
206		let uint = Uint::from_u64(12345);
207		assert_eq!(format!("{}", uint), "12345");
208	}
209
210	#[test]
211	fn test_uint_hash() {
212		use std::collections::HashSet;
213
214		let a = Uint::from_u64(42);
215		let b = Uint::from_u64(42);
216
217		let mut set = HashSet::new();
218		set.insert(a);
219		assert!(set.contains(&b));
220	}
221
222	#[test]
223	fn test_uint_negative_input() {
224		// Test that negative inputs are converted to zero
225		let negative_i32 = Uint::from(-42i32);
226		let negative_i64 = Uint::from(-999i64);
227		let negative_i128 = Uint::from(-12345i128);
228		let negative_bigint = Uint::from(StdBigInt::from(-777));
229
230		assert_eq!(negative_i32, Uint::zero());
231		assert_eq!(negative_i64, Uint::zero());
232		assert_eq!(negative_i128, Uint::zero());
233		assert_eq!(negative_bigint, Uint::zero());
234
235		// Test that positive inputs remain unchanged
236		let positive_i32 = Uint::from(42i32);
237		let positive_i64 = Uint::from(999i64);
238		assert_eq!(format!("{}", positive_i32), "42");
239		assert_eq!(format!("{}", positive_i64), "999");
240	}
241}