#bounded #int #integer #bounds #saturating

comfy-bounded-ints

专注于舒适性和安全的边界整型类型。(见 README.md)

4 个版本

0.2.1 2024 年 5 月 11 日
0.2.0 2024 年 1 月 21 日
0.1.1 2024 年 1 月 10 日
0.1.0 2024 年 1 月 10 日

251Rust 模式

MIT 许可证

5MB
12K SLoC

专注于舒适性和安全的边界整型类型。

该包的目标是允许用户大胆地使用边界整数,而无需担心检查对其进行的操作。

有一个例外:除以零仍然会引发恐慌。

在使用之前,请务必仔细阅读此 README。

由于所有边界类型行为相同,因此此 README 是完整的文档。

  • 没有不安全代码。
  • 所有操作都是饱和的,没有溢出/下溢,没有包装。
  • 除以零仍然会引发恐慌。
  • 专注于舒适性和便捷性:允许使用不同整数类型(例如 i8 和 i16)的操作,这些操作使用更大的类型进行评估,然后结果被饱和到目标类型。
  • 操作的速度至少与 std::saturating 操作一样慢。如果您需要速度,请考虑使用 .get()deref * 运算符获取内部值的副本。
  • 大部分已通过测试覆盖。目前,派生的 Hash/PartialOrd/Ord 特性没有通过单元测试进行覆盖。

特性

默认情况下禁用所有特性。

  • div_assign_zero:启用未检查的除以零。(此特性未提供非零类型(NonZeroI8, ...)的除法)。
  • serde:启用 serde 序列化/反序列化支持,所有有界类型都透明地按其内部值进行序列化。例如:assert_eq!(serde_json::to_string(&Bound_i8::<0, 10>::new(5)).unwrap(), serde_json::to_string(&5_i8).unwrap()).

问题

支持所有 Rust 有符号/无符号类型:i8、i16、i32、i64、i128、isize、u8、u16、u32、u64、u128、usize

use comfy_bounded_ints::{
    Bound_i8, Bound_i16, Bound_i32, Bound_i64, Bound_i128, Bound_isize,
    Bound_u8, Bound_u16, Bound_u32, Bound_u64, Bound_u128, Bound_usize
};

约束在编译时强制执行,您可以使用 const 参数指定它们

使用 new 函数创建一个新的有界类型。如果 MIN > MAX,则 cargo build 不会编译

use comfy_bounded_ints::Bound_i16;

let bounded = Bound_i16::<20, 50>::new(30);
                          ^^^^^^

此软件包保证内部值始终在指定的范围内

没有任何操作可以违反此规则。

use comfy_bounded_ints::Bound_i32;

let bounded = Bound_i32::<20, 50>::new(80);
assert_eq!(bounded.get(), 50);
           ^^^^^^^^^^^^^^^^^

let bounded = Bound_i32::<20, 50>::new(10);
assert_eq!(bounded.get(), 20);
           ^^^^^^^^^^^^^^^^^

您可以使用 .get() 方法或 deref * 操作符来获取内部值的副本

use comfy_bounded_ints::Bound_i64;

let bounded = Bound_i64::<20, 50>::new(30);
assert_eq!(bounded.get(), 30);
                  ^^^^^^
assert_eq!(*bounded, 30);
           ^

请注意,所有有界类型都没有实现 DerefMut,因为这会允许违反约束。

如果您想修改内部值,则可以使用 .set() 方法或任何赋值运算符。

use comfy_bounded_ints::Bound_isize;

let mut bounded = Bound_isize::<20, 50>::new(30);
bounded.set(40);
       ^^^^^^^^
assert_eq!(bounded.get(), 40);

bounded += 10;
        ^^
assert_eq!(bounded.get(), 50);

bounded.set(10);
       ^^^^^^^^
assert_eq!(bounded.get(), 20);

bounded.set(80);
       ^^^^^^^^
assert_eq!(bounded.get(), 50);

bounded -= 10;
        ^^
assert_eq!(bounded.get(), 40);

bounded /= 2;
        ^^
assert_eq!(bounded.get(), 20);

bounded *= 2;
        ^^
assert_eq!(bounded.get(), 40);

bounded %= 30;
        ^^
assert_eq!(bounded.get(), 20);

AddAssign/SubAssign/MulAssign/DivAssign/RemAssign

允许在不同整数类型之间以及具有不同约束的有界类型之间进行操作。不支持常规的 Add/Sub/Mul/Div/Rem 操作,使用 .get* deref 在内部值上执行这些操作。由于返回类型的不确定性,不支持常规操作。

use comfy_bounded_ints::{Bound_i8, Bound_i16, Bound_u8, Bound_u32, Bound_isize};

let mut bounded_i8 = Bound_i8::<20, 50>::new(30);
let bounded_i16 = Bound_i16::< -200, 500>::new(-200);
bounded_i8 += bounded_i16;
           ^^
assert_eq!(bounded_i8.get(), 20);

let mut bounded_i8 = Bound_i8::< -128, 127>::new(-128);
let bounded_i16 = Bound_i16::< -300, 500>::new(-300);
bounded_i8 -= bounded_i16;
           ^^
assert_eq!(bounded_i8.get(), 127);

let mut bounded_u8 = Bound_u8::< 5, 80>::new(70);
let bounded_i16 = Bound_i16::< -300, 500>::new(-1);
bounded_u8 *= bounded_i16;
           ^^
assert_eq!(bounded_u8.get(), 5);

let mut bounded_u32 = Bound_u8::< 2, 650>::new(800);
let bounded_i8 = Bound_i8::< -30, 10>::new(-1);
bounded_u32 /= bounded_i8;
            ^^
assert_eq!(bounded_u32.get(), 2);

let mut bounded_u32 = Bound_u32::< 3, 650>::new(800);
let bounded_i8 = Bound_i8::< -30, 10>::new(-1);
bounded_u32 %= bounded_i8;
            ^^
assert_eq!(bounded_u32.get(), 3);

let mut bounded_isize = Bound_isize::<0, 200>::new(80);
let int_i8 = 30_i8;
bounded_isize += int_i8;
              ^^
assert_eq!(bounded_isize.get(), 110);

let mut bounded_isize = Bound_isize::<0, 200>::new(80);
let int_i32 = -900_i32;
bounded_isize += int_i32;
              ^^
assert_eq!(bounded_isize.get(), 0);

...

为所有有界类型实现了 Default 特性

它创建了一个新的有界类型,其内部值为最小值。

所有有界类型都实现了 #[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, Eq)]

所有有界类型为其相应的 NonZero 类型实现了 DivAssign/RemAssign

需要提供 div_assign_zero 功能。

use comfy_bounded_ints::{Bound_i8, Bound_u128};

let mut bounded_i8 = Bound_i8::< -30, 80>::new(-120);
let non_zero_i8 = NonZeroI8::new(-2).unwrap();
bounded_i8 *= non_zero_i8;
           ^^
assert_eq!(bounded_i8.get(), 60);

let mut bounded_u128 = Bound_u128::< 3, 650>::new(800);
let non_zero_u128 = NonZeroU128::new(2).unwrap();
bounded_u128 /= non_zero_u128;
             ^^
assert_eq!(bounded_u128.get(), 325);

所有有界类型都可以使用 From 特性从任何整数类型创建

此特性还提供了一个通配实现,允许任何整数使用 .into() 方法转换为给定的有界类型。

use comfy_bounded_ints::{Bound_i8, Bound_isize, Bound_u8, Bound_u32};

let bounded_i8 = Bound_i8::< -30, 80>::from(-120_i8);
                                       ^^^^^^^^^^^^^
assert_eq!(bounded_i8.get(), -30);

let bounded_u32 = Bound_u32::< 2, 650>::from(-800_i32);
                                        ^^^^^^^^^^^^^^
assert_eq!(bounded_u32.get(), 2);

let bounded_isize: Bound_isize<20, 100> = 50_u128.into();
                                                 ^^^^^^^
assert_eq!(bounded_isize.get(), 50);

let bounded_u8: Bound_u8<20, 100> = -50_i64.into();
                                           ^^^^^^^
assert_eq!(bounded_u8.get(), 20);

PartialEq 是在具有相同内部整型类型的有限类型之间实现的

对于这种比较,约束条件是无关紧要的。对于其他比较,您可以使用 .get() 方法或 deref * 操作符,然后使用内部值进行比较。

use comfy_bounded_ints::{Bound_i8, Bound_u16};

let a_i8 = Bound_i8::< -30, 80>::new(-120);
let b_i8 = Bound_i8::< -30, 80>::new(20);
assert!(a_i8 != b_i8);

let a_u16 = Bound_u16::< 2, 650>::new(800);
let b_u16 = Bound_u16::< 2, 650>::new(650);
assert!(a_u16 == b_u16);

依赖关系