Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ jobs:
strategy:
fail-fast: false
matrix:
rust: ["stable", "beta", "nightly", "1.65"] # MSRV
rust: ["stable", "beta", "nightly", "1.85"] # MSRV
flags: ["--no-default-features", "", "--all-features"]
exclude:
# Skip because some features have higher MSRV.
- rust: "1.65" # MSRV
- rust: "1.85" # MSRV
flags: "--all-features"
steps:
- uses: actions/checkout@v4
Expand All @@ -44,20 +44,20 @@ jobs:
cache-on-failure: true
# Only run tests on latest stable and above
- name: Check
if: ${{ matrix.rust == '1.65' }} # MSRV
if: ${{ matrix.rust == '1.85' }} # MSRV
run: cargo check ${{ matrix.flags }}

# Cargo doc test is not included in `--all-targets` so we call it separately.
# See <https://github.com/rust-lang/cargo/issues/6669>
# Cargo doc test also doesn't support `--no-run`, so we run it but
# have it just print `--help`.
- name: Build tests
if: ${{ matrix.rust != '1.65' }} # MSRV
if: ${{ matrix.rust != '1.85' }} # MSRV
run: |
cargo test --workspace ${{ matrix.flags }} --all-targets --no-run
cargo test --workspace ${{ matrix.flags }} --doc -- --help
- name: Run tests
if: ${{ matrix.rust != '1.65' }} # MSRV
if: ${{ matrix.rust != '1.85' }} # MSRV
run: |
cargo test --workspace ${{ matrix.flags }} --all-targets -- --nocapture
cargo test --workspace ${{ matrix.flags }} --doc -- --nocapture
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- MSRV bumped to 1.85 ([#503])

[#503]: https://github.com/recmo/uint/pull/503

## [1.16.0] - 2025-08-04

### Added
Expand Down
35 changes: 33 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,43 @@ resolver = "2"

[workspace.package]
edition = "2021"
rust-version = "1.65"
rust-version = "1.85"
authors = ["Remco Bloemen <remco@wicked.ventures>"]
license = "MIT"
homepage = "https://github.com/recmo/uint"
repository = "https://github.com/recmo/uint"

[workspace.lints.clippy]
all = { level = "warn", priority = -1 }
pedantic = { level = "warn", priority = -1 }
nursery = { level = "warn", priority = -1 }
missing-inline-in-public-items = "warn"
std-instead-of-alloc = "warn"
std-instead-of-core = "warn"

doc-markdown = "allow" # Unfortunately many false positives on Latex.
inline-always = "allow"
module-name-repetitions = "allow"
redundant-pub-crate = "allow"
unreadable-literal = "allow"
let-unit-value = "allow"
option-if-let-else = "allow"
cast-sign-loss = "allow"
cast-lossless = "allow"

[workspace.lints.rust]
missing-copy-implementations = "warn"
missing-debug-implementations = "warn"
missing-docs = "warn"
rust-2018-idioms = "warn"
unreachable-pub = "warn"
unused-must-use = "warn"
redundant-lifetimes = "warn"
unnameable-types = "warn"

[workspace.lints.rustdoc]
all = "warn"

[dependencies]
ruint-macro = { version = "1.2.1", path = "ruint-macro" }

Expand Down Expand Up @@ -141,7 +172,6 @@ std = [
"valuable?/std",
"zeroize?/std",
]
ssz = ["std", "dep:ethereum_ssz"]
alloc = [
"proptest?/alloc",
"rand-08?/alloc",
Expand Down Expand Up @@ -183,6 +213,7 @@ rkyv = ["dep:rkyv", "alloc"]
rlp = ["dep:rlp", "alloc"]
serde = ["dep:serde", "alloc"] # TODO: try to avoid alloc in serde impls
sqlx = ["dep:sqlx-core", "std", "dep:thiserror"]
ssz = ["dep:ethereum_ssz", "std"]
subtle = ["dep:subtle"]
valuable = ["dep:valuable"]
zeroize = ["dep:zeroize"]
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ When updating this, also update:

Uint will keep a rolling MSRV (minimum supported rust version) policy of **at
least** 6 months. When increasing the MSRV, the new Rust version must have been
released at least six months ago. The current MSRV is 1.65.0.
released at least six months ago. The current MSRV is 1.85.0.

Note that the MSRV is not increased automatically, and only as part of a minor
release.
Expand Down
2 changes: 1 addition & 1 deletion clippy.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
msrv = "1.65"
msrv = "1.85"
doc-valid-idents = ["CPython", "PyPy", ".."]
4 changes: 2 additions & 2 deletions ruint-macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ fn parse_digits(value: &str) -> Result<Vec<u64>, String> {

fn pad_limbs(bits: usize, mut limbs: Vec<u64>) -> Option<Vec<u64>> {
// Get limb count and mask
let num_limbs = (bits + 63) / 64;
let num_limbs = bits.div_ceil(64);
let mask = if bits == 0 {
0
} else {
Expand Down Expand Up @@ -196,7 +196,7 @@ impl Transformer {
write!(&mut limbs_str, "0x{limb:016x}_u64, ").unwrap();
}
let limbs_str = limbs_str.trim_end_matches(", ");
let limbs = (bits + 63) / 64;
let limbs = bits.div_ceil(64);
let source = format!("::{base_type}::<{bits}, {limbs}>::from_limbs([{limbs_str}])");

let mut tokens = self.ruint_crate.clone();
Expand Down
1 change: 1 addition & 0 deletions src/algorithms/mul_redc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ fn reduce1_carry<const N: usize>(value: [u64; N], modulus: [u64; N], carry: bool
let (reduced, borrow) = sub(value, modulus);
// TODO: Ideally this turns into a cmov, which makes the whole mul_redc constant
// time.
// TODO(MSRV-1.88): Use `core::hint::select_unpredictable`.
if carry | !borrow {
reduced
} else {
Expand Down
5 changes: 1 addition & 4 deletions src/base_convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,10 +393,7 @@ impl<const LIMBS: usize> SpigotBuf<LIMBS> {
base = crate::utils::max_pow_u64(base);

let mut buf = [[MaybeUninit::uninit(); 2]; LIMBS];
// TODO(MSRV-1.80): let as_slice = buf.as_flattened_mut();
let as_slice = unsafe {
core::slice::from_raw_parts_mut(buf.as_mut_ptr().cast::<MaybeUninit<u64>>(), LIMBS * 2)
};
let as_slice = buf.as_flattened_mut();
let mut i = 0;
for limb in SpigotLittle::new(limbs, base) {
debug_assert!(
Expand Down
2 changes: 1 addition & 1 deletion src/bit_arr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ impl<const BITS: usize, const LIMBS: usize> Bits<BITS, LIMBS> {
/// Returns a mutable reference to the inner [Uint].
#[must_use]
#[inline(always)]
pub fn as_uint_mut(&mut self) -> &mut Uint<BITS, LIMBS> {
pub const fn as_uint_mut(&mut self) -> &mut Uint<BITS, LIMBS> {
&mut self.0
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/bits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {

/// Sets a specific bit to a value.
#[inline]
pub fn set_bit(&mut self, index: usize, value: bool) {
pub const fn set_bit(&mut self, index: usize, value: bool) {
if index >= BITS {
return;
}
Expand Down Expand Up @@ -248,7 +248,7 @@ impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
#[must_use]
#[inline]
pub const fn byte_len(&self) -> usize {
(self.bit_len() + 7) / 8
self.bit_len().div_ceil(8)
}

/// Returns the most significant 64 bits of the number and the exponent.
Expand Down
23 changes: 11 additions & 12 deletions src/bytes.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
// OPT: Use u64::from_{be/le}_bytes() to work 8 bytes at a time.
// FEATURE: (BLOCKED) Make `const fn`s when `const_for` is stable.

use crate::Uint;
use core::slice;

Expand All @@ -12,7 +9,7 @@ use alloc::{borrow::Cow, vec::Vec};
impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
/// The size of this integer type in bytes. Note that some bits may be
/// forced zero if BITS is not cleanly divisible by eight.
pub const BYTES: usize = (BITS + 7) / 8;
pub const BYTES: usize = BITS.div_ceil(8);

/// Access the underlying store as a little-endian slice of bytes.
///
Expand All @@ -39,7 +36,7 @@ impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
#[cfg(target_endian = "little")]
#[must_use]
#[inline(always)]
pub unsafe fn as_le_slice_mut(&mut self) -> &mut [u8] {
pub const unsafe fn as_le_slice_mut(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.limbs.as_mut_ptr().cast(), Self::BYTES) }
}

Expand Down Expand Up @@ -96,8 +93,7 @@ impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
#[inline]
#[must_use]
pub const fn to_le_bytes<const BYTES: usize>(&self) -> [u8; BYTES] {
// TODO: Use a `const {}` block for this assertion
assert!(BYTES == Self::BYTES, "BYTES must be equal to Self::BYTES");
const { Self::assert_bytes(BYTES) }

// Specialized impl
#[cfg(target_endian = "little")]
Expand Down Expand Up @@ -209,8 +205,7 @@ impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
#[track_caller]
#[inline]
pub const fn from_be_bytes<const BYTES: usize>(bytes: [u8; BYTES]) -> Self {
// TODO: Use a `const {}` block for this assertion
assert!(BYTES == Self::BYTES, "BYTES must be equal to Self::BYTES");
const { Self::assert_bytes(BYTES) }
Self::from_be_slice(&bytes)
}

Expand Down Expand Up @@ -288,8 +283,7 @@ impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
#[track_caller]
#[inline]
pub const fn from_le_bytes<const BYTES: usize>(bytes: [u8; BYTES]) -> Self {
// TODO: Use a `const {}` block for this assertion
assert!(BYTES == Self::BYTES, "BYTES must be equal to Self::BYTES");
const { Self::assert_bytes(BYTES) }
Self::from_le_slice(&bytes)
}

Expand Down Expand Up @@ -453,6 +447,11 @@ impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {

Some(self.copy_be_bytes_to(buf))
}

#[track_caller]
const fn assert_bytes(bytes: usize) {
assert!(bytes == Self::BYTES, "BYTES must be equal to Self::BYTES");
}
}

/// Number of bytes required to represent the given number of bits.
Expand All @@ -463,7 +462,7 @@ impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
#[inline]
#[must_use]
pub const fn nbytes(bits: usize) -> usize {
(bits + 7) / 8
bits.div_ceil(8)
}

#[cfg(test)]
Expand Down
7 changes: 1 addition & 6 deletions src/fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,36 +17,31 @@ mod base {
const MAX: u64 = crate::utils::max_pow_u64(Self::BASE);
/// Number of characters written using `MAX` as the base in
/// `to_base_be`.
// TODO(MSRV-1.67): = `Self::MAX.ilog(Self::BASE)`
const WIDTH: usize;
const WIDTH: usize = Self::MAX.ilog(Self::BASE) as _;
}

pub(super) struct Binary;
impl Base for Binary {
const BASE: u64 = 2;
const PREFIX: &'static str = "0b";
const WIDTH: usize = 63;
}

pub(super) struct Octal;
impl Base for Octal {
const BASE: u64 = 8;
const PREFIX: &'static str = "0o";
const WIDTH: usize = 21;
}

pub(super) struct Decimal;
impl Base for Decimal {
const BASE: u64 = 10;
const PREFIX: &'static str = "";
const WIDTH: usize = 19;
}

pub(super) struct Hexadecimal;
impl Base for Hexadecimal {
const BASE: u64 = 16;
const PREFIX: &'static str = "0x";
const WIDTH: usize = 15;
}
}
use base::Base;
Expand Down
41 changes: 6 additions & 35 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,5 @@
#![doc = include_str!("../README.md")]
#![doc(issue_tracker_base_url = "https://github.com/recmo/uint/issues/")]
#![warn(
clippy::all,
clippy::pedantic,
clippy::nursery,
clippy::missing_inline_in_public_items,
clippy::std_instead_of_alloc,
clippy::std_instead_of_core,
missing_docs,
unreachable_pub
)]
#![allow(
clippy::doc_markdown, // Unfortunately many false positives on Latex.
clippy::inline_always,
clippy::module_name_repetitions,
clippy::redundant_pub_crate,
clippy::unreadable_literal,
clippy::let_unit_value,
clippy::option_if_let_else,
clippy::cast_sign_loss,
clippy::cast_lossless,
)]
#![cfg_attr(test, allow(clippy::wildcard_imports, clippy::cognitive_complexity))]
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
#![cfg_attr(not(feature = "std"), no_std)]
Expand Down Expand Up @@ -113,14 +92,6 @@ pub mod nightly {
pub type Bits<const BITS: usize> = crate::Bits<BITS, { crate::nlimbs(BITS) }>;
}

// FEATURE: (BLOCKED) Many functions could be made `const` if a number of
// features land. This requires
// #![feature(const_mut_refs)]
// #![feature(const_float_classify)]
// #![feature(const_fn_floating_point_arithmetic)]
// #![feature(const_float_bits_conv)]
// and more.

/// Packed u128, for [`as_double_words`](Uint::as_double_words).
#[derive(Clone, Copy)]
#[allow(non_camel_case_types)]
Expand Down Expand Up @@ -225,7 +196,7 @@ impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
/// size if the bit-size is not limb-aligned.
#[inline(always)]
#[must_use]
pub unsafe fn as_limbs_mut(&mut self) -> &mut [u64; LIMBS] {
pub const unsafe fn as_limbs_mut(&mut self) -> &mut [u64; LIMBS] {
&mut self.limbs
}

Expand Down Expand Up @@ -263,12 +234,14 @@ impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
"Value too large for this Uint"
);
}
let _ = Self::LIMBS; // Triggers the assertion.
Self { limbs }
}

#[inline(always)]
#[must_use]
const fn from_limbs_unmasked(limbs: [u64; LIMBS]) -> Self {
let _ = Self::LIMBS; // Triggers the assertion.
Self { limbs }.masked()
}

Expand Down Expand Up @@ -341,17 +314,15 @@ impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
}

#[inline(always)]
fn apply_mask(&mut self) {
const fn apply_mask(&mut self) {
if Self::SHOULD_MASK {
self.limbs[LIMBS - 1] &= Self::MASK;
}
}

#[inline(always)]
const fn masked(mut self) -> Self {
if Self::SHOULD_MASK {
self.limbs[LIMBS - 1] &= Self::MASK;
}
self.apply_mask();
self
}
}
Expand All @@ -368,7 +339,7 @@ impl<const BITS: usize, const LIMBS: usize> Default for Uint<BITS, LIMBS> {
#[inline]
#[must_use]
pub const fn nlimbs(bits: usize) -> usize {
(bits + 63) / 64
bits.div_ceil(64)
}

/// Mask to apply to the highest limb to get the correct number of bits.
Expand Down
Loading