Skip to content

Commit

Permalink
Refint hint feature (#49)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
danlehmann authored Dec 2, 2024
1 parent 680553d commit 18d8ac2
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 10 deletions.
18 changes: 18 additions & 0 deletions .github/workflows/test-hint.yml
Original file line number Diff line number Diff line change
@@ -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
30 changes: 22 additions & 8 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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<T>` 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<T>` 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

Expand Down
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
16 changes: 16 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ impl<T: Copy, const BITS: usize> UInt<T, BITS> {
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
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 18d8ac2

Please sign in to comment.