#assert #build #static #const-generics #testing

no-std build_assert

在构建时断言 const 泛型表达式

1 个不稳定版本

0.0.1 2023年11月21日

#87 in #const-generics

MIT/Apache

22KB
213

build_assert

github crates.io docs.rs build status

build_assert 允许你在构建时进行断言。

assert 以及一些编译时断言的实现(如 static_assertions)不同,build_assert 在运行前工作,可以用于包含 const 泛型的表达式。

用法

通过运行 cargo addbuild_assert 添加到您的项目中

cargo add build_assert

示例

fn foo<const N: usize>() {
  build_assert!(N > 5);
}

foo::<10>(); // Fine.
foo::<0>();  // Fails to compile.

上面的示例在发布模式下将 无法构建。由于内部实现,它在调试模式下将 通过构建并在运行时恐慌

相比之下,assert 只会在运行时恐慌,静态断言实现不能应用于 const 泛型

macro_rules! static_assert {
  ($e:expr) => {
    const _: () = core::assert!($e);
  };
}

fn foo<const N: usize>() {
  static_assert!(N > 5);
}

编译上面的示例时出现错误

error[E0401]: can't use generic parameters from outer item
  --> src/lib.rs:36:18
   |
9  | fn foo<const N: usize>() {
   |              - const parameter from outer item
10 |   static_assert!(N > 5);
   |                  ^ use of generic parameter from outer item

特性

默认情况下,build_assert 使用内联汇编(即 core::arch::asm)来引发构建时错误。如果您需要在不支持内联汇编的目标上构建此crate(参见 Rust 参考),您可以启用 no_asm 功能。

当启用 no_asm 时,如果断言失败,build_assert 通过引用一个未定义的符号来引发链接错误。默认情况下,符号名称为 __build_error_impl。为了避免符号冲突,您可以在构建之前设置环境变量 BUILD_ERROR_SYM 来指定不同的符号

BUILD_ERROR_SYM=hello cargo build --release

请注意,如果项目之前已经构建,则应清除构建缓存以确保此更改生效。

内部原理

build_assert 宏将被展开为

if !cond {
  build_error!();
}

在发布模式下,期望优化器评估 if 表达式的条件。如果 condtrue,则 build_error 宏展开的结果将被优化掉。否则,将保留展开结果。

在支持内联汇编的目标上,build_error 宏将展开为

core::arch::asm!("build error at file.rs:line:column");

由于 build 在任何目标上都不是一个有效的指令,因此构建将失败。

在不支持内联汇编的目标上,build_error 宏会展开为

extern "Rust" {
  fn __build_error_impl() -> !;
}

unsafe { __build_error_impl() }

可能会出现如下链接错误

error: linking with `cc` failed: exit status: 1
  |
  = note: env -u ...
  = note: /usr/bin/ld: ... .o: in function `rust_out::main::...':
          ... .rs:6: undefined reference to `__build_error_impl'
          collect2: error: ld returned 1 exit status

  = note: ...

在调试模式下,由于优化器不会运行,build_error 宏将始终保留。我们无法使用上述方法引发构建错误,否则无论条件是否为 true,构建都将始终失败。因此,build_error 宏将展开为 panic

参考资料

build_assert 宏的灵感来源于 Rust for Linux 项目。此crate使用不同的方法来实现宏。

变更日志

请参阅 CHANGELOG.md

许可证

版权所有 (C) 2023 MaxXing。根据您的选择,许可协议为 Apache 2.0MIT

依赖项

~260–710KB
~17K SLoC