Skip to main content

pax_core/
repeat.rs

1use std::any::Any;
2use std::cell::RefCell;
3use std::iter;
4use std::rc::Rc;
5
6use crate::declarative_macros::handle_vtable_update_optional;
7use crate::{
8    BaseInstance, ExpandedNode, InstanceFlags, InstanceNode, InstantiationArgs, RuntimeContext,
9};
10use pax_runtime_api::Layer;
11
12/// A special "control-flow" primitive associated with the `for` statement.
13/// Repeat allows for nodes to be rendered dynamically per data specified in `source_expression`.
14/// That is: for a `source_expression` of length `n`, `Repeat` will render its
15/// template `n` times, each with an embedded component context (`RepeatItem`)
16/// with an index `i` and a pointer to that relevant datum `source_expression[i]`
17pub struct RepeatInstance {
18    pub base: BaseInstance,
19}
20
21///Contains modal _vec_ and _range_ variants, describing whether the Repeat source
22///is encoded as a Vec<T> (where T is a `dyn Any` properties type) or as a Range<isize>
23#[derive(Default)]
24pub struct RepeatProperties {
25    pub source_expression_vec:
26        Option<Box<dyn pax_runtime_api::PropertyInstance<Vec<Rc<RefCell<dyn Any>>>>>>,
27    pub source_expression_range:
28        Option<Box<dyn pax_runtime_api::PropertyInstance<std::ops::Range<isize>>>>,
29    last_len: usize,
30    last_bounds: (f64, f64),
31}
32
33pub struct RepeatItem {
34    pub elem: Rc<RefCell<dyn Any>>,
35    pub i: usize,
36}
37
38impl InstanceNode for RepeatInstance {
39    fn instantiate(args: InstantiationArgs) -> Rc<Self>
40    where
41        Self: Sized,
42    {
43        Rc::new(Self {
44            base: BaseInstance::new(
45                args,
46                InstanceFlags {
47                    invisible_to_slot: true,
48                    invisible_to_raycasting: true,
49                    layer: Layer::DontCare,
50                    is_component: false,
51                },
52            ),
53        })
54    }
55
56    #[cfg(debug_assertions)]
57    fn resolve_debug(
58        &self,
59        f: &mut std::fmt::Formatter,
60        _expanded_node: Option<&ExpandedNode>,
61    ) -> std::fmt::Result {
62        f.debug_struct("Repeat").finish()
63    }
64
65    fn base(&self) -> &BaseInstance {
66        &self.base
67    }
68
69    fn update(self: Rc<Self>, expanded_node: &Rc<ExpandedNode>, context: &mut RuntimeContext) {
70        let new_vec =
71            expanded_node.with_properties_unwrapped(|properties: &mut RepeatProperties| {
72                handle_vtable_update_optional(
73                    context.expression_table(),
74                    &expanded_node.stack,
75                    properties.source_expression_range.as_mut(),
76                );
77                handle_vtable_update_optional(
78                    context.expression_table(),
79                    &expanded_node.stack,
80                    properties.source_expression_vec.as_mut(),
81                );
82
83                let vec = if let Some(ref source) = properties.source_expression_range {
84                    Box::new(
85                        source
86                            .get()
87                            .clone()
88                            .map(|v| Rc::new(RefCell::new(v)) as Rc<RefCell<dyn Any>>),
89                    ) as Box<dyn ExactSizeIterator<Item = Rc<RefCell<dyn Any>>>>
90                } else if let Some(ref source) = properties.source_expression_vec {
91                    Box::new(source.get().clone().into_iter())
92                        as Box<dyn ExactSizeIterator<Item = Rc<RefCell<dyn Any>>>>
93                } else {
94                    //A valid Repeat must have a repeat source; presumably this has been gated by the parser / compiler
95                    unreachable!();
96                };
97
98                let current_len = vec.len();
99                let exp_props = expanded_node.layout_properties.borrow();
100                let current_bounds = exp_props
101                    .as_ref()
102                    .map(|t| t.computed_tab.bounds)
103                    .unwrap_or_default();
104                let update_children =
105                    current_len != properties.last_len || current_bounds != properties.last_bounds;
106                properties.last_len = current_len;
107                properties.last_bounds = current_bounds;
108                update_children.then_some(vec)
109            });
110
111        if let Some(vec) = new_vec {
112            let template_children = self.base().get_instance_children();
113            let children_with_envs = iter::repeat(template_children)
114                .zip(vec.into_iter())
115                .enumerate()
116                .flat_map(|(i, (children, elem))| {
117                    let new_repeat_item = Rc::new(RefCell::new(RepeatItem {
118                        i,
119                        elem: Rc::clone(&elem),
120                    })) as Rc<RefCell<dyn Any>>;
121                    let new_env = expanded_node.stack.push(&new_repeat_item);
122                    children.clone().into_iter().zip(iter::repeat(new_env))
123                });
124            expanded_node.set_children(children_with_envs, context);
125        }
126    }
127
128    fn handle_mount(&self, _expanded_node: &Rc<ExpandedNode>, _context: &mut RuntimeContext) {
129        // No-op: wait with creating child-nodes until update tick, since the
130        // condition has then been evaluated
131    }
132}