enum_tree_derive/lib.rs
1use proc_macro::TokenStream;
2use syn::{DeriveInput, parse_macro_input};
3mod enum_from;
4mod enum_tree;
5mod into_ancestors;
6
7/// Derive `From<Self>` for every enum mentioned in an
8/// `#[ancestors(Parent::Variant)]` attribute.
9///
10/// For each `#[ancestors(Parent::Variant)]` attribute on the deriving type,
11/// the macro emits:
12///
13/// ```text
14/// impl ::core::convert::From<Self> for Parent {
15/// fn from(child: Self) -> Parent {
16/// Parent::Variant(::core::convert::Into::into(child))
17/// }
18/// }
19/// ```
20///
21/// The body wraps the child via `Into::into`, so any compatible
22/// `From`/`Into` chain already in scope is reused. List every parent the
23/// type needs to reach directly; the macro does **not** transitively walk
24/// the `#[ancestors(...)]` attributes on intermediate enums.
25///
26/// # Example
27///
28/// ```ignore
29/// use enum_tree::{EnumFrom, IntoAncestors};
30///
31/// #[derive(EnumFrom)]
32/// enum Fermion
33/// {
34/// Quark(#[enum_from(from)] Quark),
35/// Charged(#[enum_from(from)] ChargedLepton),
36/// Neutrino(#[enum_from(from)] Neutrino),
37/// }
38///
39/// #[derive(EnumFrom)]
40/// enum Quark
41/// {
42/// Up(#[enum_from(from)] UpQuark),
43/// Charm(#[enum_from(from)] CharmQuark),
44/// }
45///
46/// struct ChargedLepton;
47/// struct Neutrino;
48///
49/// // Each leaf lists every ancestor it must reach directly.
50/// #[derive(IntoAncestors)]
51/// #[ancestors(Quark::Charm)]
52/// #[ancestors(Fermion::Quark)]
53/// struct CharmQuark;
54///
55/// #[derive(IntoAncestors)]
56/// #[ancestors(Quark::Up)]
57/// #[ancestors(Fermion::Quark)]
58/// struct UpQuark;
59///
60/// let _: Quark = CharmQuark.into();
61/// let _: Fermion = CharmQuark.into();
62/// let _: Fermion = UpQuark.into();
63/// ```
64///
65/// # Limitations
66///
67/// The macro does not have access to the parent enum's definition, so it
68/// cannot emit a `where Self: ::core::convert::Into<...>` bound: the
69/// payload type of `Parent::Variant` is unknown at derive time. If the
70/// caller has not supplied a compatible `From`/`Into` chain, the
71/// resulting type error appears inside the generated function body
72/// instead of on the impl header.
73#[proc_macro_derive(IntoAncestors, attributes(ancestors))]
74pub fn derive_into_ancestors(input: TokenStream) -> TokenStream
75{
76 let input = parse_macro_input!(input as DeriveInput);
77 TokenStream::from(into_ancestors::derive_into_ancestors(&input))
78}
79
80/// Create a const array with all possible values of an enum.
81/// Target must be an `enum`, and each variant of the target must be of *nested unit type*.
82/// A variant is of nested unit type if it is either:
83///
84/// a) a unit variant, or
85/// b) an singleton tuple variant, whose inner type is compatible.
86///
87/// Variants annotated with `#[enum_tree(skip)]` are excluded.
88#[proc_macro_derive(DeepVariants, attributes(ancestors, enum_tree))]
89pub fn derive_deep_variants(input: TokenStream) -> TokenStream
90{
91 let input = parse_macro_input!(input as DeriveInput);
92 TokenStream::from(enum_tree::derive_deep_variants(&input))
93}
94
95/// Derive From implementations for an enum from variants.
96#[proc_macro_derive(EnumFrom, attributes(enum_from))]
97pub fn derive_enum_from(input: TokenStream) -> TokenStream
98{
99 let input = parse_macro_input!(input as DeriveInput);
100 TokenStream::from(enum_from::generate(&input))
101}