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
30 sort_types(&mut hash, &key, &mut |key, ty| {
31 let used_struct_and_enums = &mut used_types.structs_and_enums;
33
34 if let Some(library_info) = doc.library_exports.get(key.as_str()) {
35 used_types.library_types_imports.push((key.clone(), library_info.clone()));
37 } else {
38 used_struct_and_enums.push(ty.clone());
39 }
40 });
41 }
42}
43
44fn maybe_collect_struct(ty: &Type, hash: &mut BTreeMap<SmolStr, Type>) {
45 visit_declared_type(ty, &mut |name, sub_ty| {
46 hash.entry(name.clone()).or_insert_with(|| sub_ty.clone());
47 });
48}
49
50fn collect_types_in_component(root_component: &Rc<Component>, hash: &mut BTreeMap<SmolStr, Type>) {
51 recurse_elem_including_sub_components_no_borrow(root_component, &(), &mut |elem, _| {
52 for x in elem.borrow().property_declarations.values() {
53 maybe_collect_struct(&x.property_type, hash);
54 }
55 });
56
57 visit_all_expressions(root_component, |expr, _| {
58 expr.visit_recursive(&mut |expr| match expr {
59 Expression::Struct { ty, .. } => maybe_collect_struct(&Type::Struct(ty.clone()), hash),
60 Expression::Array { element_ty, .. } => maybe_collect_struct(element_ty, hash),
61 Expression::EnumerationValue(ev) => {
62 maybe_collect_struct(&Type::Enumeration(ev.enumeration.clone()), hash)
63 }
64 _ => (),
65 })
66 });
67}
68
69fn sort_types(
72 hash: &mut BTreeMap<SmolStr, Type>,
73 key: &SmolStr,
74 visitor: &mut impl FnMut(&SmolStr, &Type),
75) {
76 let ty = if let Some(ty) = hash.remove(key) { ty } else { return };
77 if let Type::Struct(s) = &ty
78 && let StructName::User { .. } = &s.name
79 {
80 for sub_ty in s.fields.values() {
81 visit_declared_type(sub_ty, &mut |name, _| sort_types(hash, name, visitor));
82 }
83 }
84 visitor(key, &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 && let StructName::User { name, .. } = &s.name
93 {
94 visitor(name, ty);
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) if en.node.is_some() => visitor(&en.name, ty),
108 _ => {}
109 }
110}