enum-tree-derive 0.1.0

Derive macros for the enum-tree crate
Documentation
use proc_macro::TokenStream;
use syn::{DeriveInput, parse_macro_input};
mod enum_from;
mod enum_tree;
mod into_ancestors;

/// Derive `From<Self>` for every enum mentioned in an
/// `#[ancestors(Parent::Variant)]` attribute.
///
/// For each `#[ancestors(Parent::Variant)]` attribute on the deriving type,
/// the macro emits:
///
/// ```text
/// impl ::core::convert::From<Self> for Parent {
///     fn from(child: Self) -> Parent {
///         Parent::Variant(::core::convert::Into::into(child))
///     }
/// }
/// ```
///
/// The body wraps the child via `Into::into`, so any compatible
/// `From`/`Into` chain already in scope is reused. List every parent the
/// type needs to reach directly; the macro does **not** transitively walk
/// the `#[ancestors(...)]` attributes on intermediate enums.
///
/// # Example
///
/// ```ignore
/// use enum_tree::{EnumFrom, IntoAncestors};
///
/// #[derive(EnumFrom)]
/// enum Fermion
/// {
///     Quark(#[enum_from(from)] Quark),
///     Charged(#[enum_from(from)] ChargedLepton),
///     Neutrino(#[enum_from(from)] Neutrino),
/// }
///
/// #[derive(EnumFrom)]
/// enum Quark
/// {
///     Up(#[enum_from(from)] UpQuark),
///     Charm(#[enum_from(from)] CharmQuark),
/// }
///
/// struct ChargedLepton;
/// struct Neutrino;
///
/// // Each leaf lists every ancestor it must reach directly.
/// #[derive(IntoAncestors)]
/// #[ancestors(Quark::Charm)]
/// #[ancestors(Fermion::Quark)]
/// struct CharmQuark;
///
/// #[derive(IntoAncestors)]
/// #[ancestors(Quark::Up)]
/// #[ancestors(Fermion::Quark)]
/// struct UpQuark;
///
/// let _: Quark = CharmQuark.into();
/// let _: Fermion = CharmQuark.into();
/// let _: Fermion = UpQuark.into();
/// ```
///
/// # Limitations
///
/// The macro does not have access to the parent enum's definition, so it
/// cannot emit a `where Self: ::core::convert::Into<...>` bound: the
/// payload type of `Parent::Variant` is unknown at derive time. If the
/// caller has not supplied a compatible `From`/`Into` chain, the
/// resulting type error appears inside the generated function body
/// instead of on the impl header.
#[proc_macro_derive(IntoAncestors, attributes(ancestors))]
pub fn derive_into_ancestors(input: TokenStream) -> TokenStream
{
    let input = parse_macro_input!(input as DeriveInput);
    TokenStream::from(into_ancestors::derive_into_ancestors(&input))
}

/// Create a const array with all possible values of an enum.
/// Target must be an `enum`, and each variant of the target must be of *nested unit type*.
/// A variant is of nested unit type if it is either:
///
/// a) a unit variant, or
/// b) an singleton tuple variant, whose inner type is compatible.
///
/// Variants annotated with `#[enum_tree(skip)]` are excluded.
#[proc_macro_derive(DeepVariants, attributes(ancestors, enum_tree))]
pub fn derive_deep_variants(input: TokenStream) -> TokenStream
{
    let input = parse_macro_input!(input as DeriveInput);
    TokenStream::from(enum_tree::derive_deep_variants(&input))
}

/// Derive From implementations for an enum from variants.
#[proc_macro_derive(EnumFrom, attributes(enum_from))]
pub fn derive_enum_from(input: TokenStream) -> TokenStream
{
    let input = parse_macro_input!(input as DeriveInput);
    TokenStream::from(enum_from::generate(&input))
}