i_slint_compiler/passes/
move_declarations.rs1use crate::expression_tree::{Expression, NamedReference};
7use crate::langtype::ElementType;
8use crate::object_tree::*;
9use core::cell::RefCell;
10use smol_str::{format_smolstr, SmolStr};
11use std::collections::{BTreeMap, HashMap};
12use std::rc::Rc;
13
14struct Declarations {
15 property_declarations: BTreeMap<SmolStr, PropertyDeclaration>,
16}
17impl Declarations {
18 fn take_from_element(e: &mut Element) -> Self {
19 Declarations { property_declarations: core::mem::take(&mut e.property_declarations) }
20 }
21}
22
23pub fn move_declarations(component: &Rc<Component>) {
24 simplify_optimized_items_recursive(component);
25 do_move_declarations(component);
26}
27
28fn do_move_declarations(component: &Rc<Component>) {
29 let mut decl = Declarations::take_from_element(&mut component.root_element.borrow_mut());
30 component.popup_windows.borrow().iter().for_each(|f| do_move_declarations(&f.component));
31 component.menu_item_tree.borrow().iter().for_each(|f| do_move_declarations(f));
32
33 let mut new_root_bindings = HashMap::new();
34 let mut new_root_change_callbacks = HashMap::new();
35 let mut new_root_property_analysis = HashMap::new();
36
37 let move_bindings_and_animations = &mut |elem: &ElementRc| {
38 visit_all_named_references_in_element(elem, fixup_reference);
39
40 if elem.borrow().repeated.is_some() {
41 if let ElementType::Component(base) = &elem.borrow().base_type {
42 do_move_declarations(base);
43 } else {
44 panic!("Repeated element should have a component as base because of the repeater_component.rs pass")
45 }
46 debug_assert!(
47 elem.borrow().property_declarations.is_empty() && elem.borrow().children.is_empty(),
48 "Repeated element should be empty because of the repeater_component.rs pass"
49 );
50 return;
51 }
52
53 let bindings = core::mem::take(&mut elem.borrow_mut().bindings);
55 let mut new_bindings = BindingsMap::default();
56 for (k, e) in bindings {
57 let will_be_moved = elem.borrow().property_declarations.contains_key(&k);
58 if will_be_moved {
59 new_root_bindings.insert(map_name(elem, &k), e);
60 } else {
61 new_bindings.insert(k, e);
62 }
63 }
64 elem.borrow_mut().bindings = new_bindings;
65
66 let property_analysis = elem.borrow().property_analysis.take();
67 let mut new_property_analysis = HashMap::with_capacity(property_analysis.len());
68 for (prop, a) in property_analysis {
69 let will_be_moved = elem.borrow().property_declarations.contains_key(&prop);
70 if will_be_moved {
71 new_root_property_analysis.insert(map_name(elem, &prop), a);
72 } else {
73 new_property_analysis.insert(prop, a);
74 }
75 }
76 *elem.borrow().property_analysis.borrow_mut() = new_property_analysis;
77
78 let change_callbacks = core::mem::take(&mut elem.borrow_mut().change_callbacks);
80 let mut new_change_callbacks = BTreeMap::<SmolStr, RefCell<Vec<Expression>>>::default();
81 for (k, e) in change_callbacks {
82 let will_be_moved = elem.borrow().property_declarations.contains_key(&k);
83 if will_be_moved {
84 new_root_change_callbacks.insert(map_name(elem, &k), e);
85 } else {
86 new_change_callbacks.insert(k, e);
87 }
88 }
89 elem.borrow_mut().change_callbacks = new_change_callbacks;
90 };
91
92 component.optimized_elements.borrow().iter().for_each(|e| move_bindings_and_animations(e));
93 recurse_elem(&component.root_element, &(), &mut |e, _| move_bindings_and_animations(e));
94
95 component.root_constraints.borrow_mut().visit_named_references(&mut fixup_reference);
96 component.popup_windows.borrow_mut().iter_mut().for_each(|p| {
97 fixup_reference(&mut p.x);
98 fixup_reference(&mut p.y);
99 visit_all_named_references(&p.component, &mut fixup_reference)
100 });
101 component.timers.borrow_mut().iter_mut().for_each(|t| {
102 fixup_reference(&mut t.interval);
103 fixup_reference(&mut t.running);
104 fixup_reference(&mut t.triggered);
105 });
106 component.menu_item_tree.borrow_mut().iter_mut().for_each(|c| {
107 visit_all_named_references(c, &mut fixup_reference);
108 });
109 component.init_code.borrow_mut().iter_mut().for_each(|expr| {
110 visit_named_references_in_expression(expr, &mut fixup_reference);
111 });
112 for pd in decl.property_declarations.values_mut() {
113 pd.is_alias.as_mut().map(fixup_reference);
114 }
115
116 let move_properties = &mut |elem: &ElementRc| {
117 let elem_decl = Declarations::take_from_element(&mut elem.borrow_mut());
118 decl.property_declarations.extend(
119 elem_decl.property_declarations.into_iter().map(|(p, d)| (map_name(elem, &p), d)),
120 );
121 };
122
123 recurse_elem(&component.root_element, &(), &mut |elem, _| move_properties(elem));
124
125 component.optimized_elements.borrow().iter().for_each(move_properties);
126
127 {
128 let mut r = component.root_element.borrow_mut();
129 r.property_declarations = decl.property_declarations;
130 r.bindings.extend(new_root_bindings);
131 r.property_analysis.borrow_mut().extend(new_root_property_analysis);
132 r.change_callbacks.extend(new_root_change_callbacks);
133 }
134}
135
136fn fixup_reference(nr: &mut NamedReference) {
137 let e = nr.element();
138 let component = e.borrow().enclosing_component.upgrade().unwrap();
139 if !Rc::ptr_eq(&e, &component.root_element)
140 && e.borrow().property_declarations.contains_key(nr.name())
141 {
142 *nr = NamedReference::new(&component.root_element, map_name(&e, nr.name()).into());
143 }
144}
145
146fn map_name(e: &ElementRc, s: &SmolStr) -> SmolStr {
147 format_smolstr!("{}-{}", e.borrow().id, s)
148}
149
150fn simplify_optimized_items_recursive(component: &Rc<Component>) {
151 simplify_optimized_items(component.optimized_elements.borrow().as_slice());
152 component
153 .popup_windows
154 .borrow()
155 .iter()
156 .for_each(|f| simplify_optimized_items_recursive(&f.component));
157 recurse_elem(&component.root_element, &(), &mut |elem, _| {
158 if elem.borrow().repeated.is_some() {
159 if let ElementType::Component(base) = &elem.borrow().base_type {
160 simplify_optimized_items_recursive(base);
161 }
162 }
163 });
164}
165
166fn simplify_optimized_items(items: &[ElementRc]) {
170 for elem in items {
171 recurse_elem(elem, &(), &mut |elem, _| {
172 let base = core::mem::take(&mut elem.borrow_mut().base_type);
173 if let ElementType::Builtin(c) = base {
174 elem.borrow_mut().property_declarations.extend(c.properties.iter().map(
176 |(k, v)| {
177 (
178 k.clone(),
179 PropertyDeclaration {
180 property_type: v.ty.clone(),
181 ..Default::default()
182 },
183 )
184 },
185 ));
186 } else {
187 unreachable!("Only builtin items should be optimized")
188 }
189 })
190 }
191}