aeiou_macros/
lib.rs

1// Copyright 2021 Vladislav Melnik
2// SPDX-License-Identifier: MIT
3
4// TODO: error handling
5
6#[proc_macro_derive(Effect, attributes(input))]
7pub fn derive_effect(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
8    let syn::DeriveInput { attrs, ident, .. } = syn::parse_macro_input!(input);
9
10    let input_ty = match attrs.iter().find(|a| a.path.is_ident("input")) {
11        Some(limit) => limit.parse_args::<syn::Type>().unwrap(),
12        None => panic!(),
13    };
14
15    let t = quote::quote! {
16        impl Effect for #ident {
17            type Input = #input_ty;
18        }
19    };
20    t.into()
21}
22
23#[proc_macro_derive(Composable, attributes(part))]
24pub fn derive_composable(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
25    let syn::DeriveInput { ident, data, .. } = syn::parse_macro_input!(input);
26
27    let it = match data {
28        syn::Data::Enum(e) => e.variants.into_iter().filter_map(|v| {
29            let ident = v.ident;
30            v.attrs
31                .into_iter()
32                .find(|a| a.path.is_ident("part"))
33                .map(|part| (part.parse_args::<syn::Type>().unwrap(), ident))
34        }),
35        _ => panic!(),
36    };
37    let (ty, id): (Vec<syn::Type>, Vec<syn::Ident>) = it.unzip();
38
39    let t = quote::quote! {
40        #(
41        impl Composable<#ty> for #ident {
42            fn take(output: &aeiou::Context<Self>) -> Option<#ty> {
43                match output.0.borrow_mut().take()? {
44                    #ident::#id(v) => Some(#ty(v)),
45                    _ => None,
46                }
47            }
48        }
49        )*
50    };
51    t.into()
52}