#const #panic #format

no-std constpanic

const panic 带格式化

12 个版本

0.2.8 2023 年 4 月 30 日
0.2.7 2022 年 11 月 28 日
0.2.6 2022 年 10 月 10 日
0.2.4 2022 年 7 月 6 日
0.2.1 2021 年 11 月 20 日

#4 in 无标准库

Download history 35836/week @ 2024-04-26 34983/week @ 2024-05-03 37634/week @ 2024-05-10 53044/week @ 2024-05-17 60373/week @ 2024-05-24 65835/week @ 2024-05-31 56544/week @ 2024-06-07 53577/week @ 2024-06-14 45124/week @ 2024-06-21 42581/week @ 2024-06-28 62204/week @ 2024-07-05 81216/week @ 2024-07-12 89304/week @ 2024-07-19 70550/week @ 2024-07-26 82263/week @ 2024-08-02 82782/week @ 2024-08-09

340,501 每月下载量
848 个 Crates 中使用 (16 直接)

Zlib 许可证

220KB
4K SLoC

Rust crates-io api-docs

用于 const 上下文中的带格式化 panic。

由于 Rust 1.57.0 中 panic 宏在 const 上下文中的稳定性得到了保证,但缺乏格式化支持,因此存在这个库。

所有实现了 PanicFmt 特质的类型都可以在 panic 中进行格式化。

示例

基本

use const_panic::concat_assert;

const FOO: u32 = 10;
const BAR: u32 = 0;
const _: () = assert_non_zero(FOO, BAR);

#[track_caller]
const fn assert_non_zero(foo: u32, bar: u32) {
    concat_assert!{
        foo != 0 && bar != 0,
        "\nneither foo nor bar can be zero!\nfoo: ", foo, "\nbar: ", bar
    }
}

上述代码会因为这个错误而无法编译

error[E0080]: evaluation of constant value failed
 --> src/lib.rs:20:15
  |
8 | const _: () = assert_non_zero(FOO, BAR);
  |               ^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at '
neither foo nor bar can be zero!
foo: 10
bar: 0', src/lib.rs:8:15

在运行时调用时

use const_panic::concat_assert;

assert_non_zero(10, 0);

#[track_caller]
const fn assert_non_zero(foo: u32, bar: u32) {
    concat_assert!{
        foo != 0 && bar != 0,
        "\nneither foo nor bar can be zero!\nfoo: ", foo, "\nbar: ", bar
    }
}

将打印出这个

thread 'main' panicked at '
neither foo nor bar can be zero!
foo: 10
bar: 0', src/lib.rs:6:1
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

自定义类型

自定义类型的 panic 格式化可以按照以下方式(按详尽程度递增)完成

  • 使用 PanicFmt derive 宏(需要启用 opt-in "derive" 功能)
  • 使用 impl_panicfmt 宏(需要启用默认启用的 "non_basic" 功能)
  • 使用 flatten_panicvals 宏(需要启用默认启用的 "non_basic" 功能)
  • 按照其文档中的描述手动实现 PanicFmt 特质。

此示例使用 PanicFmt derive 方法。

use const_panic::{PanicFmt, concat_panic};

const LAST: u8 = {
    Foo{
        x: &[],
        y: Bar(false, true),
        z: Qux::Left(23),
    }.pop().1
};

impl Foo<'_> {
    /// Pops the last element
    ///
    /// # Panics
    ///
    /// Panics if `self.x` is empty
    #[track_caller]
    const fn pop(mut self) -> (Self, u8) {
        if let [rem @ .., last] = self.x {
            self.x = rem;
            (self, *last)
        } else {
            concat_panic!(
                "\nexpected a non-empty Foo, found: \n",
                // uses alternative Debug formatting for `self`,
                // otherwise this would use regular Debug formatting.
                alt_debug: self
            )
        }
    }
}

#[derive(PanicFmt)]
struct Foo<'a> {
    x: &'a [u8],
    y: Bar,
    z: Qux,
}

#[derive(PanicFmt)]
struct Bar(bool, bool);

#[derive(PanicFmt)]
enum Qux {
    Up,
    Down { x: u32, y: u32 },
    Left(u64),
}

上述代码会因为这个错误而无法编译

error[E0080]: evaluation of constant value failed
  --> src/lib.rs:57:5
   |
7  | /     Foo{
8  | |         x: &[],
9  | |         y: Bar(false, true),
10 | |         z: Qux::Left(23),
11 | |     }.pop().1
   | |___________^ the evaluated program panicked at '
expected a non-empty Foo, found:
Foo {
    x: [],
    y: Bar(
        false,
        true,
    ),
    z: Left(
        23,
    ),
}', src/lib.rs:11:7


限制

格式化/panic 宏的参数必须具有完全推断的具体类型,因为 const_panic 宏使用鸭子类型来调用这些参数的方法。

该限制的一个影响是,当这些整数没有被推断为具体类型时,您将不得不传递带有后缀的整数字面量(例如:100u8)。

Panic 消息长度

panic 消息的长度只能达到 MAX_PANIC_MSG_LEN,超过这个长度会被截断。

Cargo 功能

  • "non_basic"(默认启用):启用对结构体、枚举和数组的格式化支持。

如果没有这个特性,你只能有效地格式化原始类型(自定义类型可以手动实现更困难的格式化)。
  • "rust_1_64"(默认禁用):启用对需要Rust 1.64.0才能格式化的额外项的格式化。

  • "derive"(默认禁用):启用PanicFmt derive 宏。

计划

目前没有

No-std 支持

const_panic#![no_std],可以在Rust可以使用的任何地方使用。

最低支持的 Rust 版本

这需要 Rust 1.57.0,因为它在const上下文中使用了 panic 宏。

依赖项

~0–305KB