一、源码
这段代码实现了一个类型级别的左移运算(<<)系统,用于在编译时进行位运算。
/*类型级别的左移运算实现
* 编制人: $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()
}
}
二、代码结构概述
基础类型定义:使用了多种类型来表示数字,包括Z0(零)、P1(正一)、N1(负一)、B0/B1(二进制位)等
左移运算实现:为不同类型实现了Shl trait,表示左移操作
定点数支持:实现了定点数的左移运算
变量移位支持:支持运行时变量的移位操作
独立Shl1 trait:单独实现了一位左移操作
三、主要组件解析
- 零的左移(Z0)
impl<R: Unsigned> Shl<R> for Z0 {
type Output = Z0;
fn shl(self, _: R) -> Self::Output { Z0 }
}
零左移任何位数仍然是零
适用于编译时已知的任意无符号移位量
- 正一(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位递归实现:每次左移一位,直到移位量为零
负一的实现类似,保持二进制补码特性
- 二进制数的左移(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
- 定点数的左移
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)有不同的实现
移位会将小数部分的位移动到整数部分
- 变量移位
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) }
}
支持运行时变量的移位操作
将编译时常量转换为运行时变量进行移位
- 独立Shl1实现
pub trait Shl1 {
type Output: Default;
fn shl1(self) -> Self::Output;
}
单独实现一位左移操作
简化了单一位移位的实现
四、测试用例解析
测试覆盖了各种场景:
零的移位
正负一的移位
二进制数的移位
定点数的移位
变量移位
边界情况测试
五、设计特点
类型安全:所有操作在编译时进行类型检查
零成本抽象:运行时不会有额外开销
递归实现:通过类型系统实现递归移位
灵活性:支持编译时和运行时移位
扩展性:易于添加新的数字类型和操作
这个实现展示了Rust类型系统的强大能力,能够在编译时完成复杂的算术运算,同时保持代码的安全性和性能。