1#![doc = include_str!("../README.md")]
2#![doc(issue_tracker_base_url = "https://github.com/recmo/uint/issues/")]
3#![cfg_attr(test, allow(clippy::wildcard_imports, clippy::cognitive_complexity))]
4#![cfg_attr(not(test), warn(unused_crate_dependencies))]
5#![cfg_attr(not(feature = "std"), no_std)]
6#![cfg_attr(docsrs, feature(doc_cfg))]
8#![cfg_attr(
9 feature = "nightly",
10 feature(core_intrinsics, const_unsigned_bigint_helpers)
11)]
12#![cfg_attr(
13 feature = "nightly",
14 allow(internal_features, clippy::incompatible_msrv)
15)]
16#![cfg_attr(
17 feature = "generic_const_exprs",
18 feature(generic_const_exprs),
19 allow(incomplete_features)
20)]
21
22#[cfg(feature = "alloc")]
23#[allow(unused_imports)]
24#[macro_use]
27extern crate alloc;
28
29#[macro_use]
30mod macros;
31
32mod add;
33pub mod algorithms;
34pub mod aliases;
35mod base_convert;
36mod bit_arr;
37mod bits;
38mod bytes;
39mod cmp;
40mod const_for;
41mod div;
42mod fmt;
43mod from;
44mod gcd;
45mod log;
46mod modular;
47mod mul;
48mod pow;
49mod root;
50mod special;
51mod string;
52mod utils;
53
54pub mod support;
55
56#[doc(inline)]
57pub use bit_arr::Bits;
58
59#[doc(inline)]
60pub use self::{
61 base_convert::BaseConvertError,
62 bytes::nbytes,
63 from::{FromUintError, ToFieldError, ToUintError, UintTryFrom, UintTryTo},
64 string::ParseError,
65};
66
67#[cfg(doc)]
70#[doc(inline)]
71pub use ruint_macro::uint;
72
73#[cfg(feature = "generic_const_exprs")]
75pub mod nightly {
76 pub type Uint<const BITS: usize> = crate::Uint<BITS, { crate::nlimbs(BITS) }>;
94
95 pub type Bits<const BITS: usize> = crate::Bits<BITS, { crate::nlimbs(BITS) }>;
99}
100
101#[derive(Clone, Copy)]
103#[allow(non_camel_case_types)]
104pub(crate) struct pu128 {
105 inner: [u64; 2],
106}
107impl pu128 {
108 #[inline]
109 pub(crate) const fn get(self) -> u128 {
110 let arr = self.inner;
111 #[cfg(target_endian = "little")]
112 {
113 unsafe { core::mem::transmute(arr) }
114 }
115 #[cfg(target_endian = "big")]
116 {
117 arr[0] as u128 | (arr[1] as u128) << 64
118 }
119 }
120}
121
122#[derive(Clone, Copy, Eq, PartialEq, Hash)]
149#[repr(transparent)]
150pub struct Uint<const BITS: usize, const LIMBS: usize> {
151 limbs: [u64; LIMBS],
152}
153
154impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
155 pub const LIMBS: usize = {
157 let limbs = nlimbs(BITS);
158 assert!(
159 LIMBS == limbs,
160 "Can not construct Uint<BITS, LIMBS> with incorrect LIMBS"
161 );
162 limbs
163 };
164
165 pub const MASK: u64 = mask(BITS);
167
168 const SHOULD_MASK: bool = BITS > 0 && Self::MASK != u64::MAX;
169
170 pub const BITS: usize = BITS;
172
173 pub const ZERO: Self = Self::from_limbs([0; LIMBS]);
176
177 pub const ONE: Self = Self::const_from_u64(1);
181
182 pub const MIN: Self = Self::ZERO;
185
186 pub const MAX: Self = Self::from_limbs_unmasked([u64::MAX; LIMBS]);
189
190 #[inline(always)]
192 #[must_use]
193 pub const fn as_limbs(&self) -> &[u64; LIMBS] {
194 &self.limbs
195 }
196
197 #[inline(always)]
204 #[must_use]
205 pub const unsafe fn as_limbs_mut(&mut self) -> &mut [u64; LIMBS] {
206 &mut self.limbs
207 }
208
209 #[inline(always)]
213 #[must_use]
214 pub const fn into_limbs(self) -> [u64; LIMBS] {
215 self.limbs
216 }
217
218 #[inline]
219 pub(crate) const fn as_double_words(&self) -> &[pu128] {
220 assert!(LIMBS >= 2);
221 let (ptr, len) = (self.limbs.as_ptr(), self.limbs.len());
222 unsafe { core::slice::from_raw_parts(ptr.cast(), len / 2) }
223 }
224
225 #[inline(always)]
233 #[must_use]
234 #[track_caller]
235 pub const fn from_limbs(limbs: [u64; LIMBS]) -> Self {
236 if Self::SHOULD_MASK {
237 assert!(
239 limbs[LIMBS - 1] <= Self::MASK,
240 "Value too large for this Uint"
241 );
242 }
243 let _ = Self::LIMBS; Self { limbs }
245 }
246
247 #[inline(always)]
248 #[must_use]
249 const fn from_limbs_unmasked(limbs: [u64; LIMBS]) -> Self {
250 let _ = Self::LIMBS; Self { limbs }.masked()
252 }
253
254 #[inline]
260 #[must_use]
261 #[track_caller]
262 pub fn from_limbs_slice(slice: &[u64]) -> Self {
263 match Self::overflowing_from_limbs_slice(slice) {
264 (n, false) => n,
265 (_, true) => panic!("Value too large for this Uint"),
266 }
267 }
268
269 #[inline]
272 #[must_use]
273 pub fn checked_from_limbs_slice(slice: &[u64]) -> Option<Self> {
274 match Self::overflowing_from_limbs_slice(slice) {
275 (n, false) => Some(n),
276 (_, true) => None,
277 }
278 }
279
280 #[inline]
283 #[must_use]
284 pub fn wrapping_from_limbs_slice(slice: &[u64]) -> Self {
285 Self::overflowing_from_limbs_slice(slice).0
286 }
287
288 #[inline]
292 #[must_use]
293 pub fn overflowing_from_limbs_slice(slice: &[u64]) -> (Self, bool) {
294 if slice.len() < LIMBS {
295 let mut limbs = [0; LIMBS];
296 limbs[..slice.len()].copy_from_slice(slice);
297 (Self::from_limbs(limbs), false)
298 } else {
299 let (head, tail) = slice.split_at(LIMBS);
300 let mut limbs = [0; LIMBS];
301 limbs.copy_from_slice(head);
302 let mut overflow = tail.iter().any(|&limb| limb != 0);
303 if LIMBS > 0 {
304 overflow |= limbs[LIMBS - 1] > Self::MASK;
305 limbs[LIMBS - 1] &= Self::MASK;
306 }
307 (Self::from_limbs(limbs), overflow)
308 }
309 }
310
311 #[inline]
314 #[must_use]
315 pub fn saturating_from_limbs_slice(slice: &[u64]) -> Self {
316 match Self::overflowing_from_limbs_slice(slice) {
317 (n, false) => n,
318 (_, true) => Self::MAX,
319 }
320 }
321
322 #[inline(always)]
323 const fn apply_mask(&mut self) {
324 if Self::SHOULD_MASK {
325 self.limbs[LIMBS - 1] &= Self::MASK;
326 }
327 }
328
329 #[inline(always)]
330 const fn masked(mut self) -> Self {
331 self.apply_mask();
332 self
333 }
334}
335
336impl<const BITS: usize, const LIMBS: usize> Default for Uint<BITS, LIMBS> {
337 #[inline]
338 fn default() -> Self {
339 Self::ZERO
340 }
341}
342
343#[inline]
346#[must_use]
347pub const fn nlimbs(bits: usize) -> usize {
348 bits.div_ceil(64)
349}
350
351#[inline]
353#[must_use]
354pub const fn mask(bits: usize) -> u64 {
355 if bits == 0 {
356 return 0;
357 }
358 let bits = bits % 64;
359 if bits == 0 { u64::MAX } else { (1 << bits) - 1 }
360}
361
362#[doc(hidden)]
364pub mod __private {
365 pub use ruint_macro;
366}
367
368#[cfg(test)]
369mod test {
370 use super::*;
371
372 #[test]
373 fn test_mask() {
374 assert_eq!(mask(0), 0);
375 assert_eq!(mask(1), 1);
376 assert_eq!(mask(5), 0x1f);
377 assert_eq!(mask(63), u64::MAX >> 1);
378 assert_eq!(mask(64), u64::MAX);
379 }
380
381 #[test]
382 fn test_max() {
383 assert_eq!(Uint::<0, 0>::MAX, Uint::ZERO);
384 assert_eq!(Uint::<1, 1>::MAX, Uint::from_limbs([1]));
385 assert_eq!(Uint::<7, 1>::MAX, Uint::from_limbs([127]));
386 assert_eq!(Uint::<64, 1>::MAX, Uint::from_limbs([u64::MAX]));
387 assert_eq!(
388 Uint::<100, 2>::MAX,
389 Uint::from_limbs([u64::MAX, u64::MAX >> 28])
390 );
391 }
392
393 #[test]
394 fn test_constants() {
395 const_for!(BITS in SIZES {
396 const LIMBS: usize = nlimbs(BITS);
397 assert_eq!(Uint::<BITS, LIMBS>::MIN, Uint::<BITS, LIMBS>::ZERO);
398 let _ = Uint::<BITS, LIMBS>::MAX;
399 });
400 }
401}