Skip to main content

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 { name: name.into(), module: None }
107    }
108}
109
110impl Interface {
111    pub fn requires_impls_for_role(&self, role_name: &str) -> bool {
112        if self.has_public_event_impls_for_role(role_name) {
113            return true;
114        }
115
116        for required_impls in &self.required_impls {
117            if required_impls.roles
118                .iter()
119                .find(|x| x == &role_name)
120                .is_some()
121            {
122                return true;
123            }
124        }
125
126        false
127    }
128
129    pub fn has_public_event_impls_for_role(&self, role_name: &str) -> bool {
130        for events_list in &self.events {
131            if events_list.events.len() > 0 {
132                if events_list.to_roles
133                    .iter()
134                    .find(|x| x == &role_name)
135                    .is_some()
136                {
137                    for event in &events_list.events {
138                        if !event.is_private {
139                            return true;
140                        }
141                    }
142                }
143            }
144        }
145
146        false
147    }
148
149    pub fn has_private_event_impls_for_role(&self, role_name: &str) -> bool {
150        for events_list in &self.events {
151            if events_list.events.len() > 0 {
152                if events_list.to_roles
153                    .iter()
154                    .find(|x| x == &role_name)
155                    .is_some()
156                {
157                    for event in &events_list.events {
158                        if event.is_private {
159                            return true;
160                        }
161                    }
162                }
163            }
164        }
165
166        false
167    }
168
169    pub fn has_methods_for_role(&self, role_name: &str) -> bool {
170        for methods_list in &self.methods {
171            if methods_list.methods.len() > 0 {
172                if methods_list.roles
173                    .iter()
174                    .find(|x| x == &role_name)
175                    .is_some()
176                {
177                    return true;
178                }
179            }
180        }
181
182        false
183    }
184
185    pub fn has_impls_for_role(&self, role_name: &str) -> bool {
186        for required_impls in &self.required_impls {
187            if required_impls.roles
188                .iter()
189                .find(|x| x == &role_name)
190                .is_some()
191            {
192                return true;
193            }
194        }
195
196        false
197    }
198
199    pub fn has_config_for_role(&self, role_name: &str) -> bool {
200        for config_list in &self.config {
201            if config_list.roles
202                .iter()
203                .find(|x| x == &role_name)
204                .is_some()
205            {
206                return true;
207            }
208        }
209
210        false
211    }
212
213    pub fn has_state(&self, db: &Database) -> bool {
214        if self.state.len() > 0 { return true; }
215
216        let mut has_state = false;
217
218        for object in &self.objects {
219            if let Some(object_interface) = db.lookup_interface(&object.construct) {
220                has_state |= object_interface.has_state(db);
221            } else {
222                panic!("Interface::has_state failed to lookup interface {:?}", object.construct);
223            }
224        }
225
226        has_state
227    }
228}
229
230impl InterfaceObject {
231    /// Return the role in the object's interface used by the specified role in the interface the
232    /// object appears in (a.k.a. the parent).
233    pub fn get_role_for_parent_role<'a>(
234        &self,
235        object_interface: &'a Interface,
236        parent_role_name: &str,
237    ) -> Option<&'a String> {
238        let role_arg_index = self.role_args.iter().enumerate()
239            .find(|(_, role_arg_name)| &parent_role_name == role_arg_name)
240            .map(|(i, _)| i)?;
241
242        Some(&object_interface.roles[role_arg_index])
243    }
244
245    /// Return the roles in the object's interface used by the specified role in the interface the
246    /// object appears in (a.k.a. the parent).
247    pub fn get_roles_for_parent_role<'a>(
248        &self,
249        object_interface: &'a Interface,
250        parent_role_name: &str,
251    ) -> Vec<&'a String> {
252        self.role_args.iter().enumerate()
253            .filter(move |(_, role_arg_name)| &parent_role_name == role_arg_name)
254            .map(|(role_arg_index, _)| &object_interface.roles[role_arg_index])
255            .collect()
256    }
257}
258