odra_ir/module_item/
module_impl.rs1use std::convert::TryFrom;
2
3use proc_macro2::Ident;
4use syn::parse_quote;
5
6use crate::module::{Constructor, Method};
7
8use super::{delegate::Delegate, impl_item::ImplItem};
9
10pub struct ModuleImpl {
29 impl_items: Vec<ImplItem>,
30 ident: Ident,
31 is_trait_implementation: bool
32}
33
34impl ModuleImpl {
35 pub fn impl_items(&self) -> &[ImplItem] {
36 self.impl_items.as_ref()
37 }
38
39 pub fn ident(&self) -> &Ident {
40 &self.ident
41 }
42
43 pub fn custom_impl_items(&self) -> Vec<&ImplItem> {
44 self.impl_items
45 .iter()
46 .filter(|i| matches!(i, ImplItem::Method(_) | ImplItem::Constructor(_)))
47 .collect::<Vec<_>>()
48 }
49
50 pub fn get_public_method_iter(&self) -> impl Iterator<Item = &Method> {
51 self.impl_items
52 .iter()
53 .filter_map(|item| match item {
54 ImplItem::Method(method) => Some(method),
55 _ => None
56 })
57 .filter(|m| self.is_trait_implementation || m.is_public())
58 }
59
60 pub fn get_constructor_iter(&self) -> impl Iterator<Item = &Constructor> {
61 self.impl_items.iter().filter_map(|item| match item {
62 ImplItem::Constructor(c) => Some(c),
63 _ => None
64 })
65 }
66
67 pub fn public_custom_impl_items(&self) -> Vec<&ImplItem> {
68 self.impl_items
69 .iter()
70 .filter(|item| match item {
71 ImplItem::Constructor(_) => true,
72 ImplItem::Method(m) => self.is_trait_implementation || m.is_public(),
73 ImplItem::Other(_) => false
74 })
75 .collect::<Vec<_>>()
76 }
77
78 pub fn is_trait_implementation(&self) -> bool {
79 self.is_trait_implementation
80 }
81}
82
83impl TryFrom<syn::ItemImpl> for ModuleImpl {
84 type Error = syn::Error;
85
86 fn try_from(item_impl: syn::ItemImpl) -> Result<Self, Self::Error> {
87 let is_trait_implementation = item_impl.trait_.is_some();
88 let path = match &*item_impl.self_ty {
89 syn::Type::Path(path) => path,
90 _ => todo!()
91 };
92 let contract_ident = path.path.segments.last().unwrap().clone().ident;
93
94 let delegation_stmts = item_impl
95 .items
96 .clone()
97 .into_iter()
98 .filter_map(|item| match item {
99 syn::ImplItem::Macro(macro_item) => Some(macro_item),
100 _ => None
101 })
102 .map(|macro_item| syn::parse2::<Delegate>(macro_item.mac.tokens))
103 .collect::<Result<Vec<_>, syn::Error>>()?;
104
105 let delegation_stmts = delegation_stmts
106 .into_iter()
107 .flat_map(|d| d.stmts)
108 .collect::<Vec<_>>();
109
110 let delegated_items = delegation_stmts
111 .into_iter()
112 .flat_map(|stmt| {
113 let to = stmt.delegate_to;
114 stmt.delegation_block
115 .functions
116 .iter()
117 .map(|func| {
118 let attrs = &func.attrs;
119 let sig = &func.full_sig;
120 let vis = &func.visibility;
121 let ident = &func.ident;
122 let args = &func
123 .args
124 .iter()
125 .map(|ty| ty.pat.clone())
126 .collect::<Vec<_>>();
127
128 parse_quote! {
129 #(#attrs)*
130 #vis #sig { #to.#ident(#(#args),*) }
131 }
132 })
133 .collect::<Vec<syn::ImplItem>>()
134 })
135 .map(<ImplItem as TryFrom<_>>::try_from)
136 .collect::<Result<Vec<_>, syn::Error>>()?;
137
138 let mut items = item_impl
139 .items
140 .into_iter()
141 .filter(|item| !matches!(item, syn::ImplItem::Macro(_)))
142 .map(<ImplItem as TryFrom<_>>::try_from)
143 .collect::<Result<Vec<_>, syn::Error>>()?;
144
145 items.extend(delegated_items);
146
147 Ok(Self {
148 impl_items: items,
149 ident: contract_ident,
150 is_trait_implementation
151 })
152 }
153}
154
155#[cfg(test)]
156mod test {
157 use super::ModuleImpl;
158
159 #[test]
160 fn impl_items_filtering() {
161 let item_impl: syn::ItemImpl = syn::parse_quote! {
162 impl Contract {
163
164 #[odra(init)]
165 pub fn constructor() {}
166
167 pub(crate) fn crate_public_fn() {}
168
169 pub fn public_fn() {}
170
171 fn private_fn() {}
172
173 delegate! {
174 to self.a {
175 pub fn public_fn_del(&self);
176 pub fn private_fn_del(&self);
177 }
178 }
179 }
180 };
181 let module_impl = ModuleImpl::try_from(item_impl).unwrap();
182
183 assert_eq!(module_impl.custom_impl_items().len(), 6);
184 assert_eq!(module_impl.public_custom_impl_items().len(), 4);
185 }
186}