一、源码
int_traits.rs文件定义了两个核心 trait MinInt 和 Int,为整数类型提供统一的抽象接口,并通过宏为所有原生整数类型(i8 ~ i128/u8 ~ u128)实现这些 trait。
use core::{cmp, fmt, ops};
/// Minimal integer implementations needed on all integer types, including wide integers.
pub trait MinInt:
Copy
+ fmt::Debug
+ ops::BitOr<Output = Self>
+ ops::Not<Output = Self>
+ ops::Shl<u32, Output = Self>
{
/// Type with the same width but other signedness
type OtherSign: MinInt;
/// Unsigned version of Self
type Unsigned: MinInt;
/// If `Self` is a signed integer
const SIGNED: bool;
/// The bitwidth of the int type
const BITS: u32;
const ZERO: Self;
const ONE: Self;
const MIN: Self;
const MAX: Self;
}
/// Access the associated `OtherSign` type from an int (helper to avoid ambiguous associated
/// types).
pub type OtherSign<I> = <I as MinInt>::OtherSign;
/// Trait for some basic operations on integers
#[allow(dead_code)]
pub trait Int:
MinInt
+ fmt::Display
+ fmt::Binary
+ fmt::LowerHex
+ PartialEq
+ PartialOrd
+ ops::AddAssign
+ ops::SubAssign
+ ops::BitAndAssign
+ ops::BitOrAssign
+ ops::BitXorAssign
+ ops::ShlAssign<i32>
+ ops::ShlAssign<u32>
+ ops::ShrAssign<u32>
+ ops::ShrAssign<i32>
+ ops::Add<Output = Self>
+ ops::Sub<Output = Self>
+ ops::Mul<Output = Self>
+ ops::Div<Output = Self>
+ ops::Shl<i32, Output = Self>
+ ops::Shl<u32, Output = Self>
+ ops::Shr<i32, Output = Self>
+ ops::Shr<u32, Output = Self>
+ ops::BitXor<Output = Self>
+ ops::BitAnd<Output = Self>
+ cmp::Ord
+ From<bool>
+ CastFrom<i32>
+ CastFrom<u16>
+ CastFrom<u32>
+ CastFrom<u8>
+ CastFrom<usize>
+ CastInto<i32>
+ CastInto<u16>
+ CastInto<u32>
+ CastInto<u8>
+ CastInto<usize>
{
fn signed(self) -> OtherSign<Self::Unsigned>;
fn unsigned(self) -> Self::Unsigned;
fn from_unsigned(unsigned: Self::Unsigned) -> Self;
fn abs(self) -> Self;
fn from_bool(b: bool) -> Self;
/// Prevents the need for excessive conversions between signed and unsigned
fn logical_shr(self, other: u32) -> Self;
/// Absolute difference between two integers.
fn abs_diff(self, other: Self) -> Self::Unsigned;
// copied from primitive integers, but put in a trait
fn is_zero(self) -> bool;
fn checked_add(self, other: Self) -> Option<Self>;
fn checked_sub(self, other: Self) -> Option<Self>;
fn wrapping_neg(self) -> Self;
fn wrapping_add(self, other: Self) -> Self;
fn wrapping_mul(self, other: Self) -> Self;
fn wrapping_sub(self, other: Self) -> Self;
fn wrapping_shl(self, other: u32) -> Self;
fn wrapping_shr(self, other: u32) -> Self;
fn rotate_left(self, other: u32) -> Self;
fn overflowing_add(self, other: Self) -> (Self, bool);
fn overflowing_sub(self, other: Self) -> (Self, bool);
fn leading_zeros(self) -> u32;
fn ilog2(self) -> u32;
}
macro_rules! int_impl_common {
($ty:ty) => {
fn from_bool(b: bool) -> Self {
b as $ty
}
fn logical_shr(self, other: u32) -> Self {
Self::from_unsigned(self.unsigned().wrapping_shr(other))
}
fn is_zero(self) -> bool {
self == Self::ZERO
}
fn checked_add(self, other: Self) -> Option<Self> {
self.checked_add(other)
}
fn checked_sub(self, other: Self) -> Option<Self> {
self.checked_sub(other)
}
fn wrapping_neg(self) -> Self {
<Self>::wrapping_neg(self)
}
fn wrapping_add(self, other: Self) -> Self {
<Self>::wrapping_add(self, other)
}
fn wrapping_mul(self, other: Self) -> Self {
<Self>::wrapping_mul(self, other)
}
fn wrapping_sub(self, other: Self) -> Self {
<Self>::wrapping_sub(self, other)
}
fn wrapping_shl(self, other: u32) -> Self {
<Self>::wrapping_shl(self, other)
}
fn wrapping_shr(self, other: u32) -> Self {
<Self>::wrapping_shr(self, other)
}
fn rotate_left(self, other: u32) -> Self {
<Self>::rotate_left(self, other)
}
fn overflowing_add(self, other: Self) -> (Self, bool) {
<Self>::overflowing_add(self, other)
}
fn overflowing_sub(self, other: Self) -> (Self, bool) {
<Self>::overflowing_sub(self, other)
}
fn leading_zeros(self) -> u32 {
<Self>::leading_zeros(self)
}
fn ilog2(self) -> u32 {
// On our older MSRV, this resolves to the trait method. Which won't actually work,
// but this is only called behind other gates.
#[allow(clippy::incompatible_msrv)]
<Self>::ilog2(self)
}
};
}
macro_rules! int_impl {
($ity:ty, $uty:ty) => {
impl MinInt for $uty {
type OtherSign = $ity;
type Unsigned = $uty;
const BITS: u32 = <Self as MinInt>::ZERO.count_zeros();
const SIGNED: bool = Self::MIN != Self::ZERO;
const ZERO: Self = 0;
const ONE: Self = 1;
const MIN: Self = <Self>::MIN;
const MAX: Self = <Self>::MAX;
}
impl Int for $uty {
fn signed(self) -> $ity {
self as $ity
}
fn unsigned(self) -> Self {
self
}
fn abs(self) -> Self {
unimplemented!()
}
// It makes writing macros easier if this is implemented for both signed and unsigned
#[allow(clippy::wrong_self_convention)]
fn from_unsigned(me: $uty) -> Self {
me
}
fn abs_diff(self, other: Self) -> Self {
self.abs_diff(other)
}
int_impl_common!($uty);
}
impl MinInt for $ity {
type OtherSign = $uty;
type Unsigned = $uty;
const BITS: u32 = <Self as MinInt>::ZERO.count_zeros();
const SIGNED: bool = Self::MIN != Self::ZERO;
const ZERO: Self = 0;
const ONE: Self = 1;
const MIN: Self = <Self>::MIN;
const MAX: Self = <Self>::MAX;
}
impl Int for $ity {
fn signed(self) -> Self {
self
}
fn unsigned(self) -> $uty {
self as $uty
}
fn abs(self) -> Self {
self.abs()
}
fn from_unsigned(me: $uty) -> Self {
me as $ity
}
fn abs_diff(self, other: Self) -> $uty {
self.abs_diff(other)
}
int_impl_common!($ity);
}
};
}
int_impl!(isize, usize);
int_impl!(i8, u8);
int_impl!(i16, u16);
int_impl!(i32, u32);
int_impl!(i64, u64);
int_impl!(i128, u128);
/// Trait for integers twice the bit width of another integer. This is implemented for all
/// primitives except for `u8`, because there is not a smaller primitive.
pub trait DInt: MinInt {
/// Integer that is half the bit width of the integer this trait is implemented for
type H: HInt<D = Self>;
/// Returns the low half of `self`
fn lo(self) -> Self::H;
/// Returns the high half of `self`
fn hi(self) -> Self::H;
/// Returns the low and high halves of `self` as a tuple
fn lo_hi(self) -> (Self::H, Self::H) {
(self.lo(), self.hi())
}
/// Constructs an integer using lower and higher half parts
#[allow(unused)]
fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self {
lo.zero_widen() | hi.widen_hi()
}
}
/// Trait for integers half the bit width of another integer. This is implemented for all
/// primitives except for `u128`, because it there is not a larger primitive.
pub trait HInt: Int {
/// Integer that is double the bit width of the integer this trait is implemented for
type D: DInt<H = Self> + MinInt;
// NB: some of the below methods could have default implementations (e.g. `widen_hi`), but for
// unknown reasons this can cause infinite recursion when optimizations are disabled. See
// <https://github.com/rust-lang/compiler-builtins/pull/707> for context.
/// Widens (using default extension) the integer to have double bit width
fn widen(self) -> Self::D;
/// Widens (zero extension only) the integer to have double bit width. This is needed to get
/// around problems with associated type bounds (such as `Int<Othersign: DInt>`) being unstable
fn zero_widen(self) -> Self::D;
/// Widens the integer to have double bit width and shifts the integer into the higher bits
#[allow(unused)]
fn widen_hi(self) -> Self::D;
/// Widening multiplication with zero widening. This cannot overflow.
fn zero_widen_mul(self, rhs: Self) -> Self::D;
/// Widening multiplication. This cannot overflow.
fn widen_mul(self, rhs: Self) -> Self::D;
}
macro_rules! impl_d_int {
($($X:ident $D:ident),*) => {
$(
impl DInt for $D {
type H = $X;
fn lo(self) -> Self::H {
self as $X
}
fn hi(self) -> Self::H {
(self >> <$X as MinInt>::BITS) as $X
}
}
)*
};
}
macro_rules! impl_h_int {
($($H:ident $uH:ident $X:ident),*) => {
$(
impl HInt for $H {
type D = $X;
fn widen(self) -> Self::D {
self as $X
}
fn zero_widen(self) -> Self::D {
(self as $uH) as $X
}
fn zero_widen_mul(self, rhs: Self) -> Self::D {
self.zero_widen().wrapping_mul(rhs.zero_widen())
}
fn widen_mul(self, rhs: Self) -> Self::D {
self.widen().wrapping_mul(rhs.widen())
}
fn widen_hi(self) -> Self::D {
(self as $X) << <Self as MinInt>::BITS
}
}
)*
};
}
impl_d_int!(u8 u16, u16 u32, u32 u64, u64 u128, i8 i16, i16 i32, i32 i64, i64 i128);
impl_h_int!(
u8 u8 u16,
u16 u16 u32,
u32 u32 u64,
u64 u64 u128,
i8 u8 i16,
i16 u16 i32,
i32 u32 i64,
i64 u64 i128
);
/// Trait to express (possibly lossy) casting of integers
pub trait CastInto<T: Copy>: Copy {
/// By default, casts should be exact.
fn cast(self) -> T;
/// Call for casts that are expected to truncate.
fn cast_lossy(self) -> T;
}
pub trait CastFrom<T: Copy>: Copy {
/// By default, casts should be exact.
fn cast_from(value: T) -> Self;
/// Call for casts that are expected to truncate.
fn cast_from_lossy(value: T) -> Self;
}
impl<T: Copy, U: CastInto<T> + Copy> CastFrom<U> for T {
fn cast_from(value: U) -> Self {
value.cast()
}
fn cast_from_lossy(value: U) -> Self {
value.cast_lossy()
}
}
macro_rules! cast_into {
($ty:ty) => {
cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128);
};
($ty:ty; $($into:ty),*) => {$(
impl CastInto<$into> for $ty {
fn cast(self) -> $into {
// All we can really do to enforce casting rules is check the rules when in
// debug mode.
#[cfg(not(feature = "compiler-builtins"))]
debug_assert!(<$into>::try_from(self).is_ok(), "failed cast from {self}");
self as $into
}
fn cast_lossy(self) -> $into {
self as $into
}
}
)*};
}
macro_rules! cast_into_float {
($ty:ty) => {
#[cfg(f16_enabled)]
cast_into_float!($ty; f16);
cast_into_float!($ty; f32, f64);
#[cfg(f128_enabled)]
cast_into_float!($ty; f128);
};
($ty:ty; $($into:ty),*) => {$(
impl CastInto<$into> for $ty {
fn cast(self) -> $into {
#[cfg(not(feature = "compiler-builtins"))]
debug_assert_eq!(self as $into as $ty, self, "inexact float cast");
self as $into
}
fn cast_lossy(self) -> $into {
self as $into
}
}
)*};
}
cast_into!(usize);
cast_into!(isize);
cast_into!(u8);
cast_into!(i8);
cast_into!(u16);
cast_into!(i16);
cast_into!(u32);
cast_into!(i32);
cast_into!(u64);
cast_into!(i64);
cast_into!(u128);
cast_into!(i128);
cast_into_float!(i8);
cast_into_float!(i16);
cast_into_float!(i32);
cast_into_float!(i64);
cast_into_float!(i128);
- 核心 Trait:MinInt
定义整数类型的最小通用操作集合:
pub trait MinInt: Copy + Debug + BitOr + Not + Shl<u32> {
type OtherSign: MinInt; // 同宽度的相反符号类型(如 `i32` 的 `OtherSign` 是 `u32`)
type Unsigned: MinInt; // 无符号版本
const SIGNED: bool; // 是否为有符号整数
const BITS: u32; // 位数(如 `i32` 是 32)
const ZERO: Self; // 0 值
const ONE: Self; // 1 值
const MIN: Self; // 最小值
const MAX: Self; // 最大值
}
- 扩展 Trait:Int
在 MinInt 基础上扩展更多操作:
pub trait Int: MinInt + Display + Binary + AddAssign + ... {
fn signed(self) -> OtherSign<Self::Unsigned>; // 转为有符号类型
fn unsigned(self) -> Self::Unsigned; // 转为无符号类型
fn abs(self) -> Self; // 绝对值
// 位操作
fn logical_shr(self, other: u32) -> Self; // 逻辑右移(高位补 0)
fn rotate_left(self, other: u32) -> Self; // 循环左移
// 溢出安全运算
fn wrapping_add(self, other: Self) -> Self;
fn checked_mul(self, other: Self) -> Option<Self>;
// 工具方法
fn leading_zeros(self) -> u32;
fn ilog2(self) -> u32;
}
- 宏实现
通过宏 int_impl! 为所有原生整数类型实现 MinInt 和 Int:
int_impl!(i32, u32); // 为 i32/u32 生成实现
宏展开后:
-
为 u32 实现 MinInt,关联 OtherSign = i32。
-
为 i32 实现 MinInt,关联 OtherSign = u32。
-
实现所有 Int 方法(委托给原生整数的方法,如 u32::wrapping_add)。
- 宽/窄整数 Trait
DInt(双宽度整数)
pub trait DInt: MinInt {
type H: HInt<D = Self>; // 半宽度类型(如 `u64` 的 `H` 是 `u32`)
fn lo(self) -> Self::H; // 取低半部分
fn hi(self) -> Self::H; // 取高半部分
fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self; // 合并高低部分
}
HInt(半宽度整数)
pub trait HInt: Int {
type D: DInt<H = Self>; // 双宽度类型(如 `u32` 的 `D` 是 `u64`)
fn widen(self) -> Self::D; // 符号扩展
fn zero_widen(self) -> Self::D; // 零扩展
fn widen_mul(self, rhs: Self) -> Self::D; // 扩展乘法
}
宏实现
impl_d_int!(u32 u64); // 为 u64 实现 DInt,关联 H = u32
impl_h_int!(u32 u32 u64); // 为 u32 实现 HInt,关联 D = u64
- 类型转换 Trait
CastInto/CastFrom
提供安全的类型转换接口:
pub trait CastInto<T: Copy>: Copy {
fn cast(self) -> T; // 精确转换(失败时 debug 断言)
fn cast_lossy(self) -> T; // 允许截断
}
// 为所有整数实现 CastInto
cast_into!(u32; u8, u16, u64); // u32 可转换为 u8/u16/u64
二、设计亮点
-
统一抽象:通过 trait 为所有整数类型提供一致接口。
-
零成本:宏展开后直接调用原生整数操作,无运行时开销。
-
类型安全:
-
严格区分有/无符号类型(通过 OtherSign)。
-
转换方法提供编译时检查。
- 扩展性:支持自定义整数类型实现这些 trait。
###三、使用示例
let x: u32 = 42;
let y: i32 = x.signed(); // 转为有符号
let z: u64 = x.zero_widen(); // 零扩展为 u64
let (lo, hi) = 0x12345678u32.lo_hi(); // 拆分为低 16 位和高 16 位
三、总结
这段代码是数学库的基础设施,通过 trait 和宏实现了:
-
整数类型的通用操作抽象。
-
安全且高效的类型转换。
-
宽/窄整数的互操作。
为上层算法(如浮点数解析、大数运算)提供了类型安全的底层支持。