impl_opaque_macro/
lib.rs

1#![no_std]
2extern crate alloc;
3
4mod attr;
5mod expand;
6mod gen;
7
8use attr::Attr;
9use expand::{fn_field::FnFieldExpander, impl_field::ImplFieldExpander};
10use gen::{Field, Gen};
11use proc_macro::TokenStream;
12use quote::quote;
13use syn::{parse_macro_input, ImplItem, ImplItemFn, ItemImpl};
14
15#[proc_macro_attribute]
16pub fn opaque(attr: TokenStream, item: TokenStream) -> TokenStream {
17    let attr: Attr = parse_macro_input!(attr);
18    let mut block: ItemImpl = parse_macro_input!(item);
19
20    let impl_iter = {
21        let mut impl_expand = ImplFieldExpander::new();
22        impl_expand.expand(&mut block);
23
24        impl_expand.fields.into_iter().map(Into::<Field>::into)
25    };
26
27    let fn_iter = {
28        let mut fn_expand = FnFieldExpander::new();
29        for item in &mut block.items {
30            if let ImplItem::Fn(ImplItemFn { block, .. }) = item {
31                fn_expand.expand(block);
32            }
33        }
34
35        fn_expand.fields.into_iter().map(Into::<Field>::into)
36    };
37
38    let gen = Gen {
39        struct_attrs: block.attrs.drain(..).collect(),
40        attr,
41        ty: *block.self_ty.clone(),
42        generics: block.generics.clone(),
43        fields: impl_iter.chain(fn_iter).collect(),
44    };
45
46    TokenStream::from(quote!(
47        #gen
48
49        const _: () = {
50            use impl_opaque::field;
51            #block
52        };
53    ))
54}