ligen_core/ir/
implementation.rs

1use crate::prelude::*;
2use crate::ir::{Attributes, Constant, Function, Identifier, Type};
3use crate::proc_macro;
4use proc_macro2::TokenStream;
5use std::convert::{TryFrom, TryInto};
6use syn::{parse2, ItemImpl};
7use crate::ir::processing::ReplaceIdentifier;
8
9#[derive(Debug, PartialEq, Clone)]
10/// Function Struct
11pub struct Implementation {
12    /// Attributes field.
13    pub attributes: Attributes,
14    /// Self field.
15    pub self_: Type,
16    /// Items field.
17    pub items: Vec<ImplementationItem>,
18}
19
20#[derive(Debug, PartialEq, Clone)]
21/// ImplItem Enum
22pub enum ImplementationItem {
23    /// Constant variant
24    Constant(Constant),
25    /// Method variant
26    Method(Function),
27}
28
29impl TryFrom<TokenStream> for Implementation {
30    type Error = Error;
31    fn try_from(tokenstream: TokenStream) -> Result<Self> {
32        parse2::<ItemImpl>(tokenstream)
33            .map_err(|_| "Failed to parse to Implementation.".into())
34            .and_then(|item| item.try_into())
35    }
36}
37
38impl TryFrom<proc_macro::TokenStream> for Implementation {
39    type Error = Error;
40    fn try_from(tokenstream: proc_macro::TokenStream) -> Result<Self> {
41        let tokenstream: TokenStream = tokenstream.into();
42        tokenstream.try_into()
43    }
44}
45
46impl TryFrom<syn::ImplItem> for ImplementationItem {
47    type Error = Error;
48    fn try_from(impl_item: syn::ImplItem) -> Result<Self> {
49        match impl_item {
50            syn::ImplItem::Const(impl_item_const) => Ok(Self::Constant(impl_item_const.into())),
51            syn::ImplItem::Method(impl_item_method) => Ok(Self::Method(impl_item_method.into())),
52            _ => Err("Only Const and Method Impl items are currently supported".into()),
53        }
54    }
55}
56
57impl TryFrom<ItemImpl> for Implementation {
58    type Error = Error;
59    fn try_from(item_impl: ItemImpl) -> Result<Self> {
60        if let syn::Type::Path(syn::TypePath { path, .. }) = *item_impl.self_ty {
61            Ok(Self {
62                attributes: Attributes {
63                    attributes: item_impl
64                        .attrs
65                        .into_iter()
66                        .map(|x| x.parse_meta().expect("Failed to parse Meta").into())
67                        .collect(),
68                },
69                self_: path.into(),
70                items: item_impl
71                    .items
72                    .into_iter()
73                    .map(|x| x.try_into().expect("Failed to convert from ImplItem"))
74                    .collect(),
75            })
76        } else {
77            Err("Impl Block Identifier not found".into())
78        }
79    }
80}
81
82impl Implementation {
83    /// Maps the dependencies in the method signatures.
84    pub fn dependencies(&self) -> Vec<Type> {
85        let mut deps: Vec<Type> = vec![];
86        for item in &self.items {
87            if let ImplementationItem::Method(method) = item {
88                method.inputs.clone().into_iter().for_each(|parameter| {
89                    if !deps.iter().any(|typ| typ == &parameter.type_) {
90                        deps.push(parameter.type_);
91                    }
92                });
93                if let Some(type_) = method.output.clone() {
94                    if !deps.iter().any(|typ| typ == &type_)
95                        && type_ != Type::Compound(Identifier::new("Self").into())
96                    {
97                        deps.push(type_);
98                    }
99                }
100            }
101        }
102        deps
103    }
104
105    /// Replace all the occurrences of `Self` by the real object name.
106    /// e.g.:
107    /// ```rust,compile_fail
108    /// impl Object {
109    ///     fn f(self: &Self) {}
110    /// }
111    /// ```
112    /// becomes
113    /// ```rust,compile_fail
114    /// impl Object {
115    ///     fn f(self: &Object) {}
116    /// }
117    /// ```
118    pub fn replace_self_with_explicit_names(&mut self) {
119        let identifier = self.self_.path().last();
120        let mut lower_case_identifier = identifier.clone();
121        lower_case_identifier.name = lower_case_identifier.name.to_lowercase();
122        self.replace_identifier(&Identifier::from("Self"), &identifier);
123    }
124}
125
126
127
128#[cfg(test)]
129mod test {
130    use std::convert::TryFrom;
131
132    use super::{
133        Attributes, Constant, Function, Identifier, Implementation, ImplementationItem, ItemImpl,
134    };
135    use crate::ir::{
136        Atomic, Attribute, Integer, Literal, Reference, ReferenceKind, Type, Visibility,
137    };
138    use quote::quote;
139    use syn::parse_quote::parse;
140
141    #[test]
142    fn impl_block() {
143        assert_eq!(
144            Implementation::try_from(parse::<ItemImpl>(quote! {impl Test {}}))
145                .expect("Failed to convert from ItemImpl"),
146            Implementation {
147                attributes: Attributes { attributes: vec![] },
148                self_: Type::Compound(Identifier::new("Test").into()),
149                items: vec![]
150            }
151        );
152    }
153
154    #[test]
155    fn impl_block_attributes() {
156        assert_eq!(
157            Implementation::try_from(parse::<ItemImpl>(quote! {
158                #[test(a = "b")]
159                impl Test {}
160            }))
161            .expect("Failed to convert from ItemImpl"),
162            Implementation {
163                attributes: Attributes {
164                    attributes: vec![Attribute::Group(
165                        Identifier::new("test"),
166                        Attributes {
167                            attributes: vec![Attribute::Named(
168                                Identifier::new("a"),
169                                Literal::String(String::from("b"))
170                            )]
171                        }
172                    )]
173                },
174                self_: Type::Compound(Identifier::new("Test").into()),
175                items: vec![]
176            }
177        );
178    }
179
180    #[test]
181    fn impl_block_items_const() {
182        assert_eq!(
183            Implementation::try_from(parse::<ItemImpl>(quote! {
184                impl Test {
185                    const a: i32 = 2;
186                }
187            }))
188            .expect("Failed to convert from ItemImpl"),
189            Implementation {
190                attributes: Attributes { attributes: vec![] },
191                self_: Type::Compound(Identifier::new("Test").into()),
192                items: vec![ImplementationItem::Constant(Constant {
193                    identifier: Identifier::new("a"),
194                    type_: Type::Atomic(Atomic::Integer(Integer::I32)),
195                    literal: Literal::Integer(2)
196                })]
197            }
198        );
199    }
200
201    #[test]
202    fn impl_block_items_method() {
203        assert_eq!(
204            Implementation::try_from(parse::<ItemImpl>(quote! {
205                impl Test {
206                    fn a(){}
207                }
208            }))
209            .expect("Failed to convert from ItemImpl"),
210            Implementation {
211                attributes: Attributes { attributes: vec![] },
212                self_: Type::Compound(Identifier::new("Test").into()),
213                items: vec![ImplementationItem::Method(Function {
214                    attributes: Attributes { attributes: vec![] },
215                    visibility: Visibility::Inherited,
216                    asyncness: None,
217                    identifier: Identifier::new("a"),
218                    inputs: vec![],
219                    output: None
220                })]
221            }
222        );
223    }
224
225    #[test]
226    fn impl_block_items() {
227        assert_eq!(
228            Implementation::try_from(parse::<ItemImpl>(quote! {
229                impl Test {
230                    const a: i32 = 2;
231                    fn b(){}
232                }
233            }))
234            .expect("Failed to convert from ItemImpl"),
235            Implementation {
236                attributes: Attributes { attributes: vec![] },
237                self_: Type::Compound(Identifier::new("Test").into()),
238                items: vec![
239                    ImplementationItem::Constant(Constant {
240                        identifier: Identifier::new("a"),
241                        type_: Type::Atomic(Atomic::Integer(Integer::I32)),
242                        literal: Literal::Integer(2)
243                    }),
244                    ImplementationItem::Method(Function {
245                        attributes: Attributes { attributes: vec![] },
246                        visibility: Visibility::Inherited,
247                        asyncness: None,
248                        identifier: Identifier::new("b"),
249                        inputs: vec![],
250                        output: None
251                    })
252                ]
253            }
254        );
255    }
256
257    #[test]
258    fn impl_block_dependencies() {
259        assert_eq!(
260            Implementation::try_from(parse::<ItemImpl>(quote! {
261                impl Person {
262                    pub fn new(name: FullName, age: Age) -> Self { ... }
263                    pub fn more_deps(age: Age, a: A, b: B, c: C) -> D;
264                    pub fn builtin(&self, age: i32, name: String, name_str: &str, vec: Vec<String>) -> Box<Rc<Mutex<Arc<HashMap<String, Option<Result<String, Error>>>>>>>;
265                }
266            }))
267            .expect("Failed to build implementation from TokenStream")
268            .dependencies(),
269            vec![
270                Type::Compound(Identifier::new("FullName").into()),
271                Type::Compound(Identifier::new("Age").into()),
272                Type::Compound(Identifier::new("A").into()),
273                Type::Compound(Identifier::new("B").into()),
274                Type::Compound(Identifier::new("C").into()),
275                Type::Compound(Identifier::new("D").into()),
276                Type::Reference(Reference {kind: ReferenceKind::Borrow, is_constant: true, type_: Box::new(Type::Compound(Identifier::new("Self").into()))}),
277                Type::Atomic(Atomic::Integer(Integer::I32)),
278                Type::Compound(Identifier::new("String").into()),
279                Type::Reference(Reference {kind: ReferenceKind::Borrow, is_constant: true, type_: Box::new(Type::Compound(Identifier::new("str").into()))}),
280                Type::Compound(Identifier::new("Vec").into()),
281                Type::Compound(Identifier::new("Box").into()),
282            ]
283        );
284    }
285}