Skip to content

Commit

Permalink
Merge pull request #46 from isaacholt100/latest
Browse files Browse the repository at this point in the history
Latest
  • Loading branch information
isaacholt100 authored Sep 20, 2024
2 parents d715a3e + 1eaa169 commit eeefc69
Show file tree
Hide file tree
Showing 27 changed files with 559 additions and 159 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ jobs:
- name: Install latest stable Rust
run: rustup install stable
- name: Check crate builds on stable
run: cargo build --features serde,numtraits,rand,arbitrary && cargo build
# NOTE: consider using https://github.com/frewsxcv/cargo-all-features, because all features != their arbitrary combinations
run: cargo build --features serde,numtraits,rand,arbitrary,borsh && cargo build
test_nightly:
runs-on: ubuntu-latest
steps:
Expand Down
8 changes: 6 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "bnum"
version = "0.11.0"
version = "0.12.0"
authors = ["isaac-holt <isaac_holt@icloud.com>"]
edition = "2021"
license = "MIT OR Apache-2.0"
Expand Down Expand Up @@ -33,6 +33,7 @@ quickcheck = { version = "1.0", optional = true, default-features = false }
# proptest = { version = "1.2", optional = true, default-features = false }
valuable = { version = "0.1", optional = true, features = ["derive"], default-features = false }
# lit-parser = { path = "./lit-parser/", optional = true }
borsh = { version = "^1.5", optional = true, default-features = false, features = ["unstable__schema"] }

[dev-dependencies]
quickcheck = "1.0"
Expand All @@ -44,4 +45,7 @@ lto = true # enable link-time optimisation for faster runtime, but slower compil
opt-level = 3 # maximum optimisation level for faster runtime, but slower compile time

[package.metadata.docs.rs]
all-features = true
all-features = true

[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(test_int_bits, values("64", "128"))'] }
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,21 @@ This crate uses Rust's const generics to allow creation of integers of arbitrary

- **Zero dependencies by default**: `bnum` does not depend on any other crates by default. Support for crates such as [`rand`](https://docs.rs/rand/latest/rand/) and [`serde`](https://docs.rs/serde/latest/serde/) can be enabled with crate [features](#features).
- **`no-std` compatible**: `bnum` can be used in `no_std` environments, provided that the [`arbitrary`](#fuzzing) and [`quickcheck`](#quickcheck) features are not enabled.
- **Compile-time integer parsing**: the `from_str_radix` and `parse_str_radix` methods on `bnum` integers are `const`, which allows parsing of integers from string slices at compile time. Note that this is more powerful than compile-time parsing of integer literals. This is because it allows parsing of strings in all radices from `2` to `36` inclusive instead of just `2`, `8`, `10` and `16`. Additionally, the string to be parsed does not have to be a literal: it could, for example, be obtained via [`include_str!`](https://doc.rust-lang.org/core/macro.include_str.html), or [`env!`](https://doc.rust-lang.org/core/macro.env.html)`.
- **Compile-time integer parsing**: the `from_str_radix` and `parse_str_radix` methods on `bnum` integers are `const`, which allows parsing of integers from string slices at compile time. Note that this is more powerful than compile-time parsing of integer literals. This is because it allows parsing of strings in all radices from `2` to `36` inclusive instead of just `2`, `8`, `10` and `16`. Additionally, the string to be parsed does not have to be a literal: it could, for example, be obtained via [`include_str!`](https://doc.rust-lang.org/core/macro.include_str.html), or [`env!`](https://doc.rust-lang.org/core/macro.env.html).
- **`const` evaluation**: nearly all methods defined on `bnum` integers are `const`, which allows complex compile-time calculations.

## Installation

To install and use `bnum`, simply add the following line to your `Cargo.toml` file in the `[dependencies]` section:

```toml
bnum = "0.11.0"
bnum = "0.12.0"
```

Or, to enable various `bnum` features as well, add for example this line instead:

```toml
bnum = { version = "0.11.0", features = ["rand"] } # enables the "rand" feature
bnum = { version = "0.12.0", features = ["rand"] } # enables the "rand" feature
```

## Example Usage
Expand Down Expand Up @@ -113,6 +113,8 @@ The `rand` feature allows creation of random `bnum` integers via the [`rand`](ht

The `serde` feature enables serialization and deserialization of `bnum` integers via the [`serde`](https://docs.rs/serde/latest/serde/) and [`serde_big_array`](https://docs.rs/serde-big-array/latest/serde_big_array/) crates.

The `borsh` feature enables serialization and deserialization of `bnum` integers via the [`borsh`](https://docs.rs/borsh/latest/borsh/) crate.

### `num_traits` and `num_integer` trait implementations

The `numtraits` feature includes implementations of traits from the [`num_traits`](https://docs.rs/num-traits/latest/num_traits/) and [`num_integer`](https://docs.rs/num-integer/latest/num_integer/) crates, e.g. [`AsPrimitive`](https://docs.rs/num-traits/latest/num_traits/cast/trait.AsPrimitive.html), [`Signed`](https://docs.rs/num-traits/latest/num_traits/sign/trait.Signed.html), [`Integer`](https://docs.rs/num-integer/latest/num_integer/trait.Integer.html) and [`Roots`](https://docs.rs/num-integer/latest/num_integer/trait.Roots.html).
Expand All @@ -131,7 +133,7 @@ The `valuable` feature enables the [`Valuable`](https://docs.rs/valuable/latest/

### Nightly features

Activating the `nightly` feature will enable the `from_be_bytes`, `from_le_bytes`, `from_ne_bytes`, `to_be_bytes`, `to_le_bytes` and `to_ne_bytes` methods on `bnum`'s unsigned and signed integers and will make the `unchecked_...` methods `const`. This comes at the cost of only being able to compile on nightly. The nightly features that this uses are [`generic_const_exprs`](https://github.com/rust-lang/rust/issues/76560), [`const_trait_impl`](https://github.com/rust-lang/rust/issues/67792) and [`const_option_ext`](https://github.com/rust-lang/rust/issues/91930).
Activating the `nightly` feature will enable the `from_be_bytes`, `from_le_bytes`, `from_ne_bytes`, `to_be_bytes`, `to_le_bytes` and `to_ne_bytes` methods on `bnum`'s unsigned and signed integers and will make the `unchecked_...` methods `const`. This comes at the cost of only being able to compile on nightly. The nightly features that this uses are [`generic_const_exprs`](https://github.com/rust-lang/rust/issues/76560), [`const_trait_impl`](https://github.com/rust-lang/rust/issues/67792), [`effects`](https://github.com/rust-lang/rust/issues/102090) and [`const_option`](https://github.com/rust-lang/rust/issues/67441).

## Testing

Expand Down
9 changes: 9 additions & 0 deletions changes/v0.12.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
- Add optional borsh support
- Add `digits_mut` method to unsigned integers.
- `As` and `CastFrom` traits no longer const, as const trait support removed from latest nightly.
- `cast_signed` method for unsigned integers.
- `cast_unsigned` method for signed integers.
- `midpoint` method for integers.
- `carrying_add` and `borrowing_sub` methods for signed integers.
- strict methods added.
- added `(bnum) ` prefix to error messages that were lacking it.
20 changes: 20 additions & 0 deletions src/bint/bigint_helpers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
macro_rules! bigint_helpers {
($BUint: ident, $BInt: ident, $Digit: ident) => {
#[doc = doc::bigint_helpers::impl_desc!()]
impl<const N: usize> $BInt<N> {
crate::int::bigint_helpers::impls!(I);
}

#[cfg(test)]
paste::paste! {
mod [<$Digit _digit_tests>] {
use crate::test::types::big_types::$Digit::*;
crate::int::bigint_helpers::tests!(itest);
}
}
};
}

use crate::doc;

crate::macro_impl!(bigint_helpers);
2 changes: 1 addition & 1 deletion src/bint/const_trait_fillers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ macro_rules! const_trait_fillers {
#[inline]
pub const fn neg(self) -> Self {
#[cfg(debug_assertions)]
return crate::errors::option_expect!(self.checked_neg(), crate::errors::err_msg!("attempt to negate with overflow"));
return self.strict_neg();

#[cfg(not(debug_assertions))]
self.wrapping_neg()
Expand Down
40 changes: 35 additions & 5 deletions src/bint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,19 @@ macro_rules! ilog {
}
}

#[cfg(debug_assertions)]
use crate::errors::option_expect;

use crate::digit;
use crate::ExpType;
use crate::{doc, errors};

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

#[cfg(feature = "borsh")]
use ::{
alloc::string::ToString,
borsh::{BorshDeserialize, BorshSchema, BorshSerialize},
};

use core::default::Default;

use core::iter::{Iterator, Product, Sum};
Expand All @@ -46,6 +49,7 @@ macro_rules! mod_impl {

#[derive(Clone, Copy, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize, BorshSchema))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(feature = "valuable", derive(valuable::Valuable))]
#[repr(transparent)]
Expand Down Expand Up @@ -99,6 +103,13 @@ macro_rules! mod_impl {
self.bits.trailing_ones()
}

#[doc = doc::cast_unsigned!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn cast_unsigned(self) -> $BUint<N> {
self.to_bits()
}

#[doc = doc::rotate_left!(I 256, "i")]
#[must_use = doc::must_use_op!()]
#[inline]
Expand Down Expand Up @@ -143,7 +154,7 @@ macro_rules! mod_impl {
#[inline]
pub const fn pow(self, exp: ExpType) -> Self {
#[cfg(debug_assertions)]
return option_expect!(self.checked_pow(exp), errors::err_msg!("attempt to calculate power with overflow"));
return self.strict_pow(exp);

#[cfg(not(debug_assertions))]
self.wrapping_pow(exp)
Expand All @@ -170,7 +181,7 @@ macro_rules! mod_impl {
#[inline]
pub const fn abs(self) -> Self {
#[cfg(debug_assertions)]
return option_expect!(self.checked_abs(), errors::err_msg!("attempt to negate with overflow"));
return self.strict_abs();

#[cfg(not(debug_assertions))]
match self.checked_abs() {
Expand Down Expand Up @@ -223,6 +234,20 @@ macro_rules! mod_impl {
!self.is_negative() &&self.bits.is_power_of_two()
}

#[doc = doc::midpoint!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn midpoint(self, rhs: Self) -> Self {
let m = Self::from_bits(self.to_bits().midpoint(rhs.to_bits()));
if self.is_negative() == rhs.is_negative() {
// signs agree. in the positive case, we can just compute as if they were unsigned. in the negative case, we compute as if unsigned, and the result is 2^(type bits) too large, but this is 0 (modulo 2^(type bits)) so does not affect the bits
m
} else {
// result is 2^(type bits - 1) too large, so subtract 2^(type bits - 1) by applying xor
m.bitxor(Self::MIN)
}
}

ilog!(ilog, base: Self);
ilog!(ilog2);
ilog!(ilog10);
Expand Down Expand Up @@ -420,6 +445,9 @@ macro_rules! mod_impl {
test_bignum! {
function: <itest>::is_negative(a: itest)
}
test_bignum! {
function: <itest>::cast_unsigned(a: itest)
}

#[test]
fn bit() {
Expand Down Expand Up @@ -483,6 +511,7 @@ macro_rules! mod_impl {

crate::macro_impl!(mod_impl);

mod bigint_helpers;
pub mod cast;
mod checked;
mod cmp;
Expand All @@ -497,5 +526,6 @@ mod ops;
mod overflowing;
mod radix;
mod saturating;
mod strict;
mod unchecked;
mod wrapping;
63 changes: 63 additions & 0 deletions src/bint/strict.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
macro_rules! strict {
($BUint: ident, $BInt: ident, $Digit: ident) => {
#[doc = doc::strict::impl_desc!()]
impl<const N: usize> $BInt<N> {
crate::int::strict::impls!(I);

#[doc = doc::strict::strict_abs!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn strict_abs(self) -> Self {
crate::errors::option_expect!(
self.checked_abs(),
crate::errors::err_msg!("attempt to negate with overflow")
)
}

#[doc = doc::strict::strict_add_unsigned!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn strict_add_unsigned(self, rhs: $BUint<N>) -> Self {
crate::errors::option_expect!(
self.checked_add_unsigned(rhs),
crate::errors::err_msg!("attempt to add with overflow")
)
}

#[doc = doc::strict::strict_sub_unsigned!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn strict_sub_unsigned(self, rhs: $BUint<N>) -> Self {
crate::errors::option_expect!(
self.checked_sub_unsigned(rhs),
crate::errors::err_msg!("attempt to subtract with overflow")
)
}
}

#[cfg(test)]
paste::paste! {
mod [<$Digit _digit_tests>] {
use crate::test::types::big_types::$Digit::*;
crate::int::strict::tests!(itest);

test_bignum! {
function: <itest>::strict_abs(a: itest),
skip: a.checked_abs().is_none()
}
test_bignum! {
function: <itest>::strict_add_unsigned(a: itest, b: utest),
skip: a.checked_add_unsigned(b).is_none()
}
test_bignum! {
function: <itest>::strict_sub_unsigned(a: itest, b: utest),
skip: a.checked_sub_unsigned(b).is_none()
}
}
}
};
}

use crate::doc;

crate::macro_impl!(strict);
16 changes: 8 additions & 8 deletions src/buint/as_float.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::ExpType;
use crate::cast::CastFrom;

#[cfg_attr(feature = "nightly", const_trait)]
// #[cfg_attr(feature = "nightly", const_trait)]
pub trait CastToFloatHelper: Copy {
const ZERO: Self;
const BITS: ExpType;
Expand Down Expand Up @@ -93,7 +93,7 @@ pub(crate) use impl_helper_buint;

crate::macro_impl!(impl_helper_buint);

#[cfg_attr(feature = "nightly", const_trait)]
// #[cfg_attr(feature = "nightly", const_trait)]
pub trait CastToFloatConsts {
type M: Mantissa;

Expand Down Expand Up @@ -131,7 +131,7 @@ macro_rules! cast_to_float_consts {

cast_to_float_consts!(f32; u32, f64; u64);

#[cfg_attr(feature = "nightly", const_trait)]
// #[cfg_attr(feature = "nightly", const_trait)]
pub trait Mantissa {
const ONE: Self;
const TWO: Self;
Expand All @@ -144,7 +144,7 @@ pub trait Mantissa {
fn add(self, rhs: Self) -> Self;
fn sub(self, rhs: Self) -> Self;
fn leading_zeros(self) -> ExpType;
fn bitand(self, rhs: Self) -> Self;
// fn bitand(self, rhs: Self) -> Self;
fn gt(&self, rhs: &Self) -> bool;
}

Expand Down Expand Up @@ -188,10 +188,10 @@ macro_rules! impl_mantissa_for_uint {
Self::leading_zeros(self) as ExpType
}

#[inline]
fn bitand(self, rhs: Self) -> Self {
self & rhs
}
// #[inline]
// fn bitand(self, rhs: Self) -> Self {
// self & rhs
// }

#[inline]
fn gt(&self, rhs: &Self) -> bool {
Expand Down
Loading

0 comments on commit eeefc69

Please sign in to comment.