Derive Macro const_panic::PanicFmt

source ·
#[derive(PanicFmt)]
{
    // Attributes available to this derive:
    #[pfmt]
}
Available on crate feature derive only.
Expand description

Derives the PanicFmt trait.

This requires the "derive" feature, disabled by default.

This generates a generic PanicFmt impl, as well as one or more inherent to_panicvals method definitions as described in the trait docs.

You can also use impl_panicfmt as an alternative that requires less time to compile from scratch, but requires repeating the type definition.

Jump straight to examples

Limitations

Type parameters

Types with type parameters can’t be generically formatted, to work around this you can use either or both of these attributes:

  • #[pfmt(ignore(T))]: if the type parameter(s) are only used in marker types (eg: PhantomData).
  • #[pfmt(impl Foo<Bar, Baz>)]: to implement panic formatting with concrete type arguments (this attribute can be used multiple times to add impls).

This limitation is caused by:

example below

Const parameters

Const parameters must not affect the value of the PanicFmt::PV_COUNT of this type, since the const parameter must be replaceable with a concrete value.
Note that arrays have a PV_COUNT of 1 for all lengths.

Concrete Self type for PanicFmt::PV_COUNT

The to_panicvals method that this macro generates roughly returns a

[PanicVal<'_>; <Self as PanicFmt>::PV_COUNT]

Because of limitations in stable const generics, the generic arguments of Self in the above code must be replaced with concrete arguments, requiring:

  • Lifetime arguments to be replaced with '_
  • Type arguments to be replaced with concrete types (usually () or the concrete types used in #[pfmt(impl ....)] attributes)
  • Const arguments to be replaced with concrete values (usually the default value for the type)

Attributes

Container attributes

Attributes used above the type definition.

#[pfmt(crate = foo::bar)]

Replaces the path to const_panic with foo::bar

example

#[pfmt(debug_print)]:

For diagnostics, causes the derive macro to panic with the code generated by it.

#[pfmt(ignored(T, C))]

Accepts the names of type and const parameters, replacing the generic arguments in here with a concrete value.

For type parameters, this replaces the type parameter with () unless overriden, and also tells the derive not to require T: PanicFmt in the PanicFmt implementation for the deriving type (since the type parameter is not formatted).

Const parameters are ignored by default, replacing them with the default value for that type 1

The concrete value for each generic parameter can be overriden with T = value

examples:

  • #[pfmt(ignored(T))]
  • #[pfmt(ignored(T = u16))]
  • #[pfmt(ignored(T = u32, C))]
  • #[pfmt(ignored(T, C = 100))]
  • #[pfmt(ignored(U = str, A = false))]

(more conplete example)

#[pfmt(impl Foo<Bar, BAZ>)]

Tells the derive to generate an inherent to_panicvals method for the type in the attribute (it must be the deriving type with concrete enough generic arguments).

examples:

  • #[pfmt(impl Foo<u32, 10>)]
  • #[pfmt(impl<T> Foo<T, 'A'>)]: this also requires a #[pfmt(ignored(T))] attribute

(more conplete example)

Examples

Basic struct

use const_panic::{ArrayString, FmtArg, PanicFmt};

assert_eq!(
    const_panic::concat_!(Foo { x: 3, y: &[3, 5, 8] }),
    "Foo { x: 3, y: [3, 5, 8] }",
);

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

Basic enum

use const_panic::{ArrayString, FmtArg, PanicFmt};

assert_eq!(const_panic::concat_!(Foo::Bar), "Bar");

assert_eq!(
    const_panic::concat_!(Foo::Baz("hello", true)),
    "Baz(\"hello\", true)",
);

#[derive(PanicFmt)]
enum Foo {
    Bar,
    Baz(&'static str, bool),
}

Type parameters

This example demonstrates support for types with type parameters.

use const_panic::{ArrayString, FmtArg, PanicFmt};

use std::marker::PhantomData;

{
    const WITH_INT: Foo<&str, u8> = Foo {
        value: 100u8,
        _marker: PhantomData,
    };
    assert_eq!(
        const_panic::concat_!(WITH_INT),
        "Foo { value: 100, _marker: PhantomData }",
    );
}
{
    const WITH_STR: Foo<bool, &str> = Foo {
        value: "hello",
        _marker: PhantomData,
    };
    assert_eq!(
        const_panic::concat_!(WITH_STR),
        r#"Foo { value: "hello", _marker: PhantomData }"#,
    );
}

#[derive(Debug, PanicFmt)]
// Tells the derive that the `A` type parameter is not formatted,
// removing the `A: PanicFmt` bound in `impl<A, B> PanicFmt for Foo<A, B>`,
// and using `()` as the `A` type parmeter for
// `<Foo<....> as PanicFmt>::PV_COUNT` in the generated `to_panicvals` method.
#[pfmt(ignore(A))]
// Defines a `to_panicvals` method for `Foo<A, u8>`
#[pfmt(impl<A> Foo<A, u8>)]
// Defines a `to_panicvals` method for `Foo<A, &str>`
#[pfmt(impl<A> Foo<A, &str>)]
pub struct Foo<A, B> {
    value: B,
    _marker: PhantomData<A>,
}

Phantom Type parameters

This example demonstrates how type parameters can be ignored with #[pfmt(ignore(...))].

use const_panic::{ArrayString, FmtArg, PanicFmt};

use std::marker::PhantomData;

{
    const WITH_INT: Foo<u8, bool, 100> = Foo{
        value: 5,
        _marker: PhantomData,
    };
    assert_eq!(
        const_panic::concat_!(WITH_INT),
        "Foo { value: 5, _marker: PhantomData }",
    );
}
{
    const WITH_STR: Foo<str, char, 200> = Foo {
        value: 8,
        _marker: PhantomData,
    };
    assert_eq!(
        const_panic::concat_!(WITH_STR),
        r#"Foo { value: 8, _marker: PhantomData }"#,
    );
}

#[derive(Debug, PanicFmt)]
// Tells the derive that the `A` and `B` type parameters are not formatted,
// removing the `A: PanicFmt` and `B: PanicFmt` bounds in the `PanicFmt` impl for `Foo`,
// and using `()` and `u8` as the `A` and `B` type parameters for
// `<Foo<(), u8> as PanicFmt>::PV_COUNT` in the generated `to_panicvals` method.
#[pfmt(ignore(A, B = u8))]
pub struct Foo<A: ?Sized, B, const X: u32> {
    value: u32,
    _marker: PhantomData<(PhantomData<A>, B)>,
}

Const-generic struct

use const_panic::{ArrayString, FmtArg, PanicFmt};

assert_eq!(const_panic::concat_!(Foo([])), "Foo([])");

assert_eq!(const_panic::concat_!(Foo([3, 5, 8])), "Foo([3, 5, 8])");

#[derive(PanicFmt)]
struct Foo<const LEN: usize>([u8; LEN]);

Crate renaming

This example demonstrates how the const_panic crate can be renamed, passing the new name to the derive macro.

use cpanic::{ArrayString, FmtArg, PanicFmt};;

assert_eq!(cpanic::concat_!(Foo(Some(13))), "Foo(Some(13))");

#[derive(PanicFmt)]
#[pfmt(crate = cpanic)]
struct Foo(Option<u32>);

  1. a private trait is used to get the default value for const parameters.