Skip to main content

reifydb_type/value/uint/
mod.rs

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