【glam】断言宏解析

这是一个定义条件编译宏的代码片段,用于 glam 库的运行时和编译时断言。

rust 复制代码
#[cfg(any(
    all(debug_assertions, feature = "debug-glam-assert"),
    feature = "glam-assert"
))]
macro_rules! glam_assert {
    ($($arg:tt)*) => ( assert!($($arg)*); )
}
#[cfg(not(any(
    all(debug_assertions, feature = "debug-glam-assert"),
    feature = "glam-assert"
)))]
macro_rules! glam_assert {
    ($($arg:tt)*) => {};
}

macro_rules! const_assert {
    ($x:expr $(,)?) => {
        #[allow(unknown_lints, clippy::eq_op)]
        const _: () = assert!($x);
    };
}

macro_rules! const_assert_eq {
    ($x:expr, $y:expr $(,)?) => {
        const_assert!($x == $y);
    };
}

1. glam_assert! 宏 - 运行时断言

条件编译逻辑

rust 复制代码
#[cfg(any(
    all(debug_assertions, feature = "debug-glam-assert"),
    feature = "glam-assert"
))]

这个条件表示:当满足任一条件时启用断言:

  • debug_assertions 启用 debug-glam-assert 特性启用(调试模式下的断言)
  • glam-assert 特性启用(所有模式下的断言)

两种实现

启用断言时的实现:

rust 复制代码
macro_rules! glam_assert {
    ($($arg:tt)*) => ( assert!($($arg)*); )
}
  • 接收任意参数($($arg:tt)*
  • 直接转发给标准的 assert!
  • 在条件满足时执行实际的断言检查

禁用断言时的实现:

rust 复制代码
#[cfg(not(any(
    all(debug_assertions, feature = "debug-glam-assert"),
    feature = "glam-assert"
)))]
macro_rules! glam_assert {
    ($($arg:tt)*) => {};
}
  • 当条件不满足时,宏展开为空
  • 相当于在编译时移除所有断言,零运行时开销

使用示例

rust 复制代码
// 在代码中使用
fn some_function(normalized_vector: Vec3) {
    glam_assert!(normalized_vector.is_normalized()); // 仅在启用时检查
    // 函数逻辑...
}

2. const_assert! 宏 - 编译时常量断言

rust 复制代码
macro_rules! const_assert {
    ($x:expr $(,)?) => {
        #[allow(unknown_lints, clippy::eq_op)]
        const _: () = assert!($x);
    };
}

特点

  • 编译时执行:在编译期检查常量表达式
  • 使用常量断言 :通过 const _: () = assert!($x) 在编译期求值
  • 抑制警告#[allow(unknown_lints, clippy::eq_op)] 避免不必要的 lint 警告
  • 创建匿名常量const _: () 创建一个未命名的单元类型常量

工作原理

rust 复制代码
// 在编译时检查
const_assert!(std::mem::size_of::<Vec3A>() == 16); // 编译通过
const_assert!(std::mem::size_of::<Vec3A>() == 12); // 编译错误!

3. const_assert_eq! 宏 - 编译时相等断言

rust 复制代码
macro_rules! const_assert_eq {
    ($x:expr, $y:expr $(,)?) => {
        const_assert!($x == $y);
    };
}

特点

  • const_assert! 的便捷封装
  • 专门用于检查两个表达式是否相等
  • 接收两个参数并生成相等性断言

使用示例

rust 复制代码
// 检查类型大小
const_assert_eq!(std::mem::size_of::<Vec3>(), 12);
const_assert_eq!(std::mem::size_of::<Vec3A>(), 16);

// 检查对齐要求
const_assert_eq!(std::mem::align_of::<Mat4>(), 16);

实际应用场景

1. 参数验证

rust 复制代码
impl Quat {
    pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self {
        glam_assert!(axis.is_normalized()); // 仅在调试时检查
        // 实现逻辑...
    }
}

2. 编译时类型检查

rust 复制代码
// 确保类型大小符合预期
const_assert_eq!(std::mem::size_of::<Vec3A>(), 16);
const_assert_eq!(std::mem::size_of::<Mat3A>(), 48);

3. 特性兼容性检查

rust 复制代码
// 确保对齐要求
#[cfg(target_feature = "sse2")]
const_assert_eq!(std::mem::align_of::<Vec4>(), 16);

性能影响

运行时断言 (glam_assert!)

模式 性能影响 适用场景
启用时 增加运行时检查开销 调试、测试、开发环境
禁用时 零开销,完全移除 生产环境、发布构建

编译时断言 (const_assert!/const_assert_eq!)

特性 说明
运行时开销 始终为零,在编译期完成检查
二进制影响 不会影响生成的二进制文件大小
执行速度 不影响运行时执行速度
适用场景 类型布局验证、常量检查

设计优势

优势 说明
灵活性 通过特性控制断言行为,适应不同环境需求
零成本抽象 不启用时完全消除开销,符合 Rust 哲学
编译期安全 静态验证重要属性,提前发现错误
代码清晰 将验证逻辑与业务逻辑分离,提高可维护性

特性组合矩阵

debug-glam-assert glam-assert debug_assertions glam_assert! 行为
启用断言
禁用断言
✅/❌ 启用断言
✅/❌ 禁用断言

总结

这种断言宏的设计模式在 Rust 的底层库中很常见,具有以下特点:

  1. 双重控制机制:通过特性开关和编译模式控制断言
  2. 编译期/运行时分离:不同类型的断言满足不同需求
  3. 安全性与性能平衡:既保证了安全性又维持了高性能
  4. Rust idiomatic:符合 Rust 的零成本抽象理念

这种设计使得 glam 能够在开发过程中提供充分的调试支持,同时在生产环境中保持最佳性能。

相关推荐
techdashen8 小时前
从 Windows 的 ping.exe 入手:动态库、调用约定与 Rust FFI
开发语言·windows·rust
Venuslite8 小时前
Mac系统安装Rust
rust
shimly12345610 小时前
RUST Arc
rust
盒马盒马12 小时前
Rust:Vec
开发语言·rust
doiito12 小时前
【Agent Harness实战】认清现实吧,LLM就是个“超级赌场”,而我们需要的是一套“紧箍咒”
架构·rust
盒马盒马12 小时前
Rust:String
java·前端·rust
techdashen13 小时前
用 Rust 真正发出 Ping:FFI 类型、newtype 与 MaybeUninit
开发语言·后端·rust
星栈独行1 天前
Makepad 应用如何读文件、调接口、保存数据
前端·程序人生·ui·rust·github
guyoung1 天前
BoxAgnts 工具系统(7)——Skill 模板、Agent 代理与 Cron 调度
rust·agent·ai编程
分布式存储与RustFS1 天前
基于Rust的国产开源对象存储RustFS:S3 Table对Iceberg数据湖的适配详解
rust·开源·iceberg·对象存储·rustfs·minio平替·s3 table