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

相关推荐
Naylor1 天前
只借不占:Rust 的引用与借用
后端·rust
对象存储与RustFS1 天前
RustFS 后台扫描器与自愈调参:五档速度、位腐检测周期与并发上限
后端·rust·开源
q平面人2 天前
【总工笔记】mindoc平板、桌面端笔记软件,发布到mindoc服务端
rust·tauri·华为平板·mindoc·总工笔记
MC皮蛋侠客2 天前
Tauri 2.x 系列(九):安全模型——Capabilities、Permissions、Scope 与 CSP
rust·tauri
Source.Liu2 天前
【Dioxus】Windows 环境下 Rust + Dioxus 安装配置笔记
windows·rust·dioxus
zLLM_Lab2 天前
不装 Python/PyTorch:8.1 MB Rust 程序在 MacBook Air M5 跑多模态大模型
rust
梦醒沉醉2 天前
std1.97.1——result模块细览
rust
Thneonl3 天前
同一资源、不同 ID:多源拓扑的 Identity Resolution
架构·rust
绍磊leo3 天前
【保姆级】dora-rs 一键安装脚本:类ros2的fishros 风格交互菜单 + 国内镜像加速,把坑都替你踩完了
rust·dora-rs
Ramble_Naylor3 天前
只借不占:Rust 的引用与借用
开发语言·rust