ruint/lib.rs
1#![doc = include_str!("../README.md")]
2#![doc(issue_tracker_base_url = "https://github.com/recmo/uint/issues/")]
3#![warn(
4 clippy::all,
5 clippy::pedantic,
6 clippy::nursery,
7 clippy::missing_inline_in_public_items,
8 clippy::std_instead_of_alloc,
9 clippy::std_instead_of_core,
10 missing_docs,
11 unreachable_pub
12)]
13#![allow(
14 clippy::doc_markdown, // Unfortunately many false positives on Latex.
15 clippy::inline_always,
16 clippy::module_name_repetitions,
17 clippy::redundant_pub_crate,
18 clippy::unreadable_literal,
19 clippy::let_unit_value,
20 clippy::option_if_let_else,
21 clippy::cast_sign_loss,
22 clippy::cast_lossless,
23)]
24#![cfg_attr(test, allow(clippy::wildcard_imports, clippy::cognitive_complexity))]
25#![cfg_attr(not(test), warn(unused_crate_dependencies))]
26#![cfg_attr(not(feature = "std"), no_std)]
27// Unstable features
28#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
29#![cfg_attr(feature = "nightly", feature(core_intrinsics))]
30#![cfg_attr(feature = "nightly", allow(internal_features))]
31#![cfg_attr(
32 feature = "generic_const_exprs",
33 feature(generic_const_exprs),
34 allow(incomplete_features)
35)]
36
37#[cfg(feature = "alloc")]
38#[allow(unused_imports)]
39// `unused_imports` triggers on macro_use, which is required by some support
40// modules.
41#[macro_use]
42extern crate alloc;
43
44#[macro_use]
45mod macros;
46
47mod add;
48pub mod algorithms;
49pub mod aliases;
50mod base_convert;
51mod bit_arr;
52mod bits;
53mod bytes;
54mod cmp;
55mod const_for;
56mod div;
57mod fmt;
58mod from;
59mod gcd;
60mod log;
61mod modular;
62mod mul;
63mod pow;
64mod root;
65mod special;
66mod string;
67mod utils;
68
69pub mod support;
70
71#[doc(inline)]
72pub use bit_arr::Bits;
73
74#[doc(inline)]
75pub use self::{
76 base_convert::BaseConvertError,
77 bytes::nbytes,
78 from::{FromUintError, ToFieldError, ToUintError, UintTryFrom, UintTryTo},
79 string::ParseError,
80};
81
82// For documentation purposes we expose the macro directly, otherwise it is
83// wrapped in ./macros.rs.
84#[cfg(doc)]
85#[doc(inline)]
86pub use ruint_macro::uint;
87
88/// Extra features that are nightly only.
89#[cfg(feature = "generic_const_exprs")]
90pub mod nightly {
91 /// Alias for `Uint` specified only by bit size.
92 ///
93 /// Compared to [`crate::Uint`] it compile-time computes the required number
94 /// of limbs. Unfortunately this requires the nightly feature
95 /// `generic_const_exprs`.
96 ///
97 /// # References
98 /// * [Working group](https://rust-lang.github.io/project-const-generics/)
99 /// const generics working group.
100 /// * [RFC2000](https://rust-lang.github.io/rfcs/2000-const-generics.html)
101 /// const generics.
102 /// * [#60551](https://github.com/rust-lang/rust/issues/60551) associated
103 /// constants in const generics.
104 /// * [#76560](https://github.com/rust-lang/rust/issues/76560) tracking
105 /// issue for `generic_const_exprs`.
106 /// * [Rust blog](https://blog.rust-lang.org/inside-rust/2021/09/06/Splitting-const-generics.html)
107 /// 2021-09-06 Splitting const generics.
108 pub type Uint<const BITS: usize> = crate::Uint<BITS, { crate::nlimbs(BITS) }>;
109
110 /// Alias for `Bits` specified only by bit size.
111 ///
112 /// See [`Uint`] for more information.
113 pub type Bits<const BITS: usize> = crate::Bits<BITS, { crate::nlimbs(BITS) }>;
114}
115
116// FEATURE: (BLOCKED) Many functions could be made `const` if a number of
117// features land. This requires
118// #![feature(const_mut_refs)]
119// #![feature(const_float_classify)]
120// #![feature(const_fn_floating_point_arithmetic)]
121// #![feature(const_float_bits_conv)]
122// and more.
123
124/// The ring of numbers modulo $2^{\mathtt{BITS}}$.
125///
126/// [`Uint`] implements nearly all traits and methods from the `std` unsigned
127/// integer types, including most nightly only ones.
128///
129/// # Notable differences from `std` uint types.
130///
131/// * The operators `+`, `-`, `*`, etc. using wrapping math by default. The std
132/// operators panic on overflow in debug, and are undefined in release, see
133/// [reference][std-overflow].
134/// * The [`Uint::checked_shl`], [`Uint::overflowing_shl`], etc return overflow
135/// when non-zero bits are shifted out. In std they return overflow when the
136/// shift amount is greater than the bit size.
137/// * Some methods like [`u64::div_euclid`] and [`u64::rem_euclid`] are left out
138/// because they are meaningless or redundant for unsigned integers. Std has
139/// them for compatibility with their signed integers.
140/// * Many functions that are `const` in std are not in [`Uint`].
141/// * [`Uint::to_le_bytes`] and [`Uint::to_be_bytes`] require the output size to
142/// be provided as a const-generic argument. They will runtime panic if the
143/// provided size is incorrect.
144/// * [`Uint::widening_mul`] takes as argument an [`Uint`] of arbitrary size and
145/// returns a result that is sized to fit the product without overflow (i.e.
146/// the sum of the bit sizes of self and the argument). The std version
147/// requires same-sized arguments and returns a pair of lower and higher bits.
148///
149/// [std-overflow]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow
150#[derive(Clone, Copy, Eq, PartialEq, Hash)]
151#[repr(transparent)]
152pub struct Uint<const BITS: usize, const LIMBS: usize> {
153 limbs: [u64; LIMBS],
154}
155
156impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
157 /// The size of this integer type in 64-bit limbs.
158 pub const LIMBS: usize = {
159 let limbs = nlimbs(BITS);
160 assert!(
161 LIMBS == limbs,
162 "Can not construct Uint<BITS, LIMBS> with incorrect LIMBS"
163 );
164 limbs
165 };
166
167 /// Bit mask for the last limb.
168 pub const MASK: u64 = mask(BITS);
169
170 /// The size of this integer type in bits.
171 pub const BITS: usize = BITS;
172
173 /// The value zero. This is the only value that exists in all [`Uint`]
174 /// types.
175 pub const ZERO: Self = Self::from_limbs([0; LIMBS]);
176
177 /// The smallest value that can be represented by this integer type.
178 /// Synonym for [`Self::ZERO`].
179 pub const MIN: Self = Self::ZERO;
180
181 /// The largest value that can be represented by this integer type,
182 /// $2^{\mathtt{BITS}} − 1$.
183 pub const MAX: Self = {
184 let mut limbs = [u64::MAX; LIMBS];
185 if BITS > 0 {
186 limbs[LIMBS - 1] &= Self::MASK;
187 }
188 Self::from_limbs(limbs)
189 };
190
191 /// View the array of limbs.
192 #[inline(always)]
193 #[must_use]
194 pub const fn as_limbs(&self) -> &[u64; LIMBS] {
195 &self.limbs
196 }
197
198 /// Access the array of limbs.
199 ///
200 /// # Safety
201 ///
202 /// This function is unsafe because it allows setting a bit outside the bit
203 /// size if the bit-size is not limb-aligned.
204 #[inline(always)]
205 #[must_use]
206 pub unsafe fn as_limbs_mut(&mut self) -> &mut [u64; LIMBS] {
207 &mut self.limbs
208 }
209
210 /// Convert to a array of limbs.
211 ///
212 /// Limbs are least significant first.
213 #[inline(always)]
214 #[must_use]
215 pub const fn into_limbs(self) -> [u64; LIMBS] {
216 self.limbs
217 }
218
219 /// Construct a new integer from little-endian a array of limbs.
220 ///
221 /// # Panics
222 ///
223 /// Panics it `LIMBS` is not equal to `nlimbs(BITS)`.
224 ///
225 /// Panics if the value is too large for the bit-size of the Uint.
226 #[inline(always)]
227 #[must_use]
228 #[track_caller]
229 pub const fn from_limbs(limbs: [u64; LIMBS]) -> Self {
230 if BITS > 0 && Self::MASK != u64::MAX {
231 // FEATURE: (BLOCKED) Add `<{BITS}>` to the type when Display works in const fn.
232 assert!(
233 limbs[Self::LIMBS - 1] <= Self::MASK,
234 "Value too large for this Uint"
235 );
236 }
237 Self { limbs }
238 }
239
240 /// Construct a new integer from little-endian a slice of limbs.
241 ///
242 /// # Panics
243 ///
244 /// Panics if the value is too large for the bit-size of the Uint.
245 #[inline]
246 #[must_use]
247 #[track_caller]
248 pub fn from_limbs_slice(slice: &[u64]) -> Self {
249 match Self::overflowing_from_limbs_slice(slice) {
250 (n, false) => n,
251 (_, true) => panic!("Value too large for this Uint"),
252 }
253 }
254
255 /// Construct a new integer from little-endian a slice of limbs, or `None`
256 /// if the value is too large for the [`Uint`].
257 #[inline]
258 #[must_use]
259 pub fn checked_from_limbs_slice(slice: &[u64]) -> Option<Self> {
260 match Self::overflowing_from_limbs_slice(slice) {
261 (n, false) => Some(n),
262 (_, true) => None,
263 }
264 }
265
266 /// Construct a new [`Uint`] from a little-endian slice of limbs. Returns
267 /// a potentially truncated value.
268 #[inline]
269 #[must_use]
270 pub fn wrapping_from_limbs_slice(slice: &[u64]) -> Self {
271 Self::overflowing_from_limbs_slice(slice).0
272 }
273
274 /// Construct a new [`Uint`] from a little-endian slice of limbs. Returns
275 /// a potentially truncated value and a boolean indicating whether the value
276 /// was truncated.
277 #[inline]
278 #[must_use]
279 pub fn overflowing_from_limbs_slice(slice: &[u64]) -> (Self, bool) {
280 if slice.len() < LIMBS {
281 let mut limbs = [0; LIMBS];
282 limbs[..slice.len()].copy_from_slice(slice);
283 (Self::from_limbs(limbs), false)
284 } else {
285 let (head, tail) = slice.split_at(LIMBS);
286 let mut limbs = [0; LIMBS];
287 limbs.copy_from_slice(head);
288 let mut overflow = tail.iter().any(|&limb| limb != 0);
289 if LIMBS > 0 {
290 overflow |= limbs[LIMBS - 1] > Self::MASK;
291 limbs[LIMBS - 1] &= Self::MASK;
292 }
293 (Self::from_limbs(limbs), overflow)
294 }
295 }
296
297 /// Construct a new [`Uint`] from a little-endian slice of limbs. Returns
298 /// the maximum value if the value is too large for the [`Uint`].
299 #[inline]
300 #[must_use]
301 pub fn saturating_from_limbs_slice(slice: &[u64]) -> Self {
302 match Self::overflowing_from_limbs_slice(slice) {
303 (n, false) => n,
304 (_, true) => Self::MAX,
305 }
306 }
307}
308
309impl<const BITS: usize, const LIMBS: usize> Default for Uint<BITS, LIMBS> {
310 #[inline]
311 fn default() -> Self {
312 Self::ZERO
313 }
314}
315
316/// Number of `u64` limbs required to represent the given number of bits.
317/// This needs to be public because it is used in the `Uint` type.
318#[inline]
319#[must_use]
320pub const fn nlimbs(bits: usize) -> usize {
321 (bits + 63) / 64
322}
323
324/// Mask to apply to the highest limb to get the correct number of bits.
325#[inline]
326#[must_use]
327pub const fn mask(bits: usize) -> u64 {
328 if bits == 0 {
329 return 0;
330 }
331 let bits = bits % 64;
332 if bits == 0 {
333 u64::MAX
334 } else {
335 (1 << bits) - 1
336 }
337}
338
339// Not public API.
340#[doc(hidden)]
341pub mod __private {
342 pub use ruint_macro;
343}
344
345#[cfg(test)]
346mod test {
347 use super::*;
348
349 #[test]
350 fn test_mask() {
351 assert_eq!(mask(0), 0);
352 assert_eq!(mask(1), 1);
353 assert_eq!(mask(5), 0x1f);
354 assert_eq!(mask(63), u64::MAX >> 1);
355 assert_eq!(mask(64), u64::MAX);
356 }
357
358 #[test]
359 fn test_max() {
360 assert_eq!(Uint::<0, 0>::MAX, Uint::ZERO);
361 assert_eq!(Uint::<1, 1>::MAX, Uint::from_limbs([1]));
362 assert_eq!(Uint::<7, 1>::MAX, Uint::from_limbs([127]));
363 assert_eq!(Uint::<64, 1>::MAX, Uint::from_limbs([u64::MAX]));
364 assert_eq!(
365 Uint::<100, 2>::MAX,
366 Uint::from_limbs([u64::MAX, u64::MAX >> 28])
367 );
368 }
369
370 #[test]
371 fn test_constants() {
372 const_for!(BITS in SIZES {
373 const LIMBS: usize = nlimbs(BITS);
374 assert_eq!(Uint::<BITS, LIMBS>::MIN, Uint::<BITS, LIMBS>::ZERO);
375 let _ = Uint::<BITS, LIMBS>::MAX;
376 });
377 }
378}