spire_enum_macros 1.2.0

Procedural macros distributed by the crate `spire_enum`.
Documentation
use super::*;

#[derive(Parse, ToTokens)]
pub struct InputImplInherent {
    attrs: Any<Attribute<SynMeta>>,
    defaultness: Optional<Token![default]>,
    unsafety: Optional<Token![unsafe]>,
    impl_token: Token![impl],
    generics: Optional<InputGenerics>,
    self_ty: Box<Type>,
    where_clause: Optional<WhereClause>,
    items: Brace<Any<InputImplItem>>,
}

pub fn run(input: InputImplInherent) -> Result<TokenStream> {
    let sane = sanitize_input(input)?;
    generate_output(sane)
}

struct SaneImplInherent {
    attrs: Any<Attribute<SynMeta>>,
    defaultness: Optional<Token![default]>,
    unsafety: Optional<Token![unsafe]>,
    impl_token: Token![impl],
    generics: Optional<SaneGenerics>,
    self_ty: Box<Type>,
    functions: Brace<Any<SaneMethod>>,
}

fn sanitize_input(input: InputImplInherent) -> Result<SaneImplInherent> {
    let InputImplInherent {
        attrs,
        defaultness,
        unsafety,
        impl_token,
        generics,
        self_ty,
        where_clause,
        items,
    } = input;

    let (brace, item_list) = items.into_parts();

    let generics = sanitize_generics(generics, where_clause)?;

    let sane_items = item_list
        .into_iter()
        .map(|item| {
            match item {
                InputImplItem::Fn(func) => sanitize_fn(func),
                InputImplItem::Type(assoc_type) => {
                    bail!(assoc_type => "Expected function.\n\
						Help: Associated types aren't supported in impl blocks that have the `delegate_impl` attribute.")
                }
                InputImplItem::Const(constant) => {
                    bail!(constant => "Expected function.\n\
						Help: Declare this constant in an impl block that doesn't have the `delegate_impl` attribute.")
                }
                InputImplItem::Macro(mac) => {
                    bail!(mac => "Expected function.\n\
						Help: Declare this macro in an impl block that doesn't have the `delegate_impl` attribute.")
                }
            }
        })
        .try_collect()?;

    Ok(SaneImplInherent {
        attrs,
        defaultness,
        unsafety,
        impl_token,
        generics,
        self_ty,
        functions: Brace::from((brace, sane_items)),
    })
}

fn sanitize_fn(input: Box<InputImplItemFn>) -> Result<SaneMethod> {
    let InputImplItemFn {
        attrs,
        vis,
        sig,
        body,
    } = *input;

    let semi_token = match body {
        InputImplItemFnBody::Block(block) => {
            bail!(block => "Function implementations aren't allowed. \
					The implementation will be generated by this macro.\n\
					Help: Replace this block with a `;` (semi-colon).")
        }
        InputImplItemFnBody::SemiColon(semi_token) => semi_token,
    };

    Ok(SaneMethod {
        attrs,
        vis,
        sig: sanitize_method_signature(sig)?,
        _semi_token: semi_token,
    })
}

fn generate_output(sane: SaneImplInherent) -> Result<TokenStream> {
    let SaneImplInherent {
        attrs,
        defaultness,
        unsafety: impl_unsafety,
        impl_token,
        generics: impl_generics,
        self_ty,
        functions,
    } = sane;

    let (impl_generics, impl_where_clause) = impl_generics.into_pair();

    let macro_ident = {
        let enum_ident = find_enum_ident(&self_ty)
            .ok_or_else(|| Error::new(self_ty.span(), "Could not find main ident in this type."))?;

        delegate_macro_ident(enum_ident)
    };

    let functions_tt = functions
        .into_inner()
        .into_iter()
        .map(|method| sane_method_output(method, &macro_ident))
        .try_collect::<_, Vec<_>, _>()?;

    Ok(quote! {
        #attrs
        #defaultness #impl_unsafety #impl_token #impl_generics #self_ty #impl_where_clause {
            #(#functions_tt)*
        }
    })
}