From 18d8ac258980e5f8ca98cce55a4238bd360f313e Mon Sep 17 00:00:00 2001 From: Daniel Lehmann <59584561+danlehmann@users.noreply.github.com> Date: Mon, 2 Dec 2024 13:43:01 -0800 Subject: [PATCH] Refint hint feature (#49) * Refint hint feature Most importantly, this now applies hint to `const fn value()`, which is probably the most common way to access it. Also adds integration tests for the feature. * Add new feature to changelog and describe trade-off of public feature * Fix typo --- .github/workflows/test-hint.yml | 18 ++++++++++++++++++ CHANGELOG.md | 30 ++++++++++++++++++++++-------- Cargo.toml | 5 +++-- src/lib.rs | 16 ++++++++++++++++ 4 files changed, 59 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/test-hint.yml diff --git a/.github/workflows/test-hint.yml b/.github/workflows/test-hint.yml new file mode 100644 index 0000000..0ee8731 --- /dev/null +++ b/.github/workflows/test-hint.yml @@ -0,0 +1,18 @@ +name: test release +run-name: ${{ github.actor }}'s patch +on: [push] +jobs: + build-and-test: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: '14' + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + - uses: actions-rs/cargo@v1 + with: + command: test + args: --no-default-features --features hint \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index a31fa94..269c819 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,32 +1,46 @@ # Changelog +## arbitrary-int 1.2.8 + +### Added + +- New optional feature `hint`, which tells the compiler that the returned `value()` can't exceed a maximum value. This + allows the compiler to optimize faster code at the expense of unsafe code within arbitrary-int itself. + ## arbitrary-int 1.2.7 ### Added -- Support `Step` so that arbitrary-int can be used in a range expression, e.g. `for n in u3::MIN..=u3::MAX { println!("{n}") }`. Note this trait is currently unstable, and so is only usable in nightly. Enable this feature with `step_trait`. +- Support `Step` so that arbitrary-int can be used in a range expression, e.g. + `for n in u3::MIN..=u3::MAX { println!("{n}") }`. Note this trait is currently unstable, and so is only usable in + nightly. Enable this feature with `step_trait`. - Support formatting via [defmt](https://crates.io/crates/defmt). Enable the option `defmt` feature - Support serializing and deserializing via [serde](https://crates.io/crates/serde). Enable the option `serde` feature - Support `Mul`, `MulAssign`, `Div`, `DivAssign` - The following new methods were implemented to make arbitrary ints feel more like built-in types: - * `wrapping_add`, `wrapping_sub`, `wrapping_mul`, `wrapping_div`, `wrapping_shl`, `wrapping_shr` - * `saturating_add`, `saturating_sub`, `saturating_mul`, `saturating_div`, `saturating_pow` - * `checked_add`, `checked_sub`, `checked_mul`, `checked_div`, `checked_shl`, `checked_shr` - * `overflowing_add`, `overflowing_sub`, `overflowing_mul`, `overflowing_div`, `overflowing_shl`, `overflowing_shr` + * `wrapping_add`, `wrapping_sub`, `wrapping_mul`, `wrapping_div`, `wrapping_shl`, `wrapping_shr` + * `saturating_add`, `saturating_sub`, `saturating_mul`, `saturating_div`, `saturating_pow` + * `checked_add`, `checked_sub`, `checked_mul`, `checked_div`, `checked_shl`, `checked_shr` + * `overflowing_add`, `overflowing_sub`, `overflowing_mul`, `overflowing_div`, `overflowing_shl`, `overflowing_shr` ### Changed -- In debug builds, `<<` (`Shl`, `ShlAssign`) and `>>` (`Shr`, `ShrAssign`) now bounds-check the shift amount using the same semantics as built-in shifts. For example, shifting a u5 by 5 or more bits will now panic as expected. + +- In debug builds, `<<` (`Shl`, `ShlAssign`) and `>>` (`Shr`, `ShrAssign`) now bounds-check the shift amount using the + same semantics as built-in shifts. For example, shifting a u5 by 5 or more bits will now panic as expected. ## arbitrary-int 1.2.6 ### Added -- Support `LowerHex`, `UpperHex`, `Octal`, `Binary` so that arbitrary-int can be printed via e.g. `format!("{:x}", u4::new(12))` +- Support `LowerHex`, `UpperHex`, `Octal`, `Binary` so that arbitrary-int can be printed via e.g. + `format!("{:x}", u4::new(12))` - Support `Hash` so that arbitrary-int can be used in hash tables ### Changed -- As support for `[const_trait]` has recently been removed from structs like `From` in upstream Rust, opting-in to the `nightly` feature no longer enables this behavior as that would break the build. To continue using this feature with older compiler versions, use `const_convert_and_const_trait_impl` instead. +- As support for `[const_trait]` has recently been removed from structs like `From` in upstream Rust, opting-in to + the `nightly` feature no longer enables this behavior as that would break the build. To continue using this feature + with older compiler versions, use `const_convert_and_const_trait_impl` instead. ## arbitrary-int 1.2.5 diff --git a/Cargo.toml b/Cargo.toml index 68d0183..15638f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,8 +31,9 @@ borsh = ["dep:borsh"] schemars = ["dep:schemars", "std"] -# Provide a soundness promixe to the compiler that the unerlying value is always within range -# This optimizes e.g. indexing range checks when passed in an API +# Provide a soundness promise to the compiler that the underlying value is always within range. +# This optimizes e.g. indexing range checks when passed in an API. +# The downside of this feature is that it involves an unsafe call to `core::hint::assert_unchecked` during `value()`. hint = [] [dependencies] diff --git a/src/lib.rs b/src/lib.rs index 300b8ca..c3fb502 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -129,6 +129,7 @@ impl UInt { pub const BITS: usize = BITS; /// Returns the type as a fundamental data type + #[cfg(not(feature = "hint"))] #[inline] pub const fn value(self) -> T { self.value @@ -271,6 +272,21 @@ macro_rules! uint_impl { } } + /// Returns the type as a fundamental data type + #[cfg(feature = "hint")] + #[inline] + pub const fn value(self) -> $type { + // The hint feature requires the type to be const-comparable, + // which isn't possible in the generic version above. So we have + // an entirely different function if this feature is enabled. + // It only works for primitive types, which should be ok in practice + // (but is technically an API change) + unsafe { + core::hint::assert_unchecked(self.value <= Self::MAX.value); + } + self.value + } + #[deprecated(note = "Use one of the specific functions like extract_u32")] pub const fn extract(value: $type, start_bit: usize) -> Self { assert!(start_bit + BITS <= $type::BITS as usize);