1use std::ops::ControlFlow;
11
12use anathema_state::Value as StateValue;
13use anathema_templates::blueprints::Blueprint;
14use anathema_value_resolver::{AttributeStorage, Scope};
15
16use crate::error::Result;
17use crate::layout::{LayoutCtx, LayoutFilter};
18use crate::nodes::loops::Iteration;
19use crate::nodes::{controlflow, eval_blueprint};
20use crate::widget::WidgetTreeView;
21use crate::{Element, WidgetContainer, WidgetId, WidgetKind};
22
23pub mod debug;
24
25#[derive(Debug, Copy, Clone)]
32pub enum WidgetPositionFilter {
33 Floating,
34 Fixed,
35 All,
36 None,
37}
38
39#[derive(Debug, Copy, Clone)]
40pub enum Generator<'widget, 'bp> {
41 Single {
42 ident: &'bp str,
43 body: &'bp [Blueprint],
44 },
45 Loop {
46 len: usize,
47 binding: &'bp str,
48 body: &'bp [Blueprint],
49 },
50 Iteration {
51 binding: &'bp str,
52 body: &'bp [Blueprint],
53 },
54 ControlFlow(&'widget controlflow::ControlFlow<'bp>),
55 ControlFlowContainer(&'bp [Blueprint]),
56 Slot(&'bp [Blueprint]),
57}
58
59impl<'widget, 'bp> Generator<'widget, 'bp> {
60 fn from_loop(body: &'bp [Blueprint], binding: &'bp str, len: usize) -> Self {
61 Self::Loop { binding, body, len }
62 }
63}
64
65impl<'widget, 'bp> From<&'widget WidgetContainer<'bp>> for Generator<'widget, 'bp> {
66 fn from(widget: &'widget WidgetContainer<'bp>) -> Self {
67 match &widget.kind {
68 WidgetKind::Element(_) => panic!("use Self::Single directly"),
69 WidgetKind::For(_) => panic!("use Self::Loop directory"),
70 WidgetKind::ControlFlowContainer(_) => Self::ControlFlowContainer(widget.children),
71 WidgetKind::Component(comp) => Self::Single {
72 ident: comp.name,
73 body: widget.children,
74 },
75 WidgetKind::Iteration(iter) => Self::Iteration {
76 binding: iter.binding,
77 body: widget.children,
78 },
79 WidgetKind::ControlFlow(controlflow) => Self::ControlFlow(controlflow),
80 WidgetKind::Slot => Self::Slot(widget.children),
81 }
82 }
83}
84
85#[derive(Debug)]
89pub struct LayoutForEach<'a, 'bp> {
90 tree: WidgetTreeView<'a, 'bp>,
91 scope: &'a Scope<'a, 'bp>,
92 generator: Option<Generator<'a, 'bp>>,
93 parent_component: Option<WidgetId>,
94 filter: LayoutFilter,
95}
96
97impl<'a, 'bp> LayoutForEach<'a, 'bp> {
98 pub fn new(
99 tree: WidgetTreeView<'a, 'bp>,
100 scope: &'a Scope<'a, 'bp>,
101 filter: LayoutFilter,
102 parent_component: Option<WidgetId>,
103 ) -> Self {
104 Self {
105 tree,
106 scope,
107 generator: None,
108 parent_component,
109 filter,
110 }
111 }
112
113 fn with_generator(
114 tree: WidgetTreeView<'a, 'bp>,
115 scope: &'a Scope<'a, 'bp>,
116 generator: Generator<'a, 'bp>,
117 filter: LayoutFilter,
118 parent_component: Option<WidgetId>,
119 ) -> Self {
120 Self {
121 tree,
122 scope,
123 generator: Some(generator),
124 filter,
125 parent_component,
126 }
127 }
128
129 pub fn each<F>(&mut self, ctx: &mut LayoutCtx<'_, 'bp>, mut f: F) -> Result<ControlFlow<()>>
137 where
138 F: FnMut(&mut LayoutCtx<'_, 'bp>, &mut Element<'bp>, LayoutForEach<'_, 'bp>) -> Result<ControlFlow<()>>,
139 {
140 self.inner_each(ctx, &mut f)
141 }
142
143 fn inner_each<F>(&mut self, ctx: &mut LayoutCtx<'_, 'bp>, f: &mut F) -> Result<ControlFlow<()>>
144 where
145 F: FnMut(&mut LayoutCtx<'_, 'bp>, &mut Element<'bp>, LayoutForEach<'_, 'bp>) -> Result<ControlFlow<()>>,
146 {
147 for index in 0..self.tree.layout_len() {
148 match self.process(index, ctx, f)? {
149 ControlFlow::Continue(_) => continue,
150 ControlFlow::Break(_) => return Ok(ControlFlow::Break(())),
151 }
152 }
153
154 let Some(parent) = self.generator else { return Ok(ControlFlow::Continue(())) };
156
157 loop {
160 let index = self.tree.layout_len();
161 if !generate(parent, &mut self.tree, ctx, self.scope, self.parent_component)? {
162 break;
163 }
164 match self.process(index, ctx, f)? {
165 ControlFlow::Continue(_) => continue,
166 ControlFlow::Break(_) => return Ok(ControlFlow::Break(())),
167 }
168 }
169
170 Ok(ControlFlow::Continue(()))
171 }
172
173 fn process<F>(&mut self, index: usize, ctx: &mut LayoutCtx<'_, 'bp>, f: &mut F) -> Result<ControlFlow<()>>
175 where
176 F: FnMut(&mut LayoutCtx<'_, 'bp>, &mut Element<'bp>, LayoutForEach<'_, 'bp>) -> Result<ControlFlow<()>>,
177 {
178 let node = self
179 .tree
180 .layout
181 .get(index)
182 .expect("widgets are always generated before processed");
183
184 let widget_id = node.value();
185
186 self.tree
187 .with_value_mut(widget_id, |_, widget, mut children| {
188 let output = self.filter.filter(widget, ctx.attribute_storage);
189 if let FilterOutput::Exclude = output {
190 return Ok(ControlFlow::Continue(()));
191 }
192
193 match &mut widget.kind {
194 WidgetKind::Element(el) => {
195 let children = LayoutForEach::with_generator(
196 children,
197 self.scope,
198 Generator::Single {
199 ident: el.ident,
200 body: widget.children,
201 },
202 self.filter,
203 self.parent_component,
204 );
205 f(ctx, el, children)
206 }
207 WidgetKind::ControlFlow(controlflow) => {
208 if controlflow.has_changed(&children) {
209 children.truncate_children();
210 }
211 let generator = Generator::from(&*widget);
212 let mut children = LayoutForEach::with_generator(
213 children,
214 self.scope,
215 generator,
216 self.filter,
217 self.parent_component,
218 );
219 children.inner_each(ctx, f)
220 }
221 WidgetKind::For(for_loop) => {
222 let len = for_loop.collection.len();
223 if len == 0 {
224 return Ok(ControlFlow::Break(()));
225 }
226
227 let scope = Scope::with_collection(&for_loop.collection, self.scope);
228 let mut children = LayoutForEach::with_generator(
229 children,
230 &scope,
231 Generator::from_loop(widget.children, for_loop.binding, len),
232 self.filter,
233 self.parent_component,
234 );
235
236 children.inner_each(ctx, f)
237 }
238 WidgetKind::Iteration(iteration) => {
239 let loop_index = *iteration.loop_index.to_ref() as usize;
240 let scope = Scope::with_index(
241 iteration.binding,
242 loop_index,
243 self.scope,
244 iteration.loop_index.reference(),
245 );
246 let mut children = LayoutForEach::with_generator(
247 children,
248 &scope,
249 Generator::from(&*widget),
250 self.filter,
251 self.parent_component,
252 );
253 children.inner_each(ctx, f)
254 }
255 WidgetKind::Component(component) => {
256 let parent_component = component.widget_id;
257 let state_id = component.state_id();
258 let scope = Scope::with_component(state_id, component.widget_id, Some(self.scope));
259 let mut children = LayoutForEach::with_generator(
260 children,
261 &scope,
262 Generator::from(&*widget),
263 self.filter,
264 Some(parent_component),
265 );
266 children.inner_each(ctx, f)
267 }
268 WidgetKind::ControlFlowContainer(_) => {
269 let mut children = LayoutForEach::with_generator(
270 children,
271 self.scope,
272 Generator::from(&*widget),
273 self.filter,
274 self.parent_component,
275 );
276 children.inner_each(ctx, f)
277 }
278 WidgetKind::Slot => {
279 let mut children = LayoutForEach::with_generator(
280 children,
281 self.scope.outer(),
282 Generator::from(&*widget),
283 self.filter,
284 self.parent_component,
285 );
286 children.inner_each(ctx, f)
287 }
288 }
289 })
290 .unwrap_or(Ok(ControlFlow::Continue(())))
291 }
292
293 pub(crate) fn len(&self) -> usize {
294 self.tree.layout_len()
295 }
296}
297
298fn generate<'bp>(
302 parent: Generator<'_, 'bp>,
303 tree: &mut WidgetTreeView<'_, 'bp>,
304 ctx: &mut LayoutCtx<'_, 'bp>,
305 scope: &Scope<'_, 'bp>,
306 parent_component: Option<WidgetId>,
307) -> Result<bool> {
308 match parent {
309 Generator::Single { body: blueprints, .. }
310 | Generator::Iteration { body: blueprints, .. }
311 | Generator::ControlFlowContainer(blueprints) => {
312 if blueprints.is_empty() {
313 return Ok(false);
314 }
315
316 let index = tree.layout_len();
317 if index >= blueprints.len() {
318 return Ok(false);
319 }
320
321 let mut ctx = ctx.eval_ctx(parent_component);
322 eval_blueprint(&blueprints[index], &mut ctx, scope, tree.offset, tree)?;
325 Ok(true)
326 }
327
328 Generator::Slot(blueprints) => {
329 if blueprints.is_empty() {
330 return Ok(false);
331 }
332
333 let index = tree.layout_len();
334 if index >= blueprints.len() {
335 return Ok(false);
336 }
337
338 let mut ctx = ctx.eval_ctx(parent_component);
339 eval_blueprint(&blueprints[index], &mut ctx, scope, tree.offset, tree).unwrap();
340 Ok(true)
341 }
342 Generator::Loop { len, .. } if len == tree.layout_len() => Ok(false),
343 Generator::Loop { binding, body, .. } => {
344 let loop_index = tree.layout_len();
345
346 let transaction = tree.insert(tree.offset);
347 let widget = WidgetKind::Iteration(Iteration {
348 loop_index: StateValue::new(loop_index as i64),
349 binding,
350 });
351 let widget = WidgetContainer::new(widget, body);
352 transaction.commit_child(widget).unwrap();
355 Ok(true)
356 }
357 Generator::ControlFlow(controlflow) => {
358 let child_count = tree.layout_len();
359 assert_eq!(child_count.saturating_sub(1), 0, "too many branches have been created");
360
361 let should_create = {
365 if child_count == 0 {
366 true
367 } else {
368 let node_id = tree.layout[0].value();
369 let (_, widget) = tree
370 .values
371 .get(node_id)
372 .expect("because the node exists, the value exist");
373
374 let is_true = match &widget.kind {
375 WidgetKind::ControlFlowContainer(id) => controlflow.elses[*id as usize].is_true(),
376 _ => unreachable!("the child of `ControlFlow` can only be `Else`"),
377 };
378
379 if is_true {
381 return Ok(false);
382 }
383
384 is_true
385 }
386 };
387
388 if !should_create {
389 return Ok(false);
390 }
391
392 let thing = controlflow
393 .elses
394 .iter()
395 .enumerate()
396 .filter_map(|(id, node)| {
397 let cond = match node.cond.as_ref() {
401 Some(val) => val.truthiness(),
402 None => true,
403 };
404 match cond {
405 true => Some((id, node.body)),
406 false => None,
407 }
408 })
409 .next();
410
411 match thing {
412 Some((id, body)) => {
413 let kind = WidgetKind::ControlFlowContainer(id as u16);
414 let widget = WidgetContainer::new(kind, body);
415 let transaction = tree.insert(tree.offset);
416 transaction.commit_child(widget);
417 }
418 None => return Ok(false),
419 }
420
421 Ok(true)
422 }
423 }
424}
425
426#[derive(Debug)]
427pub enum FilterOutput<T, F> {
428 Include(T, F),
429 Exclude,
430 Continue,
431}
432
433pub trait Filter<'bp>: std::fmt::Debug + Copy {
434 type Output: std::fmt::Debug;
435
436 fn filter<'a>(
437 &mut self,
438 widget: &'a mut WidgetContainer<'bp>,
439 attribute_storage: &AttributeStorage<'_>,
440 ) -> FilterOutput<&'a mut Self::Output, Self>;
441}
442
443#[derive(Debug)]
447pub struct ForEach<'a, 'bp, Fltr> {
448 tree: WidgetTreeView<'a, 'bp>,
449 attribute_storage: &'a AttributeStorage<'bp>,
450 pub filter: Fltr,
451}
452
453impl<'a, 'bp, Fltr: Filter<'bp>> ForEach<'a, 'bp, Fltr> {
454 pub fn new(tree: WidgetTreeView<'a, 'bp>, attribute_storage: &'a AttributeStorage<'bp>, filter: Fltr) -> Self {
455 Self {
456 tree,
457 attribute_storage,
458 filter,
459 }
460 }
461
462 pub fn each<F>(&mut self, mut f: F) -> ControlFlow<()>
463 where
464 F: FnMut(&mut Fltr::Output, ForEach<'_, 'bp, Fltr>) -> ControlFlow<()>,
465 {
466 self.inner_each(&mut f)
467 }
468
469 fn inner_each<F>(&mut self, f: &mut F) -> ControlFlow<()>
470 where
471 F: FnMut(&mut Fltr::Output, ForEach<'_, 'bp, Fltr>) -> ControlFlow<()>,
472 {
473 for index in 0..self.tree.layout_len() {
474 _ = self.process(index, f);
475 }
476
477 ControlFlow::Continue(())
478 }
479
480 fn process<F>(&mut self, index: usize, f: &mut F) -> ControlFlow<()>
481 where
482 F: FnMut(&mut Fltr::Output, ForEach<'_, 'bp, Fltr>) -> ControlFlow<()>,
483 {
484 let Some(node) = self.tree.layout.get(index) else { panic!() };
485 self.tree
486 .with_value_mut(node.value(), |_, widget, children| {
487 match self.filter.filter(widget, self.attribute_storage) {
488 FilterOutput::Include(el, filter) => f(el, ForEach::new(children, self.attribute_storage, filter)),
489 FilterOutput::Exclude => ControlFlow::Break(()),
490 FilterOutput::Continue => ForEach::new(children, self.attribute_storage, self.filter).inner_each(f),
491 }
492 })
493 .unwrap() }
495}