6 releases (breaking)

0.5.0 Dec 1, 2024
0.4.0 Nov 18, 2024
0.3.0 May 24, 2024
0.2.2 May 23, 2024
0.1.0 Jan 22, 2024

#1022 in Procedural macros

Download history 5/week @ 2024-08-26 31/week @ 2024-09-23 20/week @ 2024-10-07 8/week @ 2024-10-14 3/week @ 2024-10-28 195/week @ 2024-11-18 139/week @ 2024-11-25 57/week @ 2024-12-02 54/week @ 2024-12-09

445 downloads per month
Used in enumcapsulate

MPL-2.0 license

76KB
1K SLoC

enumcapsulate-macros

Crates.io Crates.io Crates.io docs.rs

Derive macros for enumcapsulate crate.


Macros

The enumcapsulate-macros proc-macro crate exports the following derive macros:

Derive macro Functionality
Encapsulate Derives impls for AsVariant, AsVariantMut, AsVariantRef, From, FromVariant, IntoVariant, TryInto, and VariantDowncast.
FromVariant Derives impls for Self: enumcapsulate::FromVariant<T> for each non-unit variant type T.
IntoVariant Derives impls for Self: enumcapsulate::FromVariant<T> for each non-unit variant type T.
From Derives impls for Self: core::convert::From<T> for each non-unit variant type T.
TryInto Derives impls for T: core::convert::TryFrom<Self> for each non-unit variant type T.
AsVariant Derives impls for Self: enumcapsulate::AsVariant<T> for each non-unit variant type T.
AsVariantMut Derives impls for Self: enumcapsulate::AsVariantMut<T> for each non-unit variant type T.
AsVariantRef Derives impls for Self: enumcapsulate::AsVariantRef<T> for each non-unit variant type T.
VariantDowncast Derives impl for Self: enumcapsulate::VariantDowncast.
VariantDiscriminant Derives impl for Self: enumcapsulate::VariantDiscriminant.

[!NOTE] The implementations generated by the From and FromVariant, as well as the TryInto and IntoVariant derive macro pairs are semantically equivalent.

#[derive(Encapsulate)]

The umbrella derive macro Encapsulate allows for conveniently deriving AsVariant, AsVariantMut, AsVariantRef, From, FromVariant, IntoVariant, TryInto, and VariantDowncast all at once.

The following two snippets are semantically equivalent:

#[derive(Encapsulate)]
enum Enum { /* ... */ }
#[derive(
    From,
    TryInto,
    FromVariant,
    IntoVariant,
    AsVariant,
    AsVariantMut,
    AsVariantRef,
    VariantDowncast,
)]
enum Enum { /* ... */ }

[!TIP] If the list of trait derives produced by #[derive(Encapsulate)] is too broad of a stroke your your particular use case then your can selectively opt them out by use of an #[enumcapsulate(exclude())] attribute on the enum itself.

#[derive(Encapsulate)]
#[enumcapsulate(exclude(From, TryInto))]
enum Enum {
    // Excluded from `From` and `TryInto` derives
    // due to existing enum-level attribute:
    VariantA(VariantA),

    // Exclude derivation of any traits
    // for this specific variant's type:
    #[enumcapsulate(exclude)]
    VariantB(VariantB),

    // Selectively exclude derivation of `From` trait
    // for this specific variant's type:
    #[enumcapsulate(exclude(From))]
    VariantC(VariantC),
}

Macro helper attributes

Most of the derive macros support helper attributes:

Enum attributes

#[enumcapsulate(exclude())]

Selectively opt out of enumcapsulate trait derivations.

  • #[enumcapsulate(exclude())]

    Exclude variant from specific Encapsulate derive macros.

[!IMPORTANT] This attribute is only recognized by the Encapsulate umbrella derive macro.

If you wish to opt out of a select few of Encapsulate's trait derives, then you can do so by use of an #[enumcapsulate(exclude())] attribute:

#[derive(Encapsulate)]
#[enumcapsulate(exclude(From, TryInto))]
enum Enum { /* ... */ }
#[enumcapsulate(discriminant(repr =))]

Specify a memory representation for the generated discriminant type.

[!IMPORTANT] This attribute is only recognized by the VariantDiscriminant derive macro.

If you wish to specify a custom memory representation for the discriminant type generated by the VariantDiscriminant derive macro, then you can do so by use of an #[enumcapsulate(discriminant(repr = <typename>))] attribute:

#[derive(VariantDiscriminant)]
#[enumcapsulate(discriminant(repr = u8))]
enum MyEnum { /* ... */ }
#[enumcapsulate(discriminant(name =))]

Specify a custom name for the generated discriminant type.

[!IMPORTANT] This attribute is only recognized by the VariantDiscriminant derive macro.

If you wish to specify a custom name for the discriminant type generated by the VariantDiscriminant derive macro, then you can do so by use of an #[enumcapsulate(discriminant(name = <typename>))] attribute:

#[derive(VariantDiscriminant)]
#[enumcapsulate(discriminant(name = MyDiscriminant))]
enum MyEnum { /* ... */ }

Variant attributes

[!NOTE] Variant-level attributes have a higher precedence than their equivalent enum-level attributes and thus act as a selective override if both are present.

#[enumcapsulate(exclude())]

Exclude this variant from trait derivation.

  • #[enumcapsulate(exclude)]

    Exclude variant from all enumcapsulate derive macros.

  • #[enumcapsulate(exclude())]

    Exclude variant from specific enumcapsulate derive macros.

[!IMPORTANT] This attribute is recognized by the following variant-based derive macros:

  • AsVariant
  • AsVariantMut
  • AsVariantRef
  • FromVariant
  • IntoVariant
  • From
  • TryInto

… as well as the umbrella derive macro:

  • Encapsulate

If you wish to opt out of a select few of Encapsulate's trait derives, then you can do so by use of an #[enumcapsulate(exclude())] attribute:

#[derive(Encapsulate)]
enum Enum {
    // Included by default.
    VariantA(VariantA),
    
    // Excluded from all derives:
    #[enumcapsulate(exclude)]
    VariantB(VariantB),
    
    // Excluded from just the `From` and `TryInto` derives:
    #[enumcapsulate(exclude(From, TryInto))]
    VariantC(VariantC),
}

#[enumcapsulate(field(=)]

Select a specific variant field as target for trait derivation.

  • #[enumcapsulate(field(index = <index>))]

    Select field at index <index> to be used as target.

  • #[enumcapsulate(field(name = "<name>"))]

    Select field with name <name> to be used as target.

[!IMPORTANT] This attribute is recognized by the following variant-based derive macros:

  • AsVariant
  • AsVariantMut
  • AsVariantRef
  • FromVariant
  • IntoVariant
  • From
  • TryInto

… as well as the umbrella derive macro:

  • Encapsulate
#[derive(Encapsulate)]
enum Enum {
    // Select field `1`, i.e. `VariantA`:
    #[enumcapsulate(field(index = 1))]
    VariantA(i32, VariantA),
    
    // Select field `b`, i.e. `VariantB`:
    #[enumcapsulate(field(name = "b"))]
    VariantB { b: VariantB, c: u32 },
}

[!NOTE] When deriving traits for variants with multiple fields a field has to be explicitly specified using #[enumcapsulate(field(=))].

Alternatively the variant can be excluded via #[enumcapsulate(exclude)].

#[enumcapsulate(discriminant(value =))]

Specify a memory representation for the generated discriminant type.

[!IMPORTANT] This attribute is only recognized by the VariantDiscriminant derive macro.

If you wish to specify a custom memory representation for the discriminant type generated by the VariantDiscriminant derive macro, then you can do so by use of an #[enumcapsulate(discriminant(value = <expr>))] attribute:

#[derive(VariantDiscriminant)]
enum Enum {
    #[enumcapsulate(discriminant(value = 42))]
    VariantA(i32),
    
    VariantB { b: u32 },
}
#[enumcapsulate(discriminant(name =))]

Specify a custom name for the generated discriminant type.

[!IMPORTANT] This attribute is only recognized by the VariantDiscriminant derive macro.

If you wish to specify a custom name for the discriminant type generated by the VariantDiscriminant derive macro, then you can do so by use of an #[enumcapsulate(discriminant(name =))] attribute:

#[derive(VariantDiscriminant)]
enum Enum {
    #[enumcapsulate(discriminant(name = CustomDiscriminant))]
    VariantA(i32),
    
    VariantB { b: u32 },
}
#[enumcapsulate(discriminant(value =))]

Specify a memory representation for the generated discriminant type.

[!IMPORTANT] This attribute is only recognized by the VariantDiscriminant derive macro.

If you wish to specify a custom memory representation for the discriminant type generated by the VariantDiscriminant derive macro, then you can do so by use of an #[enumcapsulate(discriminant(value = <expr>))] attribute:

#[derive(VariantDiscriminant)]
enum Enum {
    #[enumcapsulate(discriminant(value = 42))]
    VariantA(i32),
    
    VariantB { b: u32 },
}
#[enumcapsulate(discriminant(name =))]

Specify a custom name for the generated discriminant type.

[!IMPORTANT] This attribute is only recognized by the VariantDiscriminant derive macro.

If you wish to specify a custom name for the discriminant type generated by the VariantDiscriminant derive macro, then you can do so by use of an #[enumcapsulate(discriminant(name =))] attribute:

#[derive(VariantDiscriminant)]
enum Enum {
    #[enumcapsulate(discriminant(name = CustomDiscriminant))]
    VariantA(i32),
    
    VariantB { b: u32 },
}

Generics

There is limited support for generic enums:

Variants using generic const/type parameters are always excluded when deriving generic traits with enumcapsulate's derive macros.

The reason for this behavior is that implementing generic traits for variants that use any of the generic parameters of the enum tends to result in conflicting implementations in Rust, as shown by the following example program:

use enumcapsulate::FromVariant;

pub struct VariantA;
pub struct VariantB;

#[derive(FromVariant)]
// error[E0119]: conflicting implementations of trait `FromVariant<VariantB>` for type `Enum<VariantB>`
pub enum Enum<T> {
    Unit,
    Generic(T),
    NonGeneric(VariantB),
}

fn main() {
    let _: Enum<VariantA> = Enum::from_variant(VariantA);
    let _: Enum<VariantA> = Enum::from_variant(VariantB);
}

The expanded version of the above makes it easier to see why: The compiler can't prove that T and VariantB are disjoint types.

pub struct VariantA;
pub struct VariantB;

pub enum Enum<T> {
    Unit,
    Generic(T),
    NonGeneric(VariantB),
}

impl<T> FromVariant<T> for Enum<T> { // <- first implementation here
    fn from_variant(variant: T) -> Self {
        Self::Generic(variant)
    }
}

// error[E0119]: conflicting implementations of trait `FromVariant<VariantB>` for type `Enum<VariantB>`
impl<T> FromVariant<VariantB> for Enum<T> { // <- conflicting implementation for `Enum<VariantB>`
    fn from_variant(variant: VariantB) -> Self {
        Self::NonGeneric(variant)
    }
}

fn main() {
    let _: Enum<VariantA> = Enum::from_variant(VariantA);
    let _: Enum<VariantA> = Enum::from_variant(VariantB);
}

So in order to avoid such pitfalls altogether enumcapsulate's derive macros will skip impl<T> FromVariant<T> for Enum<T>, since it uses a generic type (or const) parameter of Enum<T>.

So all you have to do is provide your own non-generic implementations for specific type instances of your generic type yourself, filling any gaps left behind by the derive macro:

use enumcapsulate::FromVariant;

pub struct VariantA;
pub struct VariantB;

#[derive(FromVariant)]
pub enum Enum<T> {
    Unit,
    Generic(T),
    NonGeneric(VariantB),
}

// Notice how the trait is implemented on
// a specific type of the `Enum<T>` kind,
// rather than on the generic kind itself:
impl From<VariantA> for Enum<VariantA> {
    fn from(value: VariantA) -> Self {
        Self::Generic(value)
    }
}

fn main() {
    let _: Enum<VariantA> = Enum::from_variant(VariantA);
    let _: Enum<VariantA> = Enum::from_variant(VariantB);
}

Documentation

Please refer to the documentation on docs.rs.

Contributing

Please read CONTRIBUTING.md for details on our code of conduct,
and the process for submitting pull requests to us.

Versioning

We use SemVer for versioning. For the versions available, see the tags on this repository.

License

This project is licensed under the MPL-2.0 – see the LICENSE.md file for details.

Dependencies

~220–660KB
~16K SLoC