Skip to content

Commit

Permalink
Merge pull request #298 from recmo/num-traits
Browse files Browse the repository at this point in the history
Impl num-traits (fixes #226)
  • Loading branch information
recmo authored Aug 28, 2023
2 parents b3b7d84 + 19013ec commit 585c5ce
Show file tree
Hide file tree
Showing 8 changed files with 616 additions and 16 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- `bytemuck` feature ([#292])
- `num-traits` features ([#298])

[#292]: https://github.com/recmo/uint/pulls/292
[#298]: https://github.com/recmo/uint/pulls/298

### Fixed

- `leading_ones` failed for non-aligned sizes.

## [1.10.1] - 2023-07-30

Expand Down
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ ark-ff-04 = { version = "0.4.0", package = "ark-ff", optional = true, default-fe
bn-rs = { version = "0.2", optional = true, default-features = true }
fastrlp = { version = "0.3", optional = true, default-features = false, features = ["alloc"] }
num-bigint = { version = "0.4", optional = true, default-features = false }
num-traits = { version = "0.2.16", optional = true, default-features = false }
parity-scale-codec = { version = "3", optional = true, features = [
"derive",
"max-encoded-len",
Expand Down Expand Up @@ -99,6 +100,7 @@ std = [
"bytes?/std",
"fastrlp?/std",
"num-bigint?/std",
"num-traits?/std",
"parity-scale-codec?/std",
"primitive-types?/std",
"proptest?/std",
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ named feature flag.
* [`parity-scale-codec`](https://docs.rs/parity-scale-codec): Implements the [`Encode`](https://docs.rs/parity-scale-codec/latest/parity_scale_codec/trait.Encode.html), [`Decode`](https://docs.rs/parity-scale-codec/latest/parity_scale_codec/trait.Decode.html), [`MaxEncodedLen`](https://github.com/paritytech/parity-scale-codec/blob/47d98a1c23dabc890fdb548d115a18070082c66e/src/max_encoded_len.rs) and [`HasCompact`](https://docs.rs/parity-scale-codec/latest/parity_scale_codec/trait.HasCompact.html) traits.
* [`bn-rs`](https://docs.rs/bn-rs/latest/bn_rs/): Implements conversion to/from the [`BN`](https://docs.rs/bn-rs/latest/bn_rs/struct.BN.html) and [`BigNumber`](https://docs.rs/bn-rs/latest/bn_rs/struct.BigNumber.html).
* [`bytemuck`](https://docs.rs/bytemuck): Implements the [`Pod`](https://docs.rs/bytemuck/latest/bytemuck/trait.Pod.html) and [`Zeroable`](https://docs.rs/bytemuck/latest/bytemuck/trait.Zeroable.html) traits for [`Uint`] where the size is a multiple of 64, up to 1024. This allows `Uint` to be used where a `Pod` trait bound exists.

* [`num-traits`](https://docs.rs/num-traits): Implements about forty applicable traits.

## Building and testing

Expand Down
2 changes: 1 addition & 1 deletion ruint-macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ enum LiteralBaseType {
}

impl LiteralBaseType {
const PATTERN: &[char] = &['U', 'B'];
const PATTERN: &'static [char] = &['U', 'B'];
}

impl Display for LiteralBaseType {
Expand Down
61 changes: 50 additions & 11 deletions src/bits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,20 +111,11 @@ impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
})
}

/// Returns the number of leading zeros in the binary representation of
/// Returns the number of leading ones in the binary representation of
/// `self`.
#[must_use]
pub fn leading_ones(&self) -> usize {
self.as_limbs()
.iter()
.rev()
.position(|&limb| limb != u64::MAX)
.map_or(BITS, |n| {
let fixed = Self::MASK.leading_zeros() as usize;
let skipped = n * 64;
let top = self.as_limbs()[LIMBS - n - 1].leading_ones() as usize;
skipped + top - fixed
})
(self.not()).leading_zeros()
}

/// Returns the number of trailing zeros in the binary representation of
Expand Down Expand Up @@ -412,6 +403,20 @@ impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
self.overflowing_shr(rhs).0
}

/// Arithmetic shift right by `rhs` bits.
#[must_use]
pub fn arithmetic_shr(self, rhs: usize) -> Self {
if BITS == 0 {
return Self::ZERO;
}
let sign = self.bit(BITS - 1);
let mut r = self >> rhs;
if sign {
r |= Self::MAX << BITS.saturating_sub(rhs);
}
r
}

/// Shifts the bits to the left by a specified amount, `rhs`, wrapping the
/// truncated bits to the end of the resulting integer.
#[must_use]
Expand Down Expand Up @@ -649,11 +654,14 @@ impl<const BITS: usize, const LIMBS: usize> Shr<&usize> for &Uint<BITS, LIMBS> {
mod tests {
use super::*;
use crate::{aliases::U128, const_for, nlimbs};
use core::cmp::min;
use proptest::proptest;

#[test]
fn test_leading_zeros() {
assert_eq!(Uint::<0, 0>::ZERO.leading_zeros(), 0);
assert_eq!(Uint::<1, 1>::ZERO.leading_zeros(), 1);
assert_eq!(Uint::<1, 1>::from(1).leading_zeros(), 0);
const_for!(BITS in NON_ZERO {
const LIMBS: usize = nlimbs(BITS);
type U = Uint::<BITS, LIMBS>;
Expand All @@ -679,6 +687,13 @@ mod tests {
});
}

#[test]
fn test_leading_ones() {
assert_eq!(Uint::<0, 0>::ZERO.leading_ones(), 0);
assert_eq!(Uint::<1, 1>::ZERO.leading_ones(), 0);
assert_eq!(Uint::<1, 1>::from(1).leading_ones(), 1);
}

#[test]
fn test_most_significant_bits() {
const_for!(BITS in NON_ZERO {
Expand Down Expand Up @@ -730,11 +745,19 @@ mod tests {
assert_eq!(a.reverse_bits(), Uint::from((a.limbs[0] as u32).reverse_bits() as u64));
assert_eq!(a.rotate_left(s), Uint::from((a.limbs[0] as u32).rotate_left(s as u32) as u64));
assert_eq!(a.rotate_right(s), Uint::from((a.limbs[0] as u32).rotate_right(s as u32) as u64));
if s < 32 {
let arr_shifted = (((a.limbs[0] as i32) >> s) as u32) as u64;
assert_eq!(a.arithmetic_shr(s), Uint::from_limbs([arr_shifted]));
}
});
proptest!(|(a: Uint::<64, 1>, s in 0_usize..=66)| {
assert_eq!(a.reverse_bits(), Uint::from(a.limbs[0].reverse_bits()));
assert_eq!(a.rotate_left(s), Uint::from(a.limbs[0].rotate_left(s as u32)));
assert_eq!(a.rotate_right(s), Uint::from(a.limbs[0].rotate_right(s as u32)));
if s < 64 {
let arr_shifted = ((a.limbs[0] as i64) >> s) as u64;
assert_eq!(a.arithmetic_shr(s), Uint::from_limbs([arr_shifted]));
}
});
}

Expand Down Expand Up @@ -762,4 +785,20 @@ mod tests {
});
});
}

#[test]
fn test_arithmetic_shr() {
const_for!(BITS in SIZES {
const LIMBS: usize = nlimbs(BITS);
type U = Uint::<BITS, LIMBS>;
proptest!(|(value: U, shift in 0..=BITS + 2)| {
let shifted = value.arithmetic_shr(shift);
dbg!(value, shifted, shift);
assert_eq!(shifted.leading_ones(), match value.leading_ones() {
0 => 0,
n => min(BITS, n + shift)
});
});
});
}
}
2 changes: 1 addition & 1 deletion src/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {

/// Access the underlying store as a little-endian slice of bytes.
///
/// Only available on litte-endian targets.
/// Only available on little-endian targets.
///
/// If `BITS` does not evenly divide 8, it is padded with zero bits in the
/// most significant position.
Expand Down
3 changes: 1 addition & 2 deletions src/support/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod bn_rs;
mod bytemuck;
mod fastrlp;
mod num_bigint;
mod num_traits;
pub mod postgres;
mod primitive_types;
mod proptest;
Expand All @@ -22,7 +23,6 @@ mod valuable;
mod zeroize;

// FEATURE: Support for many more traits and crates.
// * https://crates.io/crates/num-traits
// * https://crates.io/crates/der
// * https://crates.io/crates/bitvec

Expand All @@ -40,4 +40,3 @@ mod zeroize;

// More databases:
// * https://crates.io/crates/diesel

Loading

0 comments on commit 585c5ce

Please sign in to comment.