i_slint_compiler/passes/
collect_structs_and_enums.rs1use crate::expression_tree::Expression;
7use crate::langtype::Type;
8use crate::object_tree::*;
9use smol_str::SmolStr;
10use std::collections::BTreeMap;
11use std::rc::Rc;
12
13pub fn collect_structs_and_enums(doc: &Document) {
15 let mut hash = BTreeMap::new();
16
17 for (_, exp) in doc.exports.iter() {
18 if let Some(ty) = exp.as_ref().right() {
19 maybe_collect_struct(ty, &mut hash);
20 }
21 }
22
23 doc.visit_all_used_components(|component| collect_types_in_component(component, &mut hash));
24
25 let mut used_types = doc.used_types.borrow_mut();
26 let used_struct_and_enums = &mut used_types.structs_and_enums;
27 *used_struct_and_enums = Vec::with_capacity(hash.len());
28 while let Some(next) = hash.iter().next() {
29 let key = next.0.clone();
31 sort_types(&mut hash, used_struct_and_enums, &key);
32 }
33}
34
35fn maybe_collect_struct(ty: &Type, hash: &mut BTreeMap<SmolStr, Type>) {
36 visit_declared_type(ty, &mut |name, sub_ty| {
37 hash.entry(name.clone()).or_insert_with(|| sub_ty.clone());
38 });
39}
40
41fn collect_types_in_component(root_component: &Rc<Component>, hash: &mut BTreeMap<SmolStr, Type>) {
42 recurse_elem_including_sub_components_no_borrow(root_component, &(), &mut |elem, _| {
43 for x in elem.borrow().property_declarations.values() {
44 maybe_collect_struct(&x.property_type, hash);
45 }
46 });
47
48 visit_all_expressions(root_component, |expr, _| {
49 expr.visit_recursive(&mut |expr| match expr {
50 Expression::Struct { ty, .. } => maybe_collect_struct(&Type::Struct(ty.clone()), hash),
51 Expression::Array { element_ty, .. } => maybe_collect_struct(element_ty, hash),
52 Expression::EnumerationValue(ev) => {
53 maybe_collect_struct(&Type::Enumeration(ev.enumeration.clone()), hash)
54 }
55 _ => (),
56 })
57 });
58}
59
60fn sort_types(hash: &mut BTreeMap<SmolStr, Type>, vec: &mut Vec<Type>, key: &str) {
63 let ty = if let Some(ty) = hash.remove(key) { ty } else { return };
64 if let Type::Struct(s) = &ty {
65 if let Some(name) = &s.name {
66 if name.contains("::") {
67 return;
70 }
71
72 for sub_ty in s.fields.values() {
73 visit_declared_type(sub_ty, &mut |name, _| sort_types(hash, vec, name));
74 }
75 }
76 }
77 vec.push(ty)
78}
79
80fn visit_declared_type(ty: &Type, visitor: &mut impl FnMut(&SmolStr, &Type)) {
82 match ty {
83 Type::Struct(s) => {
84 if s.node.is_some() {
85 if let Some(struct_name) = s.name.as_ref() {
86 visitor(struct_name, ty);
87 }
88 }
89 for sub_ty in s.fields.values() {
90 visit_declared_type(sub_ty, visitor);
91 }
92 }
93 Type::Array(x) => visit_declared_type(x, visitor),
94 Type::Function(function) | Type::Callback(function) => {
95 visit_declared_type(&function.return_type, visitor);
96 for a in &function.args {
97 visit_declared_type(a, visitor);
98 }
99 }
100 Type::Enumeration(en) => {
101 if en.node.is_some() {
102 visitor(&en.name, ty)
103 }
104 }
105 _ => {}
106 }
107}