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
445 downloads per month
Used in enumcapsulate
76KB
1K
SLoC
enumcapsulate-macros
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
andFromVariant
, as well as theTryInto
andIntoVariant
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