An open API service indexing awesome lists of open source software.

https://github.com/robbepop/enum-tag

Proc. macro to generate C-like `enum` tags.
https://github.com/robbepop/enum-tag

Last synced: about 1 year ago
JSON representation

Proc. macro to generate C-like `enum` tags.

Awesome Lists containing this project

README

          

| Continuous Integration | Documentation | Crates.io |
|:----------------------:|:----------------:|:--------------------:|
| [![ci][1]][2] | [![docs][3]][4] | [![crates][5]][6] |

[1]: https://github.com/Robbepop/enum-tag/actions/workflows/rust.yml/badge.svg
[2]: https://github.com/Robbepop/enum-tag/actions/workflows/rust.yml
[3]: https://docs.rs/enum-tag/badge.svg
[4]: https://docs.rs/enum-tag
[5]: https://img.shields.io/crates/v/enum-tag.svg
[6]: https://crates.io/crates/enum-tag

# `#[derive(EnumTag)]`

This crate provides a proc. macro to derive the `EnumTag` trait for the given Rust `enum`.
The `#derive(EnumTag)` proc. macro only works on Rust `enum` types and generates both

- a C-like `enum` type with the same variants as the input Rust `enum`
but without all the associated data.
- a derived implementation of the `EnumTag` trait for the Rust `enum`

The derived `EnumTag` trait makes it possible to create instances of the generated
C-like `enum` type as well as link to its definition via `::Tag`.

## When is this useful?

This is mostly useful for crates that profit from having a distinct `enum` tag type
while at the same time hosting Rust `enum` types with lots of variants which would
make it burdensome to maintain the mirroring between both `enum` type and `enum` tag type.

The motivation for this crate was a Wasm interpreter that represents its instructions
as an enum but also wants to access the opcodes of the instructions without their data.
In this example the opcodes are the instruction `enum` tag.

## Example

```rust
use ::enum_tag::EnumTag;

#[derive(EnumTag)]
#[repr(u8)] // Rust needs this for `B = 42`
enum Foo {
A,
B = 42,
C(i32),
D(i32, i64),
E { a: i32 },
F { a: i32, b: i64 },
}

/// This is how we can access the generated C-like enum type and name it.
type FooTag = ::Tag;

assert_eq!(FooTag::A, Foo::A.tag());
assert_eq!(FooTag::B, Foo::B.tag());
assert_eq!(FooTag::C, Foo::C(1).tag());
assert_eq!(FooTag::D, Foo::D(2, 3).tag());
assert_eq!(FooTag::E, Foo::E { a: 4 }.tag());
assert_eq!(FooTag::F, Foo::F { a: 5, b: 6 }.tag());

assert_eq!(FooTag::B as u8, 42);
```

The above `#[derive(EnumTag)]` generates the following Rust code:

```rust
const _: () = {
#[derive(
::core::fmt::Debug,
::core::clone::Clone,
::core::marker::Copy,
::core::cmp::PartialEq,
::core::cmp::Eq,
::core::cmp::PartialOrd,
::core::cmp::Ord,
::core::hash::Hash,
)]
pub enum FooTag {
A,
B = 42,
C,
D,
E,
F,
}

impl ::enum_tag::EnumTag for Foo {
type Tag = FooTag;

fn tag(&self) -> ::Tag {
match self {
Self::A { .. } => ::Tag::A,
Self::B { .. } => ::Tag::B,
Self::C { .. } => ::Tag::C,
Self::D { .. } => ::Tag::D,
Self::E { .. } => ::Tag::E,
Self::F { .. } => ::Tag::F,
}
}
}
};
```