instability/
item_like.rs

1use syn::Visibility;
2
3pub trait Stability {
4    #[allow(unused)]
5    fn attrs(&self) -> &[syn::Attribute];
6
7    fn push_attr(&mut self, attr: syn::Attribute);
8}
9
10pub trait ItemLike: Stability {
11    fn visibility(&self) -> &Visibility;
12
13    fn set_visibility(&mut self, visibility: Visibility);
14
15    fn is_public(&self) -> bool {
16        matches!(self.visibility(), Visibility::Public(_))
17    }
18
19    fn allowed_lints(&self) -> Vec<syn::Ident>;
20}
21
22/// Implement `ItemLike` for the given type.
23///
24/// This makes each of the syn::Item* types implement our `ItemLike` trait to make it possible to
25/// work with them in a more uniform way.
26///
27/// A single type can be passed to this macro, or multiple types can be passed at once.
28/// Each type can be passed with a list of lints that are allowed for that type (defaulting to
29/// `dead_code` if not specified).
30macro_rules! impl_item_like {
31    // run impl_item_like for each item in a list of items
32    ($($(#[allow($($lint:ident),*)])? $ty:ty ),+ ,) => {
33        $(
34            impl_item_like!($(#[allow($($lint),*)])? $ty );
35        )*
36    };
37
38    // run impl_item_like for a single item without any lints
39    ($ty:ty) => {
40        impl_item_like!(#[allow(dead_code)] $ty );
41    };
42
43    // Implement `ItemLike` for the given type.
44    (#[allow($($lint:ident),*)] $ty:ty) => {
45        impl Stability for $ty {
46            fn attrs(&self) -> &[syn::Attribute] {
47                &self.attrs
48            }
49
50            fn push_attr(&mut self, attr: syn::Attribute) {
51                self.attrs.push(attr);
52            }
53        }
54
55        impl ItemLike for $ty {
56            fn visibility(&self) -> &Visibility {
57                &self.vis
58            }
59
60            fn set_visibility(&mut self, visibility: Visibility) {
61                self.vis = visibility;
62            }
63
64            fn allowed_lints(&self) -> Vec<syn::Ident> {
65                vec![
66                    $(syn::Ident::new(stringify!($lint), proc_macro2::Span::call_site()),)*
67                ]
68            }
69        }
70    };
71
72}
73
74impl_item_like!(
75    syn::ItemType,
76    syn::ItemEnum,
77    syn::ItemFn,
78    syn::ItemMod,
79    syn::ItemTrait,
80    syn::ItemConst,
81    syn::ItemStatic,
82    #[allow(unused_imports)]
83    syn::ItemUse,
84);
85
86impl Stability for syn::ItemStruct {
87    fn attrs(&self) -> &[syn::Attribute] {
88        &self.attrs
89    }
90
91    fn push_attr(&mut self, attr: syn::Attribute) {
92        self.attrs.push(attr);
93    }
94}
95
96impl ItemLike for syn::ItemStruct {
97    fn visibility(&self) -> &Visibility {
98        &self.vis
99    }
100
101    fn set_visibility(&mut self, visibility: Visibility) {
102        // Also constrain visibility of all fields to be at most the given
103        // item visibility.
104        self.fields
105            .iter_mut()
106            .filter(|field| matches!(&field.vis, Visibility::Public(_)))
107            .for_each(|field| field.vis = visibility.clone());
108
109        self.vis = visibility;
110    }
111
112    fn allowed_lints(&self) -> Vec<syn::Ident> {
113        vec![syn::Ident::new("dead_code", proc_macro2::Span::call_site())]
114    }
115}
116
117impl Stability for syn::ItemImpl {
118    fn attrs(&self) -> &[syn::Attribute] {
119        &self.attrs
120    }
121
122    fn push_attr(&mut self, attr: syn::Attribute) {
123        self.attrs.push(attr);
124    }
125}