Skip to main content

reifydb_type/value/uint/
mod.rs

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