1#![doc = include_str!("../README.md")]
2#![doc(issue_tracker_base_url = "https://github.com/alloy-rs/ruint/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, Hash)]
153#[cfg_attr(
154 not(any(target_arch = "riscv32", target_arch = "riscv64")),
155 derive(PartialEq)
156)]
157#[repr(transparent)]
158pub struct Uint<const BITS: usize, const LIMBS: usize> {
159 limbs: [u64; LIMBS],
160}
161
162impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
163 pub const LIMBS: usize = {
165 let limbs = nlimbs(BITS);
166 assert!(
167 LIMBS == limbs,
168 "Can not construct Uint<BITS, LIMBS> with incorrect LIMBS"
169 );
170 limbs
171 };
172
173 pub const MASK: u64 = mask(BITS);
175
176 const SHOULD_MASK: bool = BITS > 0 && Self::MASK != u64::MAX;
177
178 pub const BITS: usize = BITS;
180
181 pub const ZERO: Self = Self::from_limbs([0; LIMBS]);
184
185 pub const ONE: Self = Self::const_from_u64(1);
189
190 pub const MIN: Self = Self::ZERO;
193
194 pub const MAX: Self = Self::from_limbs_unmasked([u64::MAX; LIMBS]);
197
198 #[inline(always)]
200 #[must_use]
201 pub const fn as_limbs(&self) -> &[u64; LIMBS] {
202 &self.limbs
203 }
204
205 #[inline(always)]
212 #[must_use]
213 pub const unsafe fn as_limbs_mut(&mut self) -> &mut [u64; LIMBS] {
214 &mut self.limbs
215 }
216
217 #[inline(always)]
221 #[must_use]
222 pub const fn into_limbs(self) -> [u64; LIMBS] {
223 self.limbs
224 }
225
226 #[inline]
227 pub(crate) const fn as_double_words(&self) -> &[pu128] {
228 assert!(LIMBS >= 2);
229 let (ptr, len) = (self.limbs.as_ptr(), self.limbs.len());
230 unsafe { core::slice::from_raw_parts(ptr.cast(), len / 2) }
231 }
232
233 #[inline(always)]
241 #[must_use]
242 #[track_caller]
243 pub const fn from_limbs(limbs: [u64; LIMBS]) -> Self {
244 if Self::SHOULD_MASK {
245 assert!(
247 limbs[LIMBS - 1] <= Self::MASK,
248 "Value too large for this Uint"
249 );
250 }
251 let _ = Self::LIMBS; Self { limbs }
253 }
254
255 #[inline(always)]
256 #[must_use]
257 const fn from_limbs_unmasked(limbs: [u64; LIMBS]) -> Self {
258 let _ = Self::LIMBS; Self { limbs }.masked()
260 }
261
262 #[inline]
268 #[must_use]
269 #[track_caller]
270 pub const fn from_limbs_slice(slice: &[u64]) -> Self {
271 match Self::overflowing_from_limbs_slice(slice) {
272 (n, false) => n,
273 (_, true) => panic!("Value too large for this Uint"),
274 }
275 }
276
277 #[inline]
280 #[must_use]
281 pub const fn checked_from_limbs_slice(slice: &[u64]) -> Option<Self> {
282 match Self::overflowing_from_limbs_slice(slice) {
283 (n, false) => Some(n),
284 (_, true) => None,
285 }
286 }
287
288 #[inline]
291 #[must_use]
292 pub const fn wrapping_from_limbs_slice(slice: &[u64]) -> Self {
293 Self::overflowing_from_limbs_slice(slice).0
294 }
295
296 #[inline]
300 #[must_use]
301 pub const fn overflowing_from_limbs_slice(slice: &[u64]) -> (Self, bool) {
302 if slice.len() < LIMBS {
303 let mut limbs = [0; LIMBS];
304 unsafe {
307 core::ptr::copy_nonoverlapping(slice.as_ptr(), limbs.as_mut_ptr(), slice.len());
308 }
309 (Self::from_limbs(limbs), false)
310 } else {
311 let (head, tail) = slice.split_at(LIMBS);
312 let mut limbs = [0; LIMBS];
313 unsafe {
315 core::ptr::copy_nonoverlapping(head.as_ptr(), limbs.as_mut_ptr(), LIMBS);
316 }
317 let mut overflow = false;
318 const_range_for!(&limb in ref tail => {
319 if limb != 0 {
320 overflow = true;
321 break;
322 }
323 });
324 if LIMBS > 0 {
325 overflow |= limbs[LIMBS - 1] > Self::MASK;
326 limbs[LIMBS - 1] &= Self::MASK;
327 }
328 (Self::from_limbs(limbs), overflow)
329 }
330 }
331
332 #[inline]
335 #[must_use]
336 pub const fn saturating_from_limbs_slice(slice: &[u64]) -> Self {
337 match Self::overflowing_from_limbs_slice(slice) {
338 (n, false) => n,
339 (_, true) => Self::MAX,
340 }
341 }
342
343 #[inline(always)]
344 const fn apply_mask(&mut self) {
345 if Self::SHOULD_MASK {
346 self.limbs[LIMBS - 1] &= Self::MASK;
347 }
348 }
349
350 #[inline(always)]
351 const fn maskable_bits(&self) -> u64 {
352 if Self::SHOULD_MASK {
353 self.limbs[LIMBS - 1] & !Self::MASK
354 } else {
355 0
356 }
357 }
358
359 #[inline(always)]
360 const fn masked(mut self) -> Self {
361 self.apply_mask();
362 self
363 }
364}
365
366impl<const BITS: usize, const LIMBS: usize> Default for Uint<BITS, LIMBS> {
367 #[inline]
368 fn default() -> Self {
369 Self::ZERO
370 }
371}
372
373#[inline]
376#[must_use]
377pub const fn nlimbs(bits: usize) -> usize {
378 bits.div_ceil(64)
379}
380
381#[inline]
383#[must_use]
384pub const fn mask(bits: usize) -> u64 {
385 if bits == 0 {
386 return 0;
387 }
388 let bits = bits % 64;
389 if bits == 0 { u64::MAX } else { (1 << bits) - 1 }
390}
391
392#[doc(hidden)]
394pub mod __private {
395 pub use ruint_macro;
396}
397
398#[cfg(test)]
399mod test {
400 use super::*;
401
402 #[test]
403 fn test_mask() {
404 assert_eq!(mask(0), 0);
405 assert_eq!(mask(1), 1);
406 assert_eq!(mask(5), 0x1f);
407 assert_eq!(mask(63), u64::MAX >> 1);
408 assert_eq!(mask(64), u64::MAX);
409 }
410
411 #[test]
412 fn test_max() {
413 assert_eq!(Uint::<0, 0>::MAX, Uint::ZERO);
414 assert_eq!(Uint::<1, 1>::MAX, Uint::from_limbs([1]));
415 assert_eq!(Uint::<7, 1>::MAX, Uint::from_limbs([127]));
416 assert_eq!(Uint::<64, 1>::MAX, Uint::from_limbs([u64::MAX]));
417 assert_eq!(
418 Uint::<100, 2>::MAX,
419 Uint::from_limbs([u64::MAX, u64::MAX >> 28])
420 );
421 }
422
423 #[test]
424 fn test_constants() {
425 const_for!(BITS in SIZES {
426 const LIMBS: usize = nlimbs(BITS);
427 assert_eq!(Uint::<BITS, LIMBS>::MIN, Uint::<BITS, LIMBS>::ZERO);
428 let _ = Uint::<BITS, LIMBS>::MAX;
429 });
430 }
431
432 #[test]
433 fn test_const_from_limbs_slice() {
434 const_for!(BITS in SIZES {
435 const LIMBS: usize = nlimbs(BITS);
436 type U = Uint<BITS, LIMBS>;
437 const {
438 let empty = [];
439 assert!(U::from_limbs_slice(&empty).const_is_zero());
440 assert!(matches!(U::checked_from_limbs_slice(&empty), Some(value) if value.const_is_zero()));
441 assert!(U::wrapping_from_limbs_slice(&empty).const_is_zero());
442
443 let source = [u64::MAX, u64::MAX];
444 let (truncated, overflow) = U::overflowing_from_limbs_slice(&source);
445 assert!(U::wrapping_from_limbs_slice(&source).const_eq(&truncated));
446 let saturated = U::saturating_from_limbs_slice(&source);
447 if overflow {
448 assert!(saturated.const_eq(&U::MAX));
449 } else {
450 assert!(saturated.const_eq(&truncated));
451 }
452 }
453 });
454 }
455}