Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ Please make sure to add your changes to the appropriate categories:

### Added

- n/a
- Added enum-level `#[enumcapsulate(discriminant(…))]` helper attribute for `VariantDiscriminant` derive macro, allowing for customizing `repr = …` and `name = …` for the generated enum.
- Added variant-level `#[enumcapsulate(discriminant(…))]` helper attribute for `VariantDiscriminant` derive macro, allowing for customizing `value = …` and `name = …` for the generated variant.

### Changed

Expand Down
177 changes: 148 additions & 29 deletions macros/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,6 @@ enum Enum { /* ... */ }
> }
> ```

### `#[derive(AsVariant)]`

The `AsVariant` derive macro requires the variant's field type to implement `Clone`.

## Macro helper attributes

Most of the derive macros support helper attributes:
Expand All @@ -91,7 +87,7 @@ Most of the derive macros support helper attributes:

#### `#[enumcapsulate(exclude(…))]`

Exclude this variant from trait derivation.
Selectively opt out of `enumcapsulate` trait derivations.

- `#[enumcapsulate(exclude(…))]`

Expand All @@ -109,6 +105,40 @@ then you can do so by use of an `#[enumcapsulate(exclude(…))]` attribute:
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:

```rust
#[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:

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

### Variant attributes

> [!NOTE]
Expand All @@ -127,6 +157,24 @@ Exclude this variant from trait derivation.

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:

```rust
#[derive(Encapsulate)]
enum Enum {
Expand All @@ -143,20 +191,6 @@ enum Enum {
}
```

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`

#### `#[enumcapsulate(field(… = …)]`

Select a specific variant field as target for trait derivation.
Expand All @@ -169,6 +203,21 @@ Select a specific variant field as target for trait derivation.

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`

```rust
#[derive(Encapsulate)]
enum Enum {
Expand All @@ -188,19 +237,89 @@ enum Enum {
>
> Alternatively the variant can be excluded via `#[enumcapsulate(exclude)]`.

This attribute is recognized by the following variant-based derive macros:
##### `#[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:

```rust
#[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:

```rust
#[derive(VariantDiscriminant)]
enum Enum {
#[enumcapsulate(discriminant(name = CustomDiscriminant))]
VariantA(i32),

VariantB { b: u32 },
}
```

- `AsVariant`
- `AsVariantMut`
- `AsVariantRef`
- `FromVariant`
- `IntoVariant`
- `From`
- `TryInto`
##### `#[enumcapsulate(discriminant(value = …))]`

… as well as the umbrella derive macro:
Specify a memory representation for the generated discriminant type.

- `Encapsulate`
> [!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:

```rust
#[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:

```rust
#[derive(VariantDiscriminant)]
enum Enum {
#[enumcapsulate(discriminant(name = CustomDiscriminant))]
VariantA(i32),

VariantB { b: u32 },
}
```

## Generics

Expand Down
5 changes: 4 additions & 1 deletion macros/src/config/for_enum.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
mod discriminant;
mod encapsulate;
mod standard;
mod variant_discriminant;

pub(crate) use self::encapsulate::EncapsulateDeriveEnumConfig;
pub(crate) use self::variant_discriminant::VariantDiscriminantDeriveEnumConfig;

use self::standard::EnumConfig;
use self::{discriminant::DiscriminantConfig, standard::EnumConfig};

pub(crate) type FromDeriveEnumConfig = EnumConfig;
pub(crate) type TryIntoDeriveEnumConfig = EnumConfig;
Expand Down
45 changes: 45 additions & 0 deletions macros/src/config/for_enum/discriminant.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use syn::meta::ParseNestedMeta;

use crate::attr::{NAME, REPR};

#[derive(Clone, Default)]
pub(crate) struct DiscriminantConfig {
repr: Option<syn::Type>,
ident: Option<syn::Ident>,
}

impl DiscriminantConfig {
pub(crate) fn parse(
&mut self,
meta: &ParseNestedMeta,
_item_enum: &syn::ItemEnum,
) -> Result<(), syn::Error> {
meta.parse_nested_meta(|meta| {
if meta.path.is_ident(REPR) {
if self.repr.is_some() {
return Err(meta.error("repr already specified"));
}

self.repr = Some(meta.value()?.parse()?);
} else if meta.path.is_ident(NAME) {
if self.ident.is_some() {
return Err(meta.error("name already specified"));
}

self.ident = Some(meta.value()?.parse()?);
} else {
return Err(meta.error("unsupported discriminant attribute"));
}

Ok(())
})
}

pub(crate) fn repr(&self) -> Option<&syn::Type> {
self.repr.as_ref()
}

pub(crate) fn ident(&self) -> Option<&syn::Ident> {
self.ident.as_ref()
}
}
40 changes: 40 additions & 0 deletions macros/src/config/for_enum/variant_discriminant.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use crate::{attr::DISCRIMINANT, parse_enumcapsulate_attrs};

use super::DiscriminantConfig;

#[derive(Clone, Default)]
pub(crate) struct VariantDiscriminantDeriveEnumConfig {
discriminant: Option<DiscriminantConfig>,
}

impl VariantDiscriminantDeriveEnumConfig {
pub(crate) fn from_enum(item_enum: &syn::ItemEnum) -> Result<Self, syn::Error> {
let mut this = Self::default();

parse_enumcapsulate_attrs(&item_enum.attrs, |meta| {
if meta.path.is_ident(DISCRIMINANT) {
let mut discriminant = this.discriminant.take().unwrap_or_default();

discriminant.parse(&meta, item_enum)?;

this.discriminant = Some(discriminant);
}

Ok(())
})?;

Ok(this)
}

pub fn repr(&self) -> Option<&syn::Type> {
self.discriminant
.as_ref()
.and_then(|discriminant| discriminant.repr())
}

pub fn ident(&self) -> Option<&syn::Ident> {
self.discriminant
.as_ref()
.and_then(|discriminant| discriminant.ident())
}
}
6 changes: 5 additions & 1 deletion macros/src/config/for_variant.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
mod discriminant;
mod standard;
mod variant_discriminant;

use self::standard::VariantConfig;
pub(crate) use self::variant_discriminant::VariantDiscriminantDeriveVariantConfig;

use self::{discriminant::DiscriminantConfig, standard::VariantConfig};

pub(crate) type FromDeriveVariantConfig = VariantConfig;
pub(crate) type TryIntoDeriveVariantConfig = VariantConfig;
Expand Down
45 changes: 45 additions & 0 deletions macros/src/config/for_variant/discriminant.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use syn::meta::ParseNestedMeta;

use crate::attr::{NAME, VALUE};

#[derive(Clone, Default)]
pub(crate) struct DiscriminantConfig {
expr: Option<syn::Expr>,
ident: Option<syn::Ident>,
}

impl DiscriminantConfig {
pub(crate) fn parse(
&mut self,
meta: &ParseNestedMeta,
_variant: &syn::Variant,
) -> Result<(), syn::Error> {
meta.parse_nested_meta(|meta| {
if meta.path.is_ident(VALUE) {
if self.expr.is_some() {
return Err(meta.error("value already specified"));
}

self.expr = Some(meta.value()?.parse()?);
} else if meta.path.is_ident(NAME) {
if self.ident.is_some() {
return Err(meta.error("name already specified"));
}

self.ident = Some(meta.value()?.parse()?);
} else {
return Err(meta.error("unsupported discriminant attribute"));
}

Ok(())
})
}

pub(crate) fn expr(&self) -> Option<&syn::Expr> {
self.expr.as_ref()
}

pub(crate) fn ident(&self) -> Option<&syn::Ident> {
self.ident.as_ref()
}
}
Loading
Loading