enum_tag_macro/lib.rs
1use proc_macro::TokenStream;
2use syn::{parse_macro_input, DeriveInput};
3
4#[macro_use]
5mod error;
6mod derive;
7
8/// Proc. macro to derive the `EnumTag` trait for the given Rust `enum`.
9///
10/// This proc. macro only works on Rust `enum` types and creates a C-like
11/// `enum` with the same variants as the input Rust `enum` without all the
12/// associated data.
13/// Also it derives an implementation of `EnumTag` for the Rust `enum` that
14/// makes it possible to create instances of the generated C-like `enum` as
15/// well as link to its identifier via `<RustEnum as EnumTag>::Tag`.
16///
17/// # Example
18///
19/// ```
20/// use enum_tag::EnumTag;
21///
22/// #[derive(EnumTag)]
23/// #[repr(u8)] // Rust needs this for `B = 42`
24/// enum Foo {
25/// A,
26/// B = 42,
27/// C(i32),
28/// D(i32, i64),
29/// E { a: i32 },
30/// F { a: i32, b: i64 },
31/// }
32///
33/// /// This is how we can access the generated C-like enum type and name it.
34/// type FooTag = <Foo as EnumTag>::Tag;
35///
36/// assert_eq!(FooTag::A, Foo::A.tag());
37/// assert_eq!(FooTag::B, Foo::B.tag());
38/// assert_eq!(FooTag::C, Foo::C(1).tag());
39/// assert_eq!(FooTag::D, Foo::D(2, 3).tag());
40/// assert_eq!(FooTag::E, Foo::E { a: 4 }.tag());
41/// assert_eq!(FooTag::F, Foo::F { a: 5, b: 6 }.tag());
42///
43/// assert_eq!(FooTag::B as u8, 42);
44/// ```
45///
46/// The above `#[derive(EnumTag)]` proc. macro will expand to roughly the following Rust code:
47///
48/// ```
49/// # #[repr(u8)] // Rust needs this for `B = 42`
50/// # enum Foo {
51/// # A,
52/// # B = 42,
53/// # C(i32),
54/// # D(i32, i64),
55/// # E { a: i32 },
56/// # F { a: i32, b: i64 },
57/// # }
58/// #
59/// const _: () = {
60/// #[derive(
61/// ::core::fmt::Debug,
62/// ::core::clone::Clone,
63/// ::core::marker::Copy,
64/// ::core::cmp::PartialEq,
65/// ::core::cmp::Eq,
66/// ::core::cmp::PartialOrd,
67/// ::core::cmp::Ord,
68/// ::core::hash::Hash,
69/// )]
70/// pub enum FooTag {
71/// A,
72/// B = 42,
73/// C,
74/// D,
75/// E,
76/// F,
77/// }
78///
79/// impl ::enum_tag::EnumTag for Foo {
80/// type Tag = FooTag;
81///
82/// fn tag(&self) -> <Self as ::enum_tag::EnumTag>::Tag {
83/// match self {
84/// Self::A { .. } => <Self as ::enum_tag::EnumTag>::Tag::A,
85/// Self::B { .. } => <Self as ::enum_tag::EnumTag>::Tag::B,
86/// Self::C { .. } => <Self as ::enum_tag::EnumTag>::Tag::C,
87/// Self::D { .. } => <Self as ::enum_tag::EnumTag>::Tag::D,
88/// Self::E { .. } => <Self as ::enum_tag::EnumTag>::Tag::E,
89/// Self::F { .. } => <Self as ::enum_tag::EnumTag>::Tag::F,
90/// }
91/// }
92/// }
93/// };
94/// ```
95#[proc_macro_derive(EnumTag)]
96pub fn enum_tag(input: TokenStream) -> TokenStream {
97 derive::enum_tag(parse_macro_input!(input as DeriveInput)).into()
98}