impl_opaque_macro/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
mod attr;
mod expand;
mod gen;

use attr::Attr;
use expand::{fn_field::FnFieldExpander, impl_field::ImplFieldExpander};
use gen::{Field, Gen};
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, ImplItem, ImplItemFn, ItemImpl};

#[proc_macro_attribute]
pub fn opaque(attr: TokenStream, item: TokenStream) -> TokenStream {
    let attr: Attr = parse_macro_input!(attr);
    let mut block: ItemImpl = parse_macro_input!(item);

    let impl_iter = {
        let mut impl_expand = ImplFieldExpander::new();
        impl_expand.expand(&mut block);

        impl_expand.fields.into_iter().map(Into::<Field>::into)
    };

    let fn_iter = {
        let mut fn_expand = FnFieldExpander::new();
        for item in &mut block.items {
            if let ImplItem::Fn(ImplItemFn { block, .. }) = item {
                fn_expand.expand(block);
            }
        }

        fn_expand.fields.into_iter().map(Into::<Field>::into)
    };

    let gen = Gen {
        struct_attrs: block.attrs.drain(..).collect(),
        attr,
        ty: *block.self_ty.clone(),
        generics: block.generics.clone(),
        fields: impl_iter.chain(fn_iter).collect(),
    };

    TokenStream::from(quote!(
        #gen
        #block
    ))
}