use proc_macro::TokenStream;
use syn::{parse::Parse, Ident};
struct Composed {
function: Ident, others: Vec<Ident>, }
impl Parse for Composed {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let function = input.parse()?;
let mut others = Vec::new();
while input.parse::<syn::Token![->]>().is_ok() {
let other: Ident = input.parse()?;
others.push(other);
}
Ok(Composed { function, others })
}
}
impl quote::ToTokens for Composed {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
let func = &self.function;
if self.others.is_empty() {
func.to_tokens(tokens);
return;
}
let mut composed = quote::quote! {
#func(x)
};
for other in &self.others {
composed = quote::quote! {
#other(#composed)
};
}
composed.to_tokens(tokens);
}
}
#[proc_macro]
pub fn compose(input: TokenStream) -> TokenStream {
let composed = syn::parse_macro_input!(input as Composed);
let out = if composed.others.is_empty() {
quote::quote! {
#composed
}
} else {
quote::quote! {
|x| #composed
}
};
out.into()
}