urs_macros 0.1.1

urs utility library macros
Documentation
//! https://www.youtube.com/watch?v=SMCRQj9Hbx8

pub(crate) use syn::{parse::{Parse, ParseStream}, parse_macro_input};
pub(crate) use quote::{
    quote, ToTokens,
};

pub(crate)struct Comp {
    mapping: Mapping,
    for_if: ForIfClause
}

impl Parse for Comp {
    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
        Ok(Self {
            mapping: input.parse()?,
            for_if: input.parse()?
        })
    }
}

impl ToTokens for Comp {
    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
        let mapping = &self.mapping.0;
        let ForIfClause {
            pat,
            expr: it,
            conds
        } = &self.for_if;

        let conds = conds.iter().map(|c| {
            let i = &c.0;
            quote! {
                #i
            }
        });

        tokens.extend(quote! {
            ::core::iter::IntoIterator::into_iter(#it).filter_map(|#pat|{
                (true #(&& (#conds))*).then(|| #mapping)
            })
        });
    }
}

pub(crate) struct Mapping(syn::Expr);

impl Parse for Mapping {
    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
        Ok(Self(input.parse()?))
    }
}

pub(crate) struct ForIfClause {
    pat: Pattern,
    expr: syn::Expr,
    conds: Vec<Condition>,
}

impl Parse for ForIfClause {
    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
        input.parse::<syn::Token![for]>()?;
        let pat = input.parse()?;
        input.parse::<syn::Token![in]>()?;
        let expr = input.parse()?;
        let conds = parse_zero_or_more(input);

        Ok(Self { pat, expr, conds })
    }
}

pub(crate) struct Pattern(syn::Pat);

impl Parse for Pattern {
    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
        Ok(Self(syn::Pat::parse_single(input)?))
    }
}

impl ToTokens for Pattern {
    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
        self.0.to_tokens(tokens);
    }
}

pub(crate) struct Condition(syn::Expr);

impl Parse for Condition {
    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
        input.parse::<syn::Token![if]>()?;
        Ok(Self(input.parse()?))
    }
}

fn parse_zero_or_more<T: Parse>(input: ParseStream) -> Vec<T>
{
    let mut result = vec![];
    while let Ok(i) = input.parse() {
        result.push(i)
    }
    result
}