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(feature = "nightly", feature(core_intrinsics, bigint_helper_methods))]
9#![cfg_attr(
10 feature = "nightly",
11 allow(internal_features, clippy::incompatible_msrv)
12)]
13#![cfg_attr(
14 feature = "generic_const_exprs",
15 feature(generic_const_exprs),
16 allow(incomplete_features)
17)]
18
19#[cfg(feature = "alloc")]
20#[allow(unused_imports)]
21#[macro_use]
24extern crate alloc;
25
26#[macro_use]
27mod macros;
28
29mod add;
30pub mod algorithms;
31pub mod aliases;
32mod base_convert;
33mod bit_arr;
34mod bits;
35mod bytes;
36mod cmp;
37mod const_for;
38mod div;
39mod fmt;
40mod from;
41mod gcd;
42mod log;
43mod modular;
44mod mul;
45mod pow;
46mod root;
47mod special;
48mod string;
49mod utils;
50
51pub mod support;
52
53#[doc(inline)]
54pub use bit_arr::Bits;
55
56#[doc(inline)]
57pub use self::{
58 base_convert::BaseConvertError,
59 bytes::nbytes,
60 from::{FromUintError, ToFieldError, ToUintError, UintTryFrom, UintTryTo},
61 string::ParseError,
62};
63
64#[cfg(doc)]
67#[doc(inline)]
68pub use ruint_macro::uint;
69
70#[cfg(feature = "generic_const_exprs")]
72pub mod nightly {
73 pub type Uint<const BITS: usize> = crate::Uint<BITS, { crate::nlimbs(BITS) }>;
91
92 pub type Bits<const BITS: usize> = crate::Bits<BITS, { crate::nlimbs(BITS) }>;
96}
97
98#[derive(Clone, Copy)]
100#[allow(non_camel_case_types)]
101pub(crate) struct pu128 {
102 inner: [u64; 2],
103}
104impl pu128 {
105 #[inline]
106 pub(crate) const fn get(self) -> u128 {
107 let arr = self.inner;
108 #[cfg(target_endian = "little")]
109 {
110 unsafe { core::mem::transmute(arr) }
111 }
112 #[cfg(target_endian = "big")]
113 {
114 arr[0] as u128 | (arr[1] as u128) << 64
115 }
116 }
117}
118
119#[derive(Clone, Copy, Eq, PartialEq, Hash)]
146#[repr(transparent)]
147pub struct Uint<const BITS: usize, const LIMBS: usize> {
148 limbs: [u64; LIMBS],
149}
150
151impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
152 pub const LIMBS: usize = {
154 let limbs = nlimbs(BITS);
155 assert!(
156 LIMBS == limbs,
157 "Can not construct Uint<BITS, LIMBS> with incorrect LIMBS"
158 );
159 limbs
160 };
161
162 pub const MASK: u64 = mask(BITS);
164
165 const SHOULD_MASK: bool = BITS > 0 && Self::MASK != u64::MAX;
166
167 pub const BITS: usize = BITS;
169
170 pub const ZERO: Self = Self::from_limbs([0; LIMBS]);
173
174 pub const ONE: Self = Self::const_from_u64(1);
178
179 pub const MIN: Self = Self::ZERO;
182
183 pub const MAX: Self = Self::from_limbs_unmasked([u64::MAX; LIMBS]);
186
187 #[inline(always)]
189 #[must_use]
190 pub const fn as_limbs(&self) -> &[u64; LIMBS] {
191 &self.limbs
192 }
193
194 #[inline(always)]
201 #[must_use]
202 pub const unsafe fn as_limbs_mut(&mut self) -> &mut [u64; LIMBS] {
203 &mut self.limbs
204 }
205
206 #[inline(always)]
210 #[must_use]
211 pub const fn into_limbs(self) -> [u64; LIMBS] {
212 self.limbs
213 }
214
215 #[inline]
216 pub(crate) const fn as_double_words(&self) -> &[pu128] {
217 assert!(LIMBS >= 2);
218 let (ptr, len) = (self.limbs.as_ptr(), self.limbs.len());
219 unsafe { core::slice::from_raw_parts(ptr.cast(), len / 2) }
220 }
221
222 #[inline(always)]
230 #[must_use]
231 #[track_caller]
232 pub const fn from_limbs(limbs: [u64; LIMBS]) -> Self {
233 if Self::SHOULD_MASK {
234 assert!(
236 limbs[LIMBS - 1] <= Self::MASK,
237 "Value too large for this Uint"
238 );
239 }
240 let _ = Self::LIMBS; Self { limbs }
242 }
243
244 #[inline(always)]
245 #[must_use]
246 const fn from_limbs_unmasked(limbs: [u64; LIMBS]) -> Self {
247 let _ = Self::LIMBS; Self { limbs }.masked()
249 }
250
251 #[inline]
257 #[must_use]
258 #[track_caller]
259 pub fn from_limbs_slice(slice: &[u64]) -> Self {
260 match Self::overflowing_from_limbs_slice(slice) {
261 (n, false) => n,
262 (_, true) => panic!("Value too large for this Uint"),
263 }
264 }
265
266 #[inline]
269 #[must_use]
270 pub fn checked_from_limbs_slice(slice: &[u64]) -> Option<Self> {
271 match Self::overflowing_from_limbs_slice(slice) {
272 (n, false) => Some(n),
273 (_, true) => None,
274 }
275 }
276
277 #[inline]
280 #[must_use]
281 pub fn wrapping_from_limbs_slice(slice: &[u64]) -> Self {
282 Self::overflowing_from_limbs_slice(slice).0
283 }
284
285 #[inline]
289 #[must_use]
290 pub fn overflowing_from_limbs_slice(slice: &[u64]) -> (Self, bool) {
291 if slice.len() < LIMBS {
292 let mut limbs = [0; LIMBS];
293 limbs[..slice.len()].copy_from_slice(slice);
294 (Self::from_limbs(limbs), false)
295 } else {
296 let (head, tail) = slice.split_at(LIMBS);
297 let mut limbs = [0; LIMBS];
298 limbs.copy_from_slice(head);
299 let mut overflow = tail.iter().any(|&limb| limb != 0);
300 if LIMBS > 0 {
301 overflow |= limbs[LIMBS - 1] > Self::MASK;
302 limbs[LIMBS - 1] &= Self::MASK;
303 }
304 (Self::from_limbs(limbs), overflow)
305 }
306 }
307
308 #[inline]
311 #[must_use]
312 pub fn saturating_from_limbs_slice(slice: &[u64]) -> Self {
313 match Self::overflowing_from_limbs_slice(slice) {
314 (n, false) => n,
315 (_, true) => Self::MAX,
316 }
317 }
318
319 #[inline(always)]
320 const fn apply_mask(&mut self) {
321 if Self::SHOULD_MASK {
322 self.limbs[LIMBS - 1] &= Self::MASK;
323 }
324 }
325
326 #[inline(always)]
327 const fn masked(mut self) -> Self {
328 self.apply_mask();
329 self
330 }
331}
332
333impl<const BITS: usize, const LIMBS: usize> Default for Uint<BITS, LIMBS> {
334 #[inline]
335 fn default() -> Self {
336 Self::ZERO
337 }
338}
339
340#[inline]
343#[must_use]
344pub const fn nlimbs(bits: usize) -> usize {
345 bits.div_ceil(64)
346}
347
348#[inline]
350#[must_use]
351pub const fn mask(bits: usize) -> u64 {
352 if bits == 0 {
353 return 0;
354 }
355 let bits = bits % 64;
356 if bits == 0 { u64::MAX } else { (1 << bits) - 1 }
357}
358
359#[doc(hidden)]
361pub mod __private {
362 pub use ruint_macro;
363}
364
365#[cfg(test)]
366mod test {
367 use super::*;
368
369 #[test]
370 fn test_mask() {
371 assert_eq!(mask(0), 0);
372 assert_eq!(mask(1), 1);
373 assert_eq!(mask(5), 0x1f);
374 assert_eq!(mask(63), u64::MAX >> 1);
375 assert_eq!(mask(64), u64::MAX);
376 }
377
378 #[test]
379 fn test_max() {
380 assert_eq!(Uint::<0, 0>::MAX, Uint::ZERO);
381 assert_eq!(Uint::<1, 1>::MAX, Uint::from_limbs([1]));
382 assert_eq!(Uint::<7, 1>::MAX, Uint::from_limbs([127]));
383 assert_eq!(Uint::<64, 1>::MAX, Uint::from_limbs([u64::MAX]));
384 assert_eq!(
385 Uint::<100, 2>::MAX,
386 Uint::from_limbs([u64::MAX, u64::MAX >> 28])
387 );
388 }
389
390 #[test]
391 fn test_constants() {
392 const_for!(BITS in SIZES {
393 const LIMBS: usize = nlimbs(BITS);
394 assert_eq!(Uint::<BITS, LIMBS>::MIN, Uint::<BITS, LIMBS>::ZERO);
395 let _ = Uint::<BITS, LIMBS>::MAX;
396 });
397 }
398}