一、源码
代码定义了一系列用于类型级别编程的标记特质(marker traits)。typenum 是一个在类型级别上表示和操作数字的库,常用于编译时计算和类型约束。
//! All of the **marker traits** used in typenum.
//!
//! Note that the definition here for marker traits is slightly different than
//! the conventional one -- we include traits with functions that convert a type
//! to the corresponding value, as well as associated constants that do the
//! same.
//!
//! For example, the `Integer` trait includes the function (among others) `fn
//! to_i32() -> i32` and the associated constant `I32` so that one can do this:
//!
//! ```
//! use typenum::{Integer, N42};
//!
//! assert_eq!(-42, N42::to_i32());
//! assert_eq!(-42, N42::I32);
//! ```
use crate::sealed::Sealed;
/// A **marker trait** to designate that a type is not zero. All number types in this
/// crate implement `NonZero` except `B0`, `U0`, and `Z0`.
pub trait NonZero: Sealed {}
/// A **marker trait** to designate that a type is zero. Only `B0`, `U0`, and `Z0`
/// implement this trait.
pub trait Zero: Sealed {}
/// A **Marker trait** for the types `Greater`, `Equal`, and `Less`.
pub trait Ord: Sealed {
#[allow(missing_docs)]
fn to_ordering() -> ::core::cmp::Ordering;
}
/// The **marker trait** for compile time bits.
pub trait Bit: Sealed + Copy + Default + 'static {
#[allow(missing_docs)]
const U8: u8;
#[allow(missing_docs)]
const BOOL: bool;
/// Instantiates a singleton representing this bit.
fn new() -> Self;
#[allow(missing_docs)]
fn to_u8() -> u8;
#[allow(missing_docs)]
fn to_bool() -> bool;
}
/// The **marker trait** for compile time unsigned integers.
///
/// # Example
/// ```rust
/// use typenum::{Unsigned, U3};
///
/// assert_eq!(U3::to_u32(), 3);
/// assert_eq!(U3::I32, 3);
/// ```
pub trait Unsigned: Sealed + Copy + Default + 'static {
#[allow(missing_docs)]
const U8: u8;
#[allow(missing_docs)]
const U16: u16;
#[allow(missing_docs)]
const U32: u32;
#[allow(missing_docs)]
const U64: u64;
#[cfg(feature = "i128")]
#[allow(missing_docs)]
const U128: u128;
#[allow(missing_docs)]
const USIZE: usize;
#[allow(missing_docs)]
const I8: i8;
#[allow(missing_docs)]
const I16: i16;
#[allow(missing_docs)]
const I32: i32;
#[allow(missing_docs)]
const I64: i64;
#[cfg(feature = "i128")]
#[allow(missing_docs)]
const I128: i128;
#[allow(missing_docs)]
const ISIZE: isize;
#[allow(missing_docs)]
fn to_u8() -> u8;
#[allow(missing_docs)]
fn to_u16() -> u16;
#[allow(missing_docs)]
fn to_u32() -> u32;
#[allow(missing_docs)]
fn to_u64() -> u64;
#[cfg(feature = "i128")]
#[allow(missing_docs)]
fn to_u128() -> u128;
#[allow(missing_docs)]
fn to_usize() -> usize;
#[allow(missing_docs)]
fn to_i8() -> i8;
#[allow(missing_docs)]
fn to_i16() -> i16;
#[allow(missing_docs)]
fn to_i32() -> i32;
#[allow(missing_docs)]
fn to_i64() -> i64;
#[cfg(feature = "i128")]
#[allow(missing_docs)]
fn to_i128() -> i128;
#[allow(missing_docs)]
fn to_isize() -> isize;
}
/// The **marker trait** for compile time signed integers.
///
/// # Example
/// ```rust
/// use typenum::{Integer, P3};
///
/// assert_eq!(P3::to_i32(), 3);
/// assert_eq!(P3::I32, 3);
/// ```
pub trait Integer: Sealed + Copy + Default + 'static {
#[allow(missing_docs)]
const I8: i8;
#[allow(missing_docs)]
const I16: i16;
#[allow(missing_docs)]
const I32: i32;
#[allow(missing_docs)]
const I64: i64;
#[cfg(feature = "i128")]
#[allow(missing_docs)]
const I128: i128;
#[allow(missing_docs)]
const ISIZE: isize;
#[allow(missing_docs)]
fn to_i8() -> i8;
#[allow(missing_docs)]
fn to_i16() -> i16;
#[allow(missing_docs)]
fn to_i32() -> i32;
#[allow(missing_docs)]
fn to_i64() -> i64;
#[cfg(feature = "i128")]
#[allow(missing_docs)]
fn to_i128() -> i128;
#[allow(missing_docs)]
fn to_isize() -> isize;
}
/// The **marker trait** for type-level arrays of type-level numbers.
///
/// Someday, it may contain an associated constant to produce a runtime array,
/// like the other marker traits here. However, that is blocked by [this
/// issue](https://github.com/rust-lang/rust/issues/44168).
pub trait TypeArray: Sealed {}
/// The **marker trait** for type-level numbers which are a power of two.
///
/// # Examples
///
/// Here's a working example:
///
/// ```rust
/// use typenum::{PowerOfTwo, P4, P8};
///
/// fn only_p2<P: PowerOfTwo>() {}
///
/// only_p2::<P4>();
/// only_p2::<P8>();
/// ```
///
/// Numbers which are not a power of two will fail to compile in this example:
///
/// ```rust,compile_fail
/// use typenum::{P9, P511, P1023, PowerOfTwo};
///
/// fn only_p2<P: PowerOfTwo>() { }
///
/// only_p2::<P9>();
/// only_p2::<P511>();
/// only_p2::<P1023>();
/// ```
pub trait PowerOfTwo: Sealed {}
二、模块文档注释
//! All of the **marker traits** used in typenum.
//!
//! Note that the definition here for marker traits is slightly different than
//! the conventional one -- we include traits with functions that convert a type
//! to the corresponding value, as well as associated constants that do the
//! same.
//!
//! For example, the `Integer` trait includes the function (among others) `fn
//! to_i32() -> i32` and the associated constant `I32` so that one can do this:
//!
//! ```
//! use typenum::{Integer, N42};
//!
//! assert_eq!(-42, N42::to_i32());
//! assert_eq!(-42, N42::I32);
//! ```
-
这部分是模块级别的文档注释,说明了这些特质是 typenum 中使用的标记特质。
-
这里的标记特质和传统的标记特质(无方法的空特质)略有不同,因为它们可能包含方法或关联常量,用于将类型转换为对应的值。
-
示例展示了如何使用 Integer 特质的 to_i32() 方法和 I32 关联常量来获取类型的值。
三、引入 Sealed 特质
use crate::sealed::Sealed;
-
Sealed 是一个私有特质(通常用于防止下游用户实现这些标记特质,即“密封模式”)。
-
所有标记特质都继承 Sealed,确保只有 typenum 内部可以为实现这些特质的类型。
四、标记特质定义
- NonZero 和 Zero
pub trait NonZero: Sealed {}
pub trait Zero: Sealed {}
-
NonZero:标记非零类型。除 B0、U0 和 Z0 外,所有数字类型都实现此特质。
-
Zero:标记零类型。只有 B0、U0 和 Z0 实现此特质。
-
用途:用于编译时区分零和非零值(例如在类型级别除法中避免除零错误)。
- Ord
pub trait Ord: Sealed {
fn to_ordering() -> ::core::cmp::Ordering;
}
-
用于类型级别的比较结果(Greater、Equal、Less)。
-
to_ordering() 方法将类型转换为运行时的 Ordering 枚举值(Less、Equal、Greater)。
- Bit
pub trait Bit: Sealed + Copy + Default + 'static {
const U8: u8;
const BOOL: bool;
fn new() -> Self;
fn to_u8() -> u8;
fn to_bool() -> bool;
}
-
表示类型级别的位(0 或 1)。
-
提供关联常量(U8、BOOL)和方法(to_u8、to_bool)将位转换为运行时值。
-
new() 用于创建该位的单例实例。
- Unsigned
pub trait Unsigned: Sealed + Copy + Default + 'static {
const U8: u8;
const U16: u16;
// ... 其他整数类型的常量(U32, U64, USIZE, I8, I16, ...)
fn to_u8() -> u8;
fn to_u16() -> u16;
// ... 其他整数类型的转换方法
}
-
表示类型级别的无符号整数(如 U3、U42)。
-
提供关联常量和方法将类型转换为各种整数类型的值(u8、i32 等)。
-
示例:
use typenum::{Unsigned, U3};
assert_eq!(U3::to_u32(), 3); // 使用方法
assert_eq!(U3::I32, 3); // 使用关联常量
- Integer
pub trait Integer: Sealed + Copy + Default + 'static {
const I8: i8;
const I16: i16;
// ... 其他有符号整数类型的常量(I32, I64, ISIZE)
fn to_i8() -> i8;
fn to_i16() -> i16;
// ... 其他有符号整数类型的转换方法
}
-
表示类型级别的有符号整数(如 P3、N42)。
-
类似于 Unsigned,但提供有符号整数的转换。
- TypeArray
pub trait TypeArray: Sealed {}
-
表示类型级别的数字数组(如 [U1, U2, U3])。
-
目前仅作为标记特质,未来可能添加关联常量以生成运行时数组。
- PowerOfTwo
pub trait PowerOfTwo: Sealed {}
-
标记类型级别的 2 的幂次方数(如 P1、P2、P4)。
-
用途:在需要 2 的幂次方的上下文中约束类型(例如位掩码或对齐)。
-
示例:
fn only_p2<P: PowerOfTwo>() {}
only_p2::<P4>(); // 合法
only_p2::<P3>(); // 编译错误
五、总结
这段代码定义了 typenum 的核心标记特质,用于:
-
区分零和非零类型(Zero、NonZero)。
-
表示类型级别的位(Bit)、无符号整数(Unsigned)和有符号整数(Integer)。
-
支持类型级别的比较(Ord)和数组(TypeArray)。
-
标记 2 的幂次方数(PowerOfTwo)。
这些特质通过关联常量和方法将类型级别的值映射到运行时值,同时利用 Rust 的类型系统在编译时强制执行约束。