sylvia_derive/
fold.rs

1use syn::fold::{self, Fold};
2use syn::punctuated::Punctuated;
3use syn::{
4    FnArg, ImplItemFn, ItemImpl, ItemTrait, PatType, Path, Receiver, Signature, Token, TraitItemFn,
5};
6
7use crate::parser::SylviaAttribute;
8
9/// Utility for stripping all attributes from input before it is emitted
10pub struct StripInput;
11
12fn remove_input_attr(inputs: Punctuated<FnArg, Token![,]>) -> Punctuated<FnArg, Token![,]> {
13    inputs
14        .into_iter()
15        .map(|input| match input {
16            syn::FnArg::Receiver(rec) if !rec.attrs.is_empty() => {
17                let rec = Receiver {
18                    attrs: vec![],
19                    ..rec
20                };
21                syn::FnArg::Receiver(rec)
22            }
23            syn::FnArg::Typed(ty) if !ty.attrs.is_empty() => {
24                let ty = PatType {
25                    attrs: vec![],
26                    ..ty
27                };
28                syn::FnArg::Typed(ty)
29            }
30            _ => input,
31        })
32        .collect()
33}
34
35impl Fold for StripInput {
36    fn fold_trait_item_fn(&mut self, i: TraitItemFn) -> TraitItemFn {
37        let attrs = i
38            .attrs
39            .into_iter()
40            .filter(|attr| SylviaAttribute::new(attr).is_none())
41            .collect();
42
43        let inputs = remove_input_attr(i.sig.inputs);
44        let sig = Signature { inputs, ..i.sig };
45        fold::fold_trait_item_fn(self, TraitItemFn { attrs, sig, ..i })
46    }
47
48    fn fold_impl_item_fn(&mut self, i: ImplItemFn) -> ImplItemFn {
49        let attrs = i
50            .attrs
51            .into_iter()
52            .filter(|attr| SylviaAttribute::new(attr).is_none())
53            .collect();
54
55        let inputs = remove_input_attr(i.sig.inputs);
56        let sig = Signature { inputs, ..i.sig };
57        fold::fold_impl_item_fn(self, ImplItemFn { attrs, sig, ..i })
58    }
59
60    fn fold_item_trait(&mut self, i: ItemTrait) -> ItemTrait {
61        let attrs = i
62            .attrs
63            .into_iter()
64            .filter(|attr| SylviaAttribute::new(attr).is_none())
65            .collect();
66
67        fold::fold_item_trait(self, ItemTrait { attrs, ..i })
68    }
69
70    fn fold_item_impl(&mut self, i: ItemImpl) -> ItemImpl {
71        let attrs = i
72            .attrs
73            .into_iter()
74            .filter(|attr| SylviaAttribute::new(attr).is_none())
75            .collect();
76
77        fold::fold_item_impl(self, ItemImpl { attrs, ..i })
78    }
79}
80
81/// Removes all generics from type assumning default values for it
82pub struct StripGenerics;
83
84impl Fold for StripGenerics {
85    fn fold_path_arguments(&mut self, _: syn::PathArguments) -> syn::PathArguments {
86        syn::PathArguments::None
87    }
88}
89
90/// Removes `Self` from associated type [Path].
91pub struct StripSelfPath;
92
93impl Fold for StripSelfPath {
94    fn fold_path(&mut self, path: Path) -> Path {
95        let segments = path
96            .segments
97            .into_iter()
98            .filter(|segment| segment.ident != "Self")
99            .collect();
100        syn::fold::fold_path(self, Path { segments, ..path })
101    }
102}