1#![deny(missing_docs)]
12#![deny(warnings)]
13#![recursion_limit = "512"]
15
16extern crate proc_macro;
17
18use proc_macro::TokenStream;
19use std::rc::Rc;
20use syn::parse::Parse;
21use syn::Result;
22use synattra::ParseAttributes;
23
24pub trait Weave: ParseAttributes {
28 type MacroAttributes: Parse;
30
31 fn parse_macro_attributes(attrs: TokenStream) -> syn::Result<Self::MacroAttributes> {
35 Ok(syn::parse(attrs)?)
36 }
37
38 fn update_fn_block(
40 fn_def: &syn::ImplItemMethod,
41 main_attr: &Self::MacroAttributes,
42 fn_attr: &[Rc<<Self as ParseAttributes>::Type>],
43 ) -> Result<syn::Block>;
44}
45
46use indexmap::IndexMap;
47pub struct WovenImplBlock<M, F> {
49 pub woven_block: syn::ItemImpl,
51 pub main_attributes: M,
53 pub woven_fns: IndexMap<syn::Ident, Vec<Rc<F>>>,
55}
56
57pub fn weave_impl_block<W: Weave>(
61 attrs: TokenStream,
62 item: TokenStream,
63) -> Result<WovenImplBlock<W::MacroAttributes, <W as ParseAttributes>::Type>> {
64 let main_attributes = W::parse_macro_attributes(attrs)?;
65
66 let mut parsed_input: syn::ItemImpl = syn::parse(item)?;
67 let mut attrs = &mut parsed_input.attrs;
68 let main_extra_attributes: Vec<Rc<<W as ParseAttributes>::Type>> =
69 process_custom_attributes::<W, _, _>(&mut attrs, Rc::new)?;
70
71 let mut woven = indexmap::map::IndexMap::new();
72
73 for item in parsed_input.items.iter_mut() {
74 if let syn::ImplItem::Method(item_fn) = item {
75 let mut attrs = &mut item_fn.attrs;
76
77 let method_attrs = process_custom_attributes::<W, _, _>(&mut attrs, Rc::new)?;
78
79 if method_attrs.is_empty() {
80 continue;
81 }
82
83 let mut fn_attributes: Vec<Rc<<W as ParseAttributes>::Type>> =
84 main_extra_attributes.clone();
85 fn_attributes.extend(method_attrs);
86
87 item_fn.block = W::update_fn_block(item_fn, &main_attributes, &fn_attributes)?;
88
89 woven.insert(item_fn.sig.ident.clone(), fn_attributes);
90 }
91 }
92
93 Ok(WovenImplBlock {
94 woven_block: parsed_input,
95 main_attributes: main_attributes,
96 woven_fns: woven,
97 })
98}
99
100fn process_custom_attributes<W: ParseAttributes, R, F: Fn(W::Type) -> R>(
101 attrs: &mut Vec<syn::Attribute>,
102 f: F,
103) -> Result<Vec<R>> {
104 let (ours, theirs): (Vec<syn::Attribute>, Vec<syn::Attribute>) = attrs
105 .clone()
106 .into_iter()
107 .partition(|attr| attr.path.is_ident(W::fn_attr_name()));
108
109 *attrs = theirs;
110
111 let mut fn_attributes: Vec<R> = Vec::new();
112 for attr in ours.into_iter() {
113 let p = W::parse_attributes(attr.tokens)?;
114 fn_attributes.push(f(p));
115 }
116
117 Ok(fn_attributes)
118}