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