【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 能够在开发过程中提供充分的调试支持,同时在生产环境中保持最佳性能。

相关推荐
咚为2 小时前
告别 lazy_static:深度解析 Rust OnceCell 的前世今生与实战
开发语言·后端·rust
Java水解18 小时前
Rust异步编程实战:构建高性能网络应用
后端·rust
土豆125018 小时前
Rust 实战:手把手教你开发一个命令行工具
前端·rust
勇敢牛牛_18 小时前
【aiway】基于 Rust 开发的 API + AI 网关
开发语言·后端·网关·ai·rust
Source.Liu1 天前
【Iced】`lib.rs` 源码分析 - `iced_core` 核心库
rust·iced
古城小栈1 天前
Rust跨平台编译打包 之 三大战役
开发语言·后端·rust
was1721 天前
基于 Rust 的跨 Shell 提示符:Starship 安装与环境初始化指南
开发语言·elasticsearch·rust
rainchestnut2 天前
bevy初体验2-官方示例学习
rust
葡萄城技术团队2 天前
Hurley:用 Rust 打造的高性能 HTTP 客户端 + 压测工具
开发语言·http·rust