【unitrix】 4.16 类型级别左移运算实现解析(shl.rs)

发布于:2025-07-05 ⋅ 阅读:(17) ⋅ 点赞:(0)

一、源码

这段代码实现了一个类型级别的左移运算(<<)系统,用于在编译时进行位运算。

/*类型级别的左移运算实现
 * 编制人: $ource
 * 修改版次:0版完成版
 * 本版次创建时间: 2025年6月27日
 * 最后修改时间: 2025年7月4日 添加Shl1特质,避免解释器递归调用
 * 待完善问题:无
 */
use core::ops::Shl;

use crate::number::{
    Z0, P1, N1, B0, B1, Var, FixedPoint,
    TypedInt, NonZero, Primitive, PrimitiveInt, Unsigned,
    IfB0, IfB1, Sub1,
};

// ==================== Left Shift Operation / 左移运算 (<<) ====================

// ==================== I << All ====================
// Zero left shifted by any amount is still zero / 零左移任何位数仍然是零
impl<R: Unsigned> Shl<R> for Z0 {
    type Output = Z0;
    fn shl(self, _: R) -> Self::Output {
        Z0
    }
}

// Zero left shifted by a variable amount is still zero / 零左移可变位数仍然是零
impl<T: Primitive> Shl<Var<T>> for Z0 {
    type Output = Z0;
    fn shl(self, _: Var<T>) -> Self::Output {
        Z0
    }
}

// ==================== P1 << U ====================
// Positive one left shifted by zero is itself
// 正一左移零位是其本身
impl Shl<Z0> for P1 {
    type Output = Self;
    fn shl(self, _: Z0) -> Self::Output {
        self
    }
}

// Positive one left shifted by more than one
// Recursively shifts left by one until the shift amount is zero
// (equivalent to adding zeros at the least significant side)
// 正一左移多于一位
// 递归地左移一位直到移位量为零(相当于在最低有效位侧添加零)
impl<R: Unsigned + NonZero + Sub1> Shl<R> for P1
where
    P1: Shl<<R as Sub1>::Output>,
{
    type Output = B0<<P1 as Shl<<R as Sub1>::Output>>::Output>;
    fn shl(self, _r: R) -> Self::Output {
        B0::new()
    }
}

// Positive one left shifted by a variable amount
// 正一左移可变位数
impl<T: PrimitiveInt> Shl<Var<T>> for P1
where 
    Var<T>: From<P1> + Shl<Output=Var<T>>,
{
    type Output = Var<T>;
    fn shl(self, rhs: Var<T>) -> Self::Output {
        Var::<T>::from(self) << rhs
    }
}

// ==================== N1 << U ====================
// Negative one left shifted by zero is itself
// 负一左移零位是其本身
impl Shl<Z0> for N1 {
    type Output = Self;
    fn shl(self, _: Z0) -> Self::Output {
        self
    }
}

// Negative one left shifted by more than one
// Recursively shifts left by one until the shift amount is zero
// (maintains sign in two's complement arithmetic)
// 负一左移多于一位
// 递归地左移一位直到移位量为零(在二进制补码算术中保持符号)
impl<R: Unsigned + NonZero + Sub1> Shl<R> for N1
where
    N1: Shl<<R as Sub1>::Output>,
{
    type Output = B0<<N1 as Shl<<R as Sub1>::Output>>::Output>;
    fn shl(self, _r: R) -> Self::Output {
        B0::new()
    }
}

// Negative one left shifted by a variable amount
// 负一左移可变位数
impl<T: PrimitiveInt> Shl<Var<T>> for N1
where 
    Var<T>: From<N1> + Shl<Output=Var<T>>
{
    type Output = Var<T>;
    fn shl(self, rhs: Var<T>) -> Self::Output {
        Var::<T>::from(self) << rhs
    }
}

// ==================== B0 << U ====================
// Binary number ending with 0 left shifted by zero is itself
// 以0结尾的二进制数左移零位是其本身
impl<H: NonZero> Shl<Z0> for B0<H> {
    type Output = Self;
    fn shl(self, _: Z0) -> Self::Output {
        self
    }
}

// Binary number ending with 0 left shifted by more than one
// Recursively shifts left by one until the shift amount is zero
// 以0结尾的二进制数左移多于一位
// 递归地左移一位直到移位量为零
impl<H: NonZero, R: Unsigned + NonZero + Sub1> Shl<R> for B0<H>
where 
    B0<H>: Shl<<R as Sub1>::Output>,
{
    type Output = B0<<B0<H> as Shl<<R as Sub1>::Output>>::Output>;
    fn shl(self, _r: R) -> Self::Output {
        B0::new()
    }
}

// Binary number ending with 0 left shifted by a variable amount
// 以0结尾的二进制数左移可变位数
impl<H: NonZero, T: PrimitiveInt> Shl<Var<T>> for B0<H>
where 
    Var<T>: From<B0<H>> + Shl<Output=Var<T>>
{
    type Output = Var<T>;
    fn shl(self, rhs: Var<T>) -> Self::Output {
        Var::<T>::from(self) << rhs
    }
}

// ==================== B1 << U ====================
// Binary number ending with 1 left shifted by zero is itself
// 以1结尾的二进制数左移零位是其本身
impl<H: NonZero> Shl<Z0> for B1<H> {
    type Output = Self;
    fn shl(self, _: Z0) -> Self::Output {
        self
    }
}

// Binary number ending with 1 left shifted by more than one
// Recursively shifts left by one until the shift amount is zero
// 以1结尾的二进制数左移多于一位
// 递归地左移一位直到移位量为零
impl<H: NonZero, R: Unsigned + NonZero + Sub1> Shl<R> for B1<H>
where 
    B1<H>: Shl<<R as Sub1>::Output>,
{
    type Output = B0<<B1<H> as Shl<<R as Sub1>::Output>>::Output>;
    fn shl(self, _r: R) -> Self::Output {
        B0::new()
    }
}

// Binary number ending with 1 left shifted by a variable amount
// 以1结尾的二进制数左移可变位数
impl<H: NonZero, T: PrimitiveInt> Shl<Var<T>> for B1<H>
where 
    Var<T>: From<B1<H>> + Shl<Output=Var<T>>
{
    type Output = Var<T>;
    fn shl(self, rhs: Var<T>) -> Self::Output {
        Var::<T>::from(self) << rhs
    }
}

// ==================== FixedPoint<IntPart, FracPart> << All ====================
// ==================== 定点数左移实现 ====================

// Fixed-point number left shifted by zero - no change
// 定点数左移零位 - 无变化
impl<IntPart: TypedInt, FracPart: Unsigned> Shl<Z0> for FixedPoint<IntPart, FracPart> {
    type Output = Self;
    fn shl(self, _: Z0) -> Self::Output {
        self
    }
}

// Fixed-point with zero fractional part left shift
// Shifting affects only the integer part
// 小数部分为零的定点数左移
// 移位仅影响整数部分
impl<IntPart: TypedInt + Shl<R>, R: Unsigned + NonZero> Shl<R> for FixedPoint<IntPart, Z0>
{
    type Output = FixedPoint<
        <IntPart as Shl<R>>::Output,
        Z0
    >;
    
    fn shl(self, _r: R) -> Self::Output {
        FixedPoint::new()
    }
}

// Fixed-point with one fractional part left shift
// Shifting affects only the integer part
// 小数部分为P1的定点数左移
impl<IntPart: IfB1, R: Unsigned + NonZero + Sub1> Shl<R> for FixedPoint<IntPart, P1>
where
    <IntPart as IfB1>::Output: Shl<<R as Sub1>::Output>,  // 递归条件
{
    type Output = FixedPoint<
        <<IntPart as IfB1>::Output as Shl<<R as Sub1>::Output> >::Output,
        Z0
    >;
    
    fn shl(self, _r: R) -> Self::Output {
        FixedPoint::new()
    }
}

// Fixed-point with fractional part ending with 0 left shift
// Shifting moves bit from fractional to integer part
// 小数部分以0结尾的定点数左移
// 移位将位从小数部分移动到整数部分
impl<IntPart: TypedInt + IfB0, L: NonZero, R: Unsigned + NonZero + Sub1> Shl<R> for FixedPoint<IntPart, B0<L>>
where 
    FixedPoint< <IntPart as IfB0>::Output,L >: Shl<<R as Sub1>::Output, Output: Default>,
{
    type Output = <  FixedPoint< <IntPart as IfB0>::Output,L > as Shl<<R as Sub1>::Output>  >::Output;
    
    fn shl(self, _: R) -> Self::Output {
        Default::default()
    }
}

// Fixed-point with fractional part ending with 1 left shift
// Shifting moves bit from fractional to integer part
// 小数部分以1结尾的定点数左移
// 移位将位从小数部分移动到整数部分
impl<IntPart: IfB1, L: NonZero, R: Unsigned + NonZero + Sub1> Shl<R> for FixedPoint<IntPart, B1<L>>
where 
    FixedPoint< <IntPart as IfB1>::Output,L >: Shl<<R as Sub1>::Output, Output: Default>,
{
    type Output = <  FixedPoint< <IntPart as IfB1>::Output,L > as Shl<<R as Sub1>::Output>  >::Output;
    
    fn shl(self, _: R) -> Self::Output {
        Default::default()
    }
}

/* // Fixed-point left shifted by a variable amount
// 定点数左移可变位数(无意义,取消)
impl<IntPart, FracPart, T> Shl<Var<T>> for FixedPoint<IntPart, FracPart>
where
    T: PrimitiveInt,
    IntPart: Into<T>,
    FracPart: Into<T>,
    Self: Into<T>,
{
    type Output = Var<T>;
    
    fn shl(self, rhs: Var<T>) -> Self::Output {
        Var(self.into() << rhs.0)
    }
} */


// ==================== Var << All ====================
impl<T: PrimitiveInt, R: Unsigned> Shl<R> for Var<T>
where
    Var<T>: From<R> + Shl<Output=Var<T>>,
{
    type Output = Var<T>;
    
    fn shl(self, rhs: R) -> Self::Output {
        self << Var::<T>::from(rhs)
    }
}

impl<T: PrimitiveInt + Shl<Output=T>> Shl<Var<T>> for Var<T>{
    type Output = Var<T>;
    
    fn shl(self, rhs: Var<T>) -> Self::Output {
        Var(self.0 << rhs.0)
    }
}

#[cfg(test)]
mod tests {
    use crate::number::*;

    // ==================== Z0 左移所有情况 ====================
    #[test]
    fn test_z0_left_shift() {
        assert_eq!(Z0 << Z0, Z0);  // 零左移零位还是零
        assert_eq!(Z0 << P1, Z0);  // 零左移一位还是零
        assert_eq!(Z0 << B0::<P1>::new(), Z0);  // 零左移两位还是零
        assert_eq!(Z0 << Var::<i32>::from(5), Z0);  // 零左移变量位数还是零
    }

    // ==================== P1 左移无符号数 ====================
    #[test]
    fn test_p1_left_shift() {
        assert_eq!(P1 << Z0, P1);  // 正一左移零位不变
        assert_eq!(P1 << P1, B0::<P1>::new());  // 正一左移一位变为10(二进制)
        assert_eq!(P1 << B0::<P1>::new(), B0::<B0<P1>>::new());  // 正一左移两位变为100(二进制)
        assert_eq!(P1 << Var::<i32>::from(3), Var::<i32>(8));  // 正一左移三位等于8
    }

    // ==================== N1 左移无符号数 ====================
    #[test]
    fn test_n1_left_shift() {
        assert_eq!(N1 << Z0, N1);  // 负一左移零位不变
        assert_eq!(N1 << P1, B0::<N1>::new());  // 负一左移一位
        assert_eq!(N1 << B0::<P1>::new(), B0::<B0::<N1>>::new());  // 负一左移两位
        assert_eq!(N1 << Var::<i32>::from(2), Var::<i32>(-4));  // 负一左移两位等于-4
    }

    // ==================== B0 左移无符号数 ====================
    #[test]
    fn test_b0_left_shift() {
        let b01 = B0::<P1>::new();  // 二进制01(即十进制的1)
        let _b001 = B0::<B0::<P1>>::new();  // 二进制001
        
        assert_eq!(b01 << Z0, b01);  // 01左移零位不变
        assert_eq!(b01 << P1, B0::<B0::<P1>>::new());  // 01左移一位变为010
        assert_eq!(b01 << B0::<P1>::new(), B0::<B0::<B0::<P1>>>::new());  // 01左移两位变为0100
        assert_eq!(b01 << Var::<i32>::from(2), Var::<i32>(8));  // 01左移两位等于4
    }

    // ==================== B1 左移无符号数 ====================
    #[test]
    fn test_b1_left_shift() {
        let b11 = B1::<P1>::new();  // 二进制11(即十进制的3)
        let _b011 = B0::<B1::<P1>>::new();  // 二进制011
        
        assert_eq!(b11 << Z0, b11);  // 11左移零位不变
        assert_eq!(b11 << P1, B0::<B1::<P1>>::new());  // 11左移一位变为110
        assert_eq!(b11 << B0::<P1>::new(), B0::<B0::<B1::<P1>>>::new());  // 11左移两位变为1100
        assert_eq!(b11 << Var::<i32>::from(3), Var::<i32>(24));
    }

    // ==================== 定点数左移 ====================
    #[test]
    fn test_fixed_point_left_shift() {
        // 小数部分为零的定点数
        let fp1 = FixedPoint::<B0<P1>, Z0>::new();
        assert_eq!(fp1 << Z0, fp1);  // 左移零位不变
        assert_eq!(fp1 << P1, FixedPoint::<B0<B0<P1>>, Z0>::new());
        
        // 小数部分为1的定点数
        let fp2 = FixedPoint::<P1, P1>::new();
        assert_eq!(fp2 << P1, FixedPoint::<B1<P1>, Z0>::new());
        
        // 小数部分以0结尾的定点数
        let fp3 = FixedPoint::<P1, B0::<P1>>::new();
        assert_eq!(fp3 << P1, FixedPoint::<B0<P1>, P1>::new());
        
        // 小数部分以1结尾的定点数
        let fp4 = FixedPoint::<P1, B1::<P1>>::new();
        assert_eq!(fp4 << P1, FixedPoint::<B1<P1>, P1>::new());
    }

    // ==================== 变量左移 ====================
    #[test]
    fn test_var_left_shift() {
        let var1 = Var::<i32>(5);
        assert_eq!(var1 << Z0, Var::<i32>(5));  // 左移零位不变
        assert_eq!(var1 << P1, Var::<i32>(10));  // 左移一位变为10
        assert_eq!(var1 << B0::<P1>::new(), Var::<i32>(20));  // 左移两位变为20
        assert_eq!(var1 << Var::<i32>(3), Var::<i32>(40));  // 左移三位变为40
    }

    // 测试边界情况和组合情况
    #[test]
    fn test_edge_cases() {
        // 大位移量测试
        assert_eq!(P1 << B1::<P1>::new(), B0::<B0::<B0::<P1>>>::new());  // 1左移3位变为1000(8)
        assert_eq!(N1 << B1::<P1>::new(), B0::<B0::<B0::<N1>>>::new());  // -1左移3位
        
        // 二进制数位移测试
        let b101 = B1::<B0::<P1>>::new();  // 101(5)
        assert_eq!(b101 << P1, B0::<B1::<B0::<P1>>>::new());  // 左移一位变为1010(10)
        
        // 复杂小数部分的定点数位移
        let fp = FixedPoint::<P1, B1::<B0<P1>>>::new();  // 1.101
        assert_eq!(fp << P1, FixedPoint::<B1<P1>, B0<P1>>::new());  // 左移一位
    }
}

// ==================== 移一位独立实现 ====================
pub trait Shl1 {
    type Output: Default;
    fn shl1(self) -> Self::Output;
}

// Zero left shifted by one is still zero
impl Shl1 for Z0 {
    type Output = Z0;
    fn shl1(self) -> Self::Output {
        Z0
    }
}

// Positive one left shifted by one
impl Shl1 for P1 {
    type Output = B0<P1>;
    fn shl1(self) -> Self::Output {
        Default::default()
    }
}

// Negative one left shifted by one
impl Shl1 for N1 {
    type Output = B0<N1>;
    fn shl1(self) -> Self::Output {
        Default::default()
    }
}

// Binary number ending with 0 left shifted by one
impl<H: NonZero> Shl1 for B0<H> {
    type Output = B0<B0<H>>;
    fn shl1(self) -> Self::Output {
        Default::default()
    }
}

// Binary number ending with 1 left shifted by one
impl<H: NonZero> Shl1 for B1<H> {
    type Output = B0<B1<H>>;
    fn shl1(self) -> Self::Output {
        Default::default()
    }
}

// Fixed-point number implementations with methods
impl<IntPart: TypedInt + Shl1> Shl1 for FixedPoint<IntPart, Z0> {
    type Output = FixedPoint<<IntPart as Shl1>::Output, Z0>;
    fn shl1(self) -> Self::Output {
        FixedPoint::new()
    }
}

impl<IntPart: IfB1> Shl1 for FixedPoint<IntPart, P1> {
    type Output = FixedPoint<<IntPart as IfB1>::Output, Z0>;
    fn shl1(self) -> Self::Output {
        FixedPoint::new()
    }
}

impl<IntPart: TypedInt + IfB0, L: NonZero> Shl1 for FixedPoint<IntPart, B0<L>> {
    type Output = FixedPoint<<IntPart as IfB0>::Output, L>;
    fn shl1(self) -> Self::Output {
        FixedPoint::new()
    }
}

impl<IntPart: IfB1, L: NonZero> Shl1 for FixedPoint<IntPart, B1<L>> {
    type Output = FixedPoint<<IntPart as IfB1>::Output, L>;
    fn shl1(self) -> Self::Output {
        FixedPoint::new()
    }
}

二、代码结构概述

  1. 基础类型定义:使用了多种类型来表示数字,包括Z0(零)、P1(正一)、N1(负一)、B0/B1(二进制位)等

  2. 左移运算实现:为不同类型实现了Shl trait,表示左移操作

  3. 定点数支持:实现了定点数的左移运算

  4. 变量移位支持:支持运行时变量的移位操作

  5. 独立Shl1 trait:单独实现了一位左移操作

三、主要组件解析

  1. 零的左移(Z0)

impl<R: Unsigned> Shl<R> for Z0 {
    type Output = Z0;
    fn shl(self, _: R) -> Self::Output { Z0 }
}
  • 零左移任何位数仍然是零

  • 适用于编译时已知的任意无符号移位量

  1. 正一(P1)和负一(N1)的左移

impl Shl<Z0> for P1 {
    type Output = Self;
    fn shl(self, _: Z0) -> Self::Output { self }
}

impl<R: Unsigned + NonZero + Sub1> Shl<R> for P1
where
    P1: Shl<<R as Sub1>::Output>,
{
    type Output = B0<<P1 as Shl<<R as Sub1>::Output>>::Output>;
    fn shl(self, _r: R) -> Self::Output { B0::new() }
}
  • 左移零位返回自身

  • 左移N位递归实现:每次左移一位,直到移位量为零

  • 负一的实现类似,保持二进制补码特性

  1. 二进制数的左移(B0/B1)

impl<H: NonZero, R: Unsigned + NonZero + Sub1> Shl<R> for B0<H>
where 
    B0<H>: Shl<<R as Sub1>::Output>,
{
    type Output = B0<<B0<H> as Shl<<R as Sub1>::Output>>::Output>;
    fn shl(self, _r: R) -> Self::Output { B0::new() }
}
  • 处理以0或1结尾的二进制数

  • 递归左移,每次在最右侧添加0

  1. 定点数的左移

impl<IntPart: TypedInt + Shl<R>, R: Unsigned + NonZero> Shl<R> for FixedPoint<IntPart, Z0>
{
    type Output = FixedPoint<<IntPart as Shl<R>>::Output, Z0>;
    fn shl(self, _r: R) -> Self::Output { FixedPoint::new() }
}
  • 处理整数部分和小数部分的移位

  • 根据小数部分的类型(B0/B1/P1)有不同的实现

  • 移位会将小数部分的位移动到整数部分

  1. 变量移位

impl<T: PrimitiveInt, R: Unsigned> Shl<R> for Var<T>
where
    Var<T>: From<R> + Shl<Output=Var<T>>,
{
    type Output = Var<T>;
    fn shl(self, rhs: R) -> Self::Output { self << Var::<T>::from(rhs) }
}
  • 支持运行时变量的移位操作

  • 将编译时常量转换为运行时变量进行移位

  1. 独立Shl1实现

pub trait Shl1 {
    type Output: Default;
    fn shl1(self) -> Self::Output;
}
  • 单独实现一位左移操作

  • 简化了单一位移位的实现

四、测试用例解析

测试覆盖了各种场景:

  1. 零的移位

  2. 正负一的移位

  3. 二进制数的移位

  4. 定点数的移位

  5. 变量移位

  6. 边界情况测试

五、设计特点

  1. 类型安全:所有操作在编译时进行类型检查

  2. 零成本抽象:运行时不会有额外开销

  3. 递归实现:通过类型系统实现递归移位

  4. 灵活性:支持编译时和运行时移位

  5. 扩展性:易于添加新的数字类型和操作

这个实现展示了Rust类型系统的强大能力,能够在编译时完成复杂的算术运算,同时保持代码的安全性和性能。