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}