intercom_common/
ast_converters.rs

1use crate::prelude::*;
2use syn::{Attribute, FnArg, GenericArgument, Ident, Item, Pat, Path, Type};
3
4/// Extract the underlying Type from various AST types.
5pub trait GetType
6{
7    /// Gets the Type from the AST element.
8    fn get_ty(&self) -> Result<Type, String>;
9}
10
11impl GetType for FnArg
12{
13    fn get_ty(&self) -> Result<Type, String>
14    {
15        Ok(match *self {
16            FnArg::Receiver(_) => self_ty(),
17            FnArg::Typed(ref pat_type) => pat_type.ty.as_ref().to_owned(),
18        })
19    }
20}
21
22impl GetType for GenericArgument
23{
24    fn get_ty(&self) -> Result<Type, String>
25    {
26        match *self {
27            GenericArgument::Type(ref ty) => Ok(ty.clone()),
28            _ => Err("Expected type parameter".to_string()),
29        }
30    }
31}
32
33pub trait GetIdent
34{
35    /// Gets the Ident from the AST element.
36    fn get_ident(&self) -> Result<Ident, String>;
37}
38
39impl GetIdent for FnArg
40{
41    fn get_ident(&self) -> Result<Ident, String>
42    {
43        Ok(match *self {
44            FnArg::Receiver(_) => Ident::new("self", Span::call_site()),
45            FnArg::Typed(ref pat_type) => match *pat_type.pat {
46                Pat::Ident(ref pat_ident) => pat_ident.ident.clone(),
47                _ => return Err(format!("Unsupported argument: {:?}", self)),
48            },
49        })
50    }
51}
52
53impl GetIdent for Path
54{
55    fn get_ident(&self) -> Result<Ident, String>
56    {
57        self.segments
58            .last()
59            .map(|l| l.ident.clone())
60            .ok_or_else(|| "Empty path".to_owned())
61    }
62}
63
64impl GetIdent for Type
65{
66    fn get_ident(&self) -> Result<Ident, String>
67    {
68        match *self {
69            Type::Path(ref p) => p
70                .path
71                .get_ident()
72                .cloned()
73                .ok_or_else(|| format!("No Ident for {:?}", self)),
74            _ => Err(format!("Cannot get Ident for {:?}", self)),
75        }
76    }
77}
78
79impl GetIdent for Item
80{
81    fn get_ident(&self) -> Result<Ident, String>
82    {
83        Ok(match *self {
84            Item::ExternCrate(ref i) => i.ident.clone(),
85            Item::Static(ref i) => i.ident.clone(),
86            Item::Const(ref i) => i.ident.clone(),
87            Item::Fn(ref i) => i.sig.ident.clone(),
88            Item::Mod(ref i) => i.ident.clone(),
89            Item::Type(ref i) => i.ident.clone(),
90            Item::Struct(ref i) => i.ident.clone(),
91            Item::Enum(ref i) => i.ident.clone(),
92            Item::Union(ref i) => i.ident.clone(),
93            Item::Trait(ref i) => i.ident.clone(),
94            Item::Impl(ref i) => i.self_ty.get_ident()?,
95            Item::Macro(ref m) => m
96                .mac
97                .path
98                .get_ident()
99                .cloned()
100                .ok_or_else(|| format!("No ident on {:?}", self))?,
101            Item::Macro2(ref i) => i.ident.clone(),
102            Item::TraitAlias(ref i) => i.ident.clone(),
103
104            Item::Use(..) | Item::ForeignMod(..) | Item::Verbatim(..) => {
105                return Err("Item type not supported for Ident".to_string())
106            }
107            _ => panic!(),
108        })
109    }
110}
111
112pub trait GetAttributes
113{
114    /// Gets the Attributes from the AST element.
115    fn get_attributes(&self) -> Result<Vec<Attribute>, String>;
116}
117
118impl GetAttributes for Item
119{
120    fn get_attributes(&self) -> Result<Vec<Attribute>, String>
121    {
122        Ok(match *self {
123            Item::ExternCrate(ref i) => i.attrs.clone(),
124            Item::Static(ref i) => i.attrs.clone(),
125            Item::Const(ref i) => i.attrs.clone(),
126            Item::Fn(ref i) => i.attrs.clone(),
127            Item::Mod(ref i) => i.attrs.clone(),
128            Item::Type(ref i) => i.attrs.clone(),
129            Item::Struct(ref i) => i.attrs.clone(),
130            Item::Enum(ref i) => i.attrs.clone(),
131            Item::Union(ref i) => i.attrs.clone(),
132            Item::Trait(ref i) => i.attrs.clone(),
133            Item::Impl(ref i) => i.attrs.clone(),
134            Item::Macro(ref i) => i.attrs.clone(),
135            Item::Macro2(ref i) => i.attrs.clone(),
136            Item::Use(ref i) => i.attrs.clone(),
137            Item::ForeignMod(ref i) => i.attrs.clone(),
138            Item::TraitAlias(ref i) => i.attrs.clone(),
139            Item::Verbatim(..) => vec![],
140            _ => panic!(),
141        })
142    }
143}
144
145pub trait ReplaceIdent: Sized
146{
147    fn map_ident(&self, f: impl FnOnce(&Ident) -> String) -> Result<Self, String>;
148}
149
150impl ReplaceIdent for syn::Path
151{
152    fn map_ident(&self, f: impl FnOnce(&Ident) -> String) -> Result<Self, String>
153    {
154        let mut result = self.clone();
155        let mut last = result
156            .segments
157            .last_mut()
158            .ok_or_else(|| format!("Path {:?} is empty", self))?;
159        last.ident = Ident::new(&f(&last.ident), Span::call_site());
160        Ok(result)
161    }
162}
163
164fn self_ty() -> Type
165{
166    parse_quote!(Self)
167}