modrpc_codegen/
ast.rs

1use crate::Database;
2
3#[derive(Clone, Debug, Eq, PartialEq, Hash)]
4pub struct Schema {
5    pub imports: Vec<Import>,
6    pub interfaces: Vec<Interface>,
7    pub type_defs: Vec<mproto_codegen::ast::TypeDef>,
8}
9
10#[derive(Clone, Debug, Eq, PartialEq, Hash)]
11pub struct Import {
12    pub name: String,
13    pub path: String,
14}
15
16#[derive(Clone, Debug, Eq, PartialEq, Hash)]
17pub struct Interface {
18    pub name: String,
19    pub type_params: Vec<String>,
20    pub roles: Vec<String>,
21
22    pub events: Vec<InterfaceEventsList>,
23    pub objects: Vec<InterfaceObject>,
24    pub config: Vec<InterfaceConfigList>,
25    pub required_impls: Vec<InterfaceRequiredImplsList>,
26    pub methods: Vec<ObjectMethodsList>,
27    pub state: Vec<InterfaceState>,
28}
29
30#[derive(Clone, Debug, Eq, PartialEq, Hash)]
31pub struct InterfaceEventsList {
32    pub from_roles: Vec<String>,
33    pub to_roles: Vec<String>,
34    pub events: Vec<InterfaceEvent>,
35}
36
37#[derive(Clone, Debug, Eq, PartialEq, Hash)]
38pub struct InterfaceEvent {
39    pub name: String,
40    pub ty: mproto_codegen::ast::Type,
41    pub is_private: bool,
42}
43
44#[derive(Clone, Debug, Eq, PartialEq, Hash)]
45pub struct InterfaceState {
46    pub name: String,
47    pub ty: mproto_codegen::ast::Type,
48}
49
50#[derive(Clone, Debug, Eq, PartialEq, Hash)]
51pub struct InterfaceObject {
52    pub name: String,
53    pub construct: QualifiedIdentifier,
54    pub type_args: Vec<mproto_codegen::ast::Type>,
55    pub role_args: Vec<String>,
56}
57
58#[derive(Clone, Debug, Eq, PartialEq, Hash)]
59pub struct InterfaceConfigList {
60    pub roles: Vec<String>,
61    pub items: Vec<InterfaceConfigItem>,
62}
63
64#[derive(Clone, Debug, Eq, PartialEq, Hash)]
65pub struct InterfaceConfigItem {
66    pub name: String,
67    pub ty: mproto_codegen::ast::Type,
68}
69
70#[derive(Clone, Debug, Eq, PartialEq, Hash)]
71pub struct InterfaceRequiredImplsList {
72    pub roles: Vec<String>,
73    pub required_impls: Vec<InterfaceRequiredImpl>,
74}
75
76#[derive(Clone, Debug, Eq, PartialEq, Hash)]
77pub struct InterfaceRequiredImpl {
78    pub name: String,
79    pub is_async: bool,
80    pub input_ty: mproto_codegen::ast::Type,
81    pub output_ty: mproto_codegen::ast::Type,
82}
83
84#[derive(Clone, Debug, Eq, PartialEq, Hash)]
85pub struct ObjectMethodsList {
86    pub roles: Vec<String>,
87    pub methods: Vec<ObjectMethod>,
88}
89
90#[derive(Clone, Debug, Eq, PartialEq, Hash)]
91pub struct ObjectMethod {
92    pub name: String,
93    pub is_async: bool,
94    pub input_ty: mproto_codegen::ast::Type,
95    pub output_ty: mproto_codegen::ast::Type,
96}
97
98#[derive(Clone, Debug, Eq, PartialEq, Hash)]
99pub struct QualifiedIdentifier {
100    pub name: String,
101    pub module: Option<String>,
102}
103
104impl QualifiedIdentifier {
105    pub fn local(name: impl Into<String>) -> Self {
106        Self {
107            name: name.into(),
108            module: None,
109        }
110    }
111}
112
113impl Interface {
114    pub fn requires_impls_for_role(&self, role_name: &str) -> bool {
115        if self.has_public_event_impls_for_role(role_name) {
116            return true;
117        }
118
119        for required_impls in &self.required_impls {
120            if required_impls
121                .roles
122                .iter()
123                .find(|x| x == &role_name)
124                .is_some()
125            {
126                return true;
127            }
128        }
129
130        false
131    }
132
133    pub fn has_public_event_impls_for_role(&self, role_name: &str) -> bool {
134        for events_list in &self.events {
135            if events_list.events.len() > 0 {
136                if events_list
137                    .to_roles
138                    .iter()
139                    .find(|x| x == &role_name)
140                    .is_some()
141                {
142                    for event in &events_list.events {
143                        if !event.is_private {
144                            return true;
145                        }
146                    }
147                }
148            }
149        }
150
151        false
152    }
153
154    pub fn has_private_event_impls_for_role(&self, role_name: &str) -> bool {
155        for events_list in &self.events {
156            if events_list.events.len() > 0 {
157                if events_list
158                    .to_roles
159                    .iter()
160                    .find(|x| x == &role_name)
161                    .is_some()
162                {
163                    for event in &events_list.events {
164                        if event.is_private {
165                            return true;
166                        }
167                    }
168                }
169            }
170        }
171
172        false
173    }
174
175    pub fn has_methods_for_role(&self, role_name: &str) -> bool {
176        for methods_list in &self.methods {
177            if methods_list.methods.len() > 0 {
178                if methods_list
179                    .roles
180                    .iter()
181                    .find(|x| x == &role_name)
182                    .is_some()
183                {
184                    return true;
185                }
186            }
187        }
188
189        false
190    }
191
192    pub fn has_impls_for_role(&self, role_name: &str) -> bool {
193        for required_impls in &self.required_impls {
194            if required_impls
195                .roles
196                .iter()
197                .find(|x| x == &role_name)
198                .is_some()
199            {
200                return true;
201            }
202        }
203
204        false
205    }
206
207    pub fn has_config_for_role(&self, role_name: &str) -> bool {
208        for config_list in &self.config {
209            if config_list.roles.iter().find(|x| x == &role_name).is_some() {
210                return true;
211            }
212        }
213
214        false
215    }
216
217    pub fn has_state(&self, db: &Database) -> bool {
218        if self.state.len() > 0 {
219            return true;
220        }
221
222        let mut has_state = false;
223
224        for object in &self.objects {
225            if let Some(object_interface) = db.lookup_interface(&object.construct) {
226                has_state |= object_interface.has_state(db);
227            } else {
228                panic!(
229                    "Interface::has_state failed to lookup interface {:?}",
230                    object.construct
231                );
232            }
233        }
234
235        has_state
236    }
237}
238
239impl InterfaceObject {
240    /// Return the role in the object's interface used by the specified role in the interface the
241    /// object appears in (a.k.a. the parent).
242    pub fn get_role_for_parent_role<'a>(
243        &self,
244        object_interface: &'a Interface,
245        parent_role_name: &str,
246    ) -> Option<&'a String> {
247        let role_arg_index = self
248            .role_args
249            .iter()
250            .enumerate()
251            .find(|(_, role_arg_name)| &parent_role_name == role_arg_name)
252            .map(|(i, _)| i)?;
253
254        Some(&object_interface.roles[role_arg_index])
255    }
256
257    /// Return the roles in the object's interface used by the specified role in the interface the
258    /// object appears in (a.k.a. the parent).
259    pub fn get_roles_for_parent_role<'a>(
260        &self,
261        object_interface: &'a Interface,
262        parent_role_name: &str,
263    ) -> Vec<&'a String> {
264        self.role_args
265            .iter()
266            .enumerate()
267            .filter(move |(_, role_arg_name)| &parent_role_name == role_arg_name)
268            .map(|(role_arg_index, _)| &object_interface.roles[role_arg_index])
269            .collect()
270    }
271}