1use super::{EvaluationContext, Expression, ParentScope};
5use crate::langtype::{NativeClass, Type};
6use derive_more::{From, Into};
7use smol_str::SmolStr;
8use std::cell::{Cell, RefCell};
9use std::collections::{BTreeMap, HashMap};
10use std::rc::Rc;
11use typed_index_collections::TiVec;
12
13#[derive(Debug, Clone, Copy, Into, From, Hash, PartialEq, Eq, PartialOrd, Ord)]
14pub struct PropertyIdx(usize);
15#[derive(Debug, Clone, Copy, Into, From, Hash, PartialEq, Eq, PartialOrd, Ord)]
16pub struct FunctionIdx(usize);
17#[derive(Debug, Clone, Copy, Into, From, Hash, PartialEq, Eq, PartialOrd, Ord)]
18pub struct CallbackIdx(usize);
19#[derive(Debug, Clone, Copy, Into, From, Hash, PartialEq, Eq)]
20pub struct SubComponentIdx(usize);
21#[derive(Debug, Clone, Copy, Into, From, Hash, PartialEq, Eq)]
22pub struct GlobalIdx(usize);
23#[derive(Debug, Clone, Copy, Into, From, Hash, PartialEq, Eq)]
24pub struct SubComponentInstanceIdx(usize);
25#[derive(Debug, Clone, Copy, Into, From, Hash, PartialEq, Eq, PartialOrd, Ord)]
26pub struct ItemInstanceIdx(usize);
27#[derive(Debug, Clone, Copy, Into, From, Hash, PartialEq, Eq)]
28pub struct RepeatedElementIdx(usize);
29#[derive(Debug, Clone, Copy, Into, From, Hash, PartialEq, Eq)]
30pub struct GridLayoutChildIdx(usize);
31
32#[derive(Debug, Clone)]
36pub enum RowChildTemplateInfo {
37 Static { child_index: GridLayoutChildIdx },
39 Repeated { repeater_index: RepeatedElementIdx },
41}
42
43pub fn has_inner_repeaters(templates: &Option<Vec<RowChildTemplateInfo>>) -> bool {
45 templates
46 .as_ref()
47 .is_some_and(|t| t.iter().any(|e| matches!(e, RowChildTemplateInfo::Repeated { .. })))
48}
49
50pub fn static_child_count(templates: &[RowChildTemplateInfo]) -> usize {
52 templates.iter().filter(|e| matches!(e, RowChildTemplateInfo::Static { .. })).count()
53}
54
55#[derive(Debug, Clone)]
56pub struct LayoutRepeatedElement {
57 pub repeater_index: RepeatedElementIdx,
58 pub row_child_templates: Option<Vec<RowChildTemplateInfo>>,
61}
62
63#[derive(Debug, Clone)]
64pub struct GridLayoutRepeatedElement {
65 pub new_row: bool,
66 pub repeater_index: RepeatedElementIdx,
67 pub row_child_templates: Option<Vec<RowChildTemplateInfo>>,
70}
71
72impl PropertyIdx {
73 pub const REPEATER_DATA: Self = Self(0);
74 pub const REPEATER_INDEX: Self = Self(1);
75}
76
77#[derive(Debug, Clone)]
80pub struct GridLayoutChildLayoutInfo {
81 pub layout_info_h: MutExpression,
82 pub layout_info_v: MutExpression,
83}
84
85#[derive(Debug, Clone, derive_more::Deref, derive_more::DerefMut)]
86pub struct MutExpression(RefCell<Expression>);
87
88impl From<Expression> for MutExpression {
89 fn from(e: Expression) -> Self {
90 Self(e.into())
91 }
92}
93
94impl MutExpression {
95 pub fn ty(&self, ctx: &dyn super::TypeResolutionContext) -> Type {
96 self.0.borrow().ty(ctx)
97 }
98}
99
100#[derive(Debug, Clone)]
101pub enum Animation {
102 Static(Expression),
104 Transition(Expression),
105}
106
107#[derive(Debug, Clone)]
108pub struct BindingExpression {
109 pub expression: MutExpression,
110 pub animation: Option<Animation>,
111 pub is_constant: bool,
113 pub is_state_info: bool,
116
117 pub use_count: Cell<usize>,
120}
121
122#[derive(Debug)]
123pub struct GlobalComponent {
124 pub name: SmolStr,
125 pub properties: TiVec<PropertyIdx, Property>,
126 pub callbacks: TiVec<CallbackIdx, Callback>,
127 pub functions: TiVec<FunctionIdx, Function>,
128 pub init_values: BTreeMap<LocalMemberIndex, BindingExpression>,
130 pub change_callbacks: BTreeMap<PropertyIdx, MutExpression>,
132 pub const_properties: TiVec<PropertyIdx, bool>,
133 pub public_properties: PublicProperties,
134 pub private_properties: PrivateProperties,
135 pub exported: bool,
137 pub aliases: Vec<SmolStr>,
140 pub is_builtin: bool,
142 pub from_library: bool,
144 pub prop_analysis: TiVec<PropertyIdx, crate::object_tree::PropertyAnalysis>,
146}
147
148impl GlobalComponent {
149 pub fn must_generate(&self) -> bool {
150 !self.from_library
151 && (self.exported
152 || !self.functions.is_empty()
153 || self.properties.iter().any(|p| p.use_count.get() > 0)
154 || self.callbacks.iter().any(|c| c.use_count.get() > 0))
155 }
156}
157
158#[derive(Clone, Debug, Hash, PartialEq, Eq, From, PartialOrd, Ord)]
159pub enum LocalMemberIndex {
160 #[from]
161 Property(PropertyIdx),
162 #[from]
163 Function(FunctionIdx),
164 #[from]
165 Callback(CallbackIdx),
166 Native {
167 item_index: ItemInstanceIdx,
168 prop_name: SmolStr,
169 },
170}
171impl LocalMemberIndex {
172 pub fn property(&self) -> Option<PropertyIdx> {
173 if let LocalMemberIndex::Property(p) = self { Some(*p) } else { None }
174 }
175}
176
177#[derive(Clone, Debug, Hash, PartialEq, Eq)]
179pub enum MemberReference {
180 Global { global_index: GlobalIdx, member: LocalMemberIndex },
182
183 Relative {
185 parent_level: usize,
187 local_reference: LocalMemberReference,
188 },
189}
190impl MemberReference {
191 #[track_caller]
193 pub fn local(&self) -> LocalMemberReference {
194 match self {
195 MemberReference::Relative { parent_level: 0, local_reference, .. } => {
196 local_reference.clone()
197 }
198 _ => panic!("not a local reference"),
199 }
200 }
201
202 pub fn is_function(&self) -> bool {
203 matches!(
204 self,
205 MemberReference::Global { member: LocalMemberIndex::Function(..), .. }
206 | MemberReference::Relative {
207 local_reference: LocalMemberReference {
208 reference: LocalMemberIndex::Function(..),
209 ..
210 },
211 ..
212 }
213 )
214 }
215}
216
217impl From<LocalMemberReference> for MemberReference {
218 fn from(local_reference: LocalMemberReference) -> Self {
219 MemberReference::Relative { parent_level: 0, local_reference }
220 }
221}
222
223#[derive(Debug, Clone, PartialEq, Eq, Hash)]
225pub struct LocalMemberReference {
226 pub sub_component_path: Vec<SubComponentInstanceIdx>,
227 pub reference: LocalMemberIndex,
228}
229
230impl<T: Into<LocalMemberIndex>> From<T> for LocalMemberReference {
231 fn from(reference: T) -> Self {
232 Self { sub_component_path: Vec::new(), reference: reference.into() }
233 }
234}
235
236#[derive(Debug, Clone)]
237pub struct TwoWayBinding {
238 pub prop1: LocalMemberReference,
239 pub prop2: MemberReference,
240 pub is_model: Option<PropertyIdx>,
244 pub field_access: Vec<SmolStr>,
246}
247
248pub struct ResolvedModelTwoWayBinding<'a> {
251 pub parent_level: usize,
253 pub body_sub_component: SubComponentIdx,
254 pub data_prop: PropertyIdx,
255 pub data_prop_ty: &'a Type,
257 pub index_prop: PropertyIdx,
258 pub parent_sub_component: SubComponentIdx,
259 pub repeater_index: RepeatedElementIdx,
260}
261
262impl TwoWayBinding {
263 pub fn resolve_model<'a, T>(
266 &self,
267 ctx: &EvaluationContext<'a, T>,
268 ) -> Option<ResolvedModelTwoWayBinding<'a>> {
269 let index_prop = self.is_model?;
270 let MemberReference::Relative { parent_level, local_reference } = &self.prop2 else {
271 unreachable!("model two-way binding's prop2 is always a Relative reference")
272 };
273 debug_assert!(local_reference.sub_component_path.is_empty());
274 let LocalMemberIndex::Property(data_prop) = local_reference.reference else {
275 unreachable!("model two-way binding's prop2 always references a property")
276 };
277 let super::EvaluationScope::SubComponent(mut sc, mut par) = ctx.current_scope else {
278 unreachable!("model two-way binding cannot be in a global")
279 };
280 for _ in 0..*parent_level {
281 let x = par.expect("parent_level should be valid");
282 par = x.parent;
283 sc = x.sub_component;
284 }
285 let par = par.expect("repeated item_tree must have a parent");
286 let data_prop_ty = &ctx.compilation_unit.sub_components[sc].properties[data_prop].ty;
287 Some(ResolvedModelTwoWayBinding {
288 parent_level: *parent_level,
289 body_sub_component: sc,
290 data_prop,
291 data_prop_ty,
292 index_prop,
293 parent_sub_component: par.sub_component,
294 repeater_index: par.repeater_index.expect("repeated parent has a repeater_index"),
295 })
296 }
297}
298
299#[derive(Debug, Default)]
300pub struct Property {
301 pub name: SmolStr,
302 pub ty: Type,
303 pub use_count: Cell<usize>,
306}
307
308#[derive(Debug, Default)]
309pub struct Callback {
310 pub name: SmolStr,
311 pub ret_ty: Type,
312 pub args: Vec<Type>,
313
314 pub ty: Type,
317
318 pub use_count: Cell<usize>,
320
321 pub needs_tracker: bool,
325}
326
327#[derive(Debug)]
328pub struct Function {
329 pub name: SmolStr,
330 pub ret_ty: Type,
331 pub args: Vec<Type>,
332 pub code: Expression,
333}
334
335#[derive(Debug, Clone)]
336pub struct ListViewInfo {
339 pub viewport_y: MemberReference,
340 pub viewport_height: MemberReference,
341 pub viewport_width: MemberReference,
342 pub listview_height: MemberReference,
344 pub listview_width: MemberReference,
346
347 pub prop_y: MemberReference,
349 pub prop_height: MemberReference,
351}
352
353#[derive(Debug)]
354pub struct RepeatedElement {
355 pub model: MutExpression,
356 pub index_prop: Option<PropertyIdx>,
358 pub data_prop: Option<PropertyIdx>,
360 pub sub_tree: ItemTree,
361 pub index_in_tree: u32,
363
364 pub listview: Option<ListViewInfo>,
365
366 pub container_item_index: Option<ItemInstanceIdx>,
368}
369
370#[derive(Debug)]
371pub struct ComponentContainerElement {
372 pub component_container_item_tree_index: u32,
374 pub component_container_items_index: ItemInstanceIdx,
376 pub component_placeholder_item_tree_index: u32,
378}
379
380pub struct Item {
381 pub ty: Rc<NativeClass>,
382 pub name: SmolStr,
383 pub index_in_tree: u32,
385}
386
387impl std::fmt::Debug for Item {
388 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
389 f.debug_struct("Item")
390 .field("ty", &self.ty.class_name)
391 .field("name", &self.name)
392 .field("index_in_tree", &self.index_in_tree)
393 .finish()
394 }
395}
396
397#[derive(Debug)]
398pub struct TreeNode {
399 pub sub_component_path: Vec<SubComponentInstanceIdx>,
400 pub item_index: itertools::Either<ItemInstanceIdx, u32>,
402 pub children: Vec<TreeNode>,
403 pub is_accessible: bool,
404}
405
406impl TreeNode {
407 fn children_count(&self) -> usize {
408 let mut count = self.children.len();
409 for c in &self.children {
410 count += c.children_count();
411 }
412 count
413 }
414
415 pub fn visit_in_array(
418 &self,
419 visitor: &mut dyn FnMut(
420 &TreeNode,
421 usize,
422 usize,
423 ),
424 ) {
425 visitor(self, 1, 0);
426 visit_in_array_recursive(self, 1, 0, visitor);
427
428 fn visit_in_array_recursive(
429 node: &TreeNode,
430 children_offset: usize,
431 current_index: usize,
432 visitor: &mut dyn FnMut(&TreeNode, usize, usize),
433 ) {
434 let mut offset = children_offset + node.children.len();
435 for c in &node.children {
436 visitor(c, offset, current_index);
437 offset += c.children_count();
438 }
439
440 let mut offset = children_offset + node.children.len();
441 for (i, c) in node.children.iter().enumerate() {
442 visit_in_array_recursive(c, offset, children_offset + i, visitor);
443 offset += c.children_count();
444 }
445 }
446 }
447}
448
449#[derive(Debug)]
450pub struct SubComponent {
451 pub name: SmolStr,
452 pub properties: TiVec<PropertyIdx, Property>,
453 pub callbacks: TiVec<CallbackIdx, Callback>,
454 pub functions: TiVec<FunctionIdx, Function>,
455 pub items: TiVec<ItemInstanceIdx, Item>,
456 pub repeated: TiVec<RepeatedElementIdx, RepeatedElement>,
457 pub component_containers: Vec<ComponentContainerElement>,
458 pub popup_windows: Vec<PopupWindow>,
459 pub menu_item_trees: Vec<ItemTree>,
461 pub timers: Vec<Timer>,
462 pub sub_components: TiVec<SubComponentInstanceIdx, SubComponentInstance>,
463 pub property_init: Vec<(MemberReference, BindingExpression)>,
466 pub change_callbacks: Vec<(MemberReference, MutExpression)>,
467 pub animations: HashMap<LocalMemberReference, Expression>,
469 pub two_way_bindings: Vec<TwoWayBinding>,
471 pub const_properties: Vec<LocalMemberReference>,
472 pub pre_init_code: Vec<MutExpression>,
475 pub init_code: Vec<MutExpression>,
477
478 pub geometries: Vec<Option<MutExpression>>,
480
481 pub layout_info_h: MutExpression,
482 pub layout_info_v: MutExpression,
483 pub child_of_layout: bool,
484 pub grid_layout_input_for_repeated: Option<MutExpression>,
485 pub flexbox_layout_item_info_for_repeated: Option<MutExpression>,
488 pub is_repeated_row: bool,
491 pub grid_layout_children: TiVec<GridLayoutChildIdx, GridLayoutChildLayoutInfo>,
494 pub row_child_templates: Option<Vec<RowChildTemplateInfo>>,
498
499 pub accessible_prop: BTreeMap<(u32, String), MutExpression>,
501
502 pub element_infos: BTreeMap<u32, String>,
504
505 pub prop_analysis: HashMap<MemberReference, PropAnalysis>,
506}
507
508#[derive(Debug)]
509pub struct PopupWindow {
510 pub item_tree: ItemTree,
511 pub position: MutExpression,
512 pub is_tooltip: bool,
513}
514
515#[derive(Debug)]
516pub struct PopupMenu {
517 pub item_tree: ItemTree,
518 pub sub_menu: MemberReference,
519 pub activated: MemberReference,
520 pub close: MemberReference,
521 pub entries: MemberReference,
522}
523
524#[derive(Debug)]
525pub struct Timer {
526 pub interval: MutExpression,
527 pub running: MutExpression,
528 pub triggered: MutExpression,
529}
530
531#[derive(Debug, Clone)]
532pub struct PropAnalysis {
533 pub property_init: Option<usize>,
535 pub analysis: crate::object_tree::PropertyAnalysis,
536}
537
538impl SubComponent {
539 pub fn repeater_count(&self, cu: &CompilationUnit) -> u32 {
541 let mut count = (self.repeated.len() + self.component_containers.len()) as u32;
542 for x in self.sub_components.iter() {
543 count += cu.sub_components[x.ty].repeater_count(cu);
544 }
545 count
546 }
547
548 pub fn child_item_count(&self, cu: &CompilationUnit) -> u32 {
550 let mut count = self.items.len() as u32;
551 for x in self.sub_components.iter() {
552 count += cu.sub_components[x.ty].child_item_count(cu);
553 }
554 count
555 }
556}
557
558#[derive(Debug)]
559pub struct SubComponentInstance {
560 pub ty: SubComponentIdx,
561 pub name: SmolStr,
562 pub index_in_tree: u32,
563 pub index_of_first_child_in_tree: u32,
564 pub repeater_offset: u32,
565}
566
567#[derive(Debug)]
568pub struct ItemTree {
569 pub root: SubComponentIdx,
570 pub tree: TreeNode,
571}
572
573#[derive(Debug, Clone, Copy, PartialEq, Eq)]
577pub enum TopLevelComponentType {
578 Window,
579 SystemTrayIcon,
580}
581
582#[derive(Debug)]
583pub struct PublicComponent {
584 pub public_properties: PublicProperties,
585 pub private_properties: PrivateProperties,
586 pub item_tree: ItemTree,
587 pub name: SmolStr,
588 pub top_level_type: TopLevelComponentType,
589}
590
591#[derive(Debug)]
592pub struct CompilationUnit {
593 pub public_components: Vec<PublicComponent>,
594 pub sub_components: TiVec<SubComponentIdx, SubComponent>,
596 pub used_sub_components: Vec<SubComponentIdx>,
598 pub globals: TiVec<GlobalIdx, GlobalComponent>,
599 pub popup_menu: Option<PopupMenu>,
600 pub has_debug_info: bool,
601 #[cfg(feature = "bundle-translations")]
602 pub translations: Option<crate::translations::Translations>,
603}
604
605impl CompilationUnit {
606 pub fn needs_window_adapter(&self) -> bool {
607 self.public_components.iter().any(|p| p.top_level_type == TopLevelComponentType::Window)
608 || self.popup_menu.is_some()
609 }
610
611 pub fn for_each_sub_components<'a>(
612 &'a self,
613 visitor: &mut dyn FnMut(&'a SubComponent, &EvaluationContext<'_>),
614 ) {
615 fn visit_component<'a>(
616 root: &'a CompilationUnit,
617 c: SubComponentIdx,
618 visitor: &mut dyn FnMut(&'a SubComponent, &EvaluationContext<'_>),
619 parent: Option<&ParentScope<'_>>,
620 ) {
621 let ctx = EvaluationContext::new_sub_component(root, c, (), parent);
622 let sc = &root.sub_components[c];
623 visitor(sc, &ctx);
624 for (idx, r) in sc.repeated.iter_enumerated() {
625 visit_component(
626 root,
627 r.sub_tree.root,
628 visitor,
629 Some(&ParentScope::new(&ctx, Some(idx))),
630 );
631 }
632 for popup in &sc.popup_windows {
633 visit_component(
634 root,
635 popup.item_tree.root,
636 visitor,
637 Some(&ParentScope::new(&ctx, None)),
638 );
639 }
640 for menu_tree in &sc.menu_item_trees {
641 visit_component(root, menu_tree.root, visitor, Some(&ParentScope::new(&ctx, None)));
642 }
643 }
644 for c in &self.used_sub_components {
645 visit_component(self, *c, visitor, None);
646 }
647 for p in &self.public_components {
648 visit_component(self, p.item_tree.root, visitor, None);
649 }
650 if let Some(p) = &self.popup_menu {
651 visit_component(self, p.item_tree.root, visitor, None);
652 }
653 }
654
655 pub fn for_each_expression<'a>(
656 &'a self,
657 visitor: &mut dyn FnMut(&'a super::MutExpression, &EvaluationContext<'_>),
658 ) {
659 self.for_each_sub_components(&mut |sc, ctx| {
660 for e in &sc.pre_init_code {
661 visitor(e, ctx);
662 }
663 for e in &sc.init_code {
664 visitor(e, ctx);
665 }
666 for (_, e) in &sc.property_init {
667 visitor(&e.expression, ctx);
668 }
669 visitor(&sc.layout_info_h, ctx);
670 visitor(&sc.layout_info_v, ctx);
671 if let Some(e) = &sc.grid_layout_input_for_repeated {
672 visitor(e, ctx);
673 }
674 if let Some(e) = &sc.flexbox_layout_item_info_for_repeated {
675 visitor(e, ctx);
676 }
677 for e in sc.accessible_prop.values() {
678 visitor(e, ctx);
679 }
680 for i in sc.geometries.iter().flatten() {
681 visitor(i, ctx);
682 }
683 for (_, e) in sc.change_callbacks.iter() {
684 visitor(e, ctx);
685 }
686 });
687 for (idx, g) in self.globals.iter_enumerated() {
688 let ctx = EvaluationContext::new_global(self, idx, ());
689 for e in g.init_values.values() {
690 visitor(&e.expression, &ctx)
691 }
692 for e in g.change_callbacks.values() {
693 visitor(e, &ctx)
694 }
695 }
696 }
697}
698
699#[derive(Debug, Clone)]
701pub struct PublicProperty {
702 pub name: SmolStr,
703 pub ty: Type,
704 pub prop: MemberReference,
705 pub read_only: bool,
706}
707pub type PublicProperties = Vec<PublicProperty>;
708pub type PrivateProperties = Vec<(SmolStr, Type)>;