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 used_types.structs_and_enums = Vec::with_capacity(hash.len());
27 while let Some(next) = hash.iter().next() {
28 let key = next.0.clone();
29 if let Some(library_info) = doc.library_exports.get(key.as_str()) {
30 hash.remove(&key);
32 used_types.library_types_imports.push((key, library_info.clone()));
33 continue;
34 }
35
36 let used_struct_and_enums = &mut used_types.structs_and_enums;
38 sort_types(&mut hash, used_struct_and_enums, &key);
39 }
40}
41
42fn maybe_collect_struct(ty: &Type, hash: &mut BTreeMap<SmolStr, Type>) {
43 visit_declared_type(ty, &mut |name, sub_ty| {
44 hash.entry(name.clone()).or_insert_with(|| sub_ty.clone());
45 });
46}
47
48fn collect_types_in_component(root_component: &Rc<Component>, hash: &mut BTreeMap<SmolStr, Type>) {
49 recurse_elem_including_sub_components_no_borrow(root_component, &(), &mut |elem, _| {
50 for x in elem.borrow().property_declarations.values() {
51 maybe_collect_struct(&x.property_type, hash);
52 }
53 });
54
55 visit_all_expressions(root_component, |expr, _| {
56 expr.visit_recursive(&mut |expr| match expr {
57 Expression::Struct { ty, .. } => maybe_collect_struct(&Type::Struct(ty.clone()), hash),
58 Expression::Array { element_ty, .. } => maybe_collect_struct(element_ty, hash),
59 Expression::EnumerationValue(ev) => {
60 maybe_collect_struct(&Type::Enumeration(ev.enumeration.clone()), hash)
61 }
62 _ => (),
63 })
64 });
65}
66
67fn sort_types(hash: &mut BTreeMap<SmolStr, Type>, vec: &mut Vec<Type>, key: &str) {
70 let ty = if let Some(ty) = hash.remove(key) { ty } else { return };
71 if let Type::Struct(s) = &ty {
72 if let Some(name) = &s.name {
73 if name.contains("::") {
74 return;
77 }
78
79 for sub_ty in s.fields.values() {
80 visit_declared_type(sub_ty, &mut |name, _| sort_types(hash, vec, name));
81 }
82 }
83 }
84 vec.push(ty)
85}
86
87fn visit_declared_type(ty: &Type, visitor: &mut impl FnMut(&SmolStr, &Type)) {
89 match ty {
90 Type::Struct(s) => {
91 if s.node.is_some() {
92 if let Some(struct_name) = s.name.as_ref() {
93 visitor(struct_name, ty);
94 }
95 }
96 for sub_ty in s.fields.values() {
97 visit_declared_type(sub_ty, visitor);
98 }
99 }
100 Type::Array(x) => visit_declared_type(x, visitor),
101 Type::Function(function) | Type::Callback(function) => {
102 visit_declared_type(&function.return_type, visitor);
103 for a in &function.args {
104 visit_declared_type(a, visitor);
105 }
106 }
107 Type::Enumeration(en) => {
108 if en.node.is_some() {
109 visitor(&en.name, ty)
110 }
111 }
112 _ => {}
113 }
114}