【libm】2整数接口(int_traits.rs)

一、源码

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);
  1. 核心 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;         // 最大值
}
  1. 扩展 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;
}
  1. 宏实现
    通过宏 int_impl! 为所有原生整数类型实现 MinInt 和 Int:
int_impl!(i32, u32);  // 为 i32/u32 生成实现

宏展开后:

  • 为 u32 实现 MinInt,关联 OtherSign = i32。

  • 为 i32 实现 MinInt,关联 OtherSign = u32。

  • 实现所有 Int 方法(委托给原生整数的方法,如 u32::wrapping_add)。

  1. 宽/窄整数 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
  1. 类型转换 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

二、设计亮点

  1. 统一抽象:通过 trait 为所有整数类型提供一致接口。

  2. 零成本:宏展开后直接调用原生整数操作,无运行时开销。

  3. 类型安全:

  • 严格区分有/无符号类型(通过 OtherSign)。

  • 转换方法提供编译时检查。

  1. 扩展性:支持自定义整数类型实现这些 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 和宏实现了:

  • 整数类型的通用操作抽象。

  • 安全且高效的类型转换。

  • 宽/窄整数的互操作。
    为上层算法(如浮点数解析、大数运算)提供了类型安全的底层支持。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liuyuan77

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值