i_slint_compiler/passes/
collect_structs_and_enums.rs1use crate::expression_tree::Expression;
7use crate::langtype::{StructName, 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 && let StructName::User { .. } = &s.name
73 {
74 for sub_ty in s.fields.values() {
75 visit_declared_type(sub_ty, &mut |name, _| sort_types(hash, vec, name));
76 }
77 }
78 vec.push(ty)
79}
80
81fn visit_declared_type(ty: &Type, visitor: &mut impl FnMut(&SmolStr, &Type)) {
83 match ty {
84 Type::Struct(s) => {
85 if s.node().is_some()
86 && let StructName::User { name, .. } = &s.name
87 {
88 visitor(name, ty);
89 }
90 for sub_ty in s.fields.values() {
91 visit_declared_type(sub_ty, visitor);
92 }
93 }
94 Type::Array(x) => visit_declared_type(x, visitor),
95 Type::Function(function) | Type::Callback(function) => {
96 visit_declared_type(&function.return_type, visitor);
97 for a in &function.args {
98 visit_declared_type(a, visitor);
99 }
100 }
101 Type::Enumeration(en) if en.node.is_some() => visitor(&en.name, ty),
102 _ => {}
103 }
104}