hirola_core/templating/
switch.rs1use std::{cell::RefCell, rc::Rc};
2
3use futures_signals::signal::{Signal, SignalExt};
4
5use crate::{
6 generic_node::GenericNode,
7 render::{Error, Render},
8};
9
10pub struct Switch<S: Signal<Item = bool>, F, G>
11where
12 F: Fn(bool) -> G,
13{
14 pub signal: S,
15 pub renderer: F,
16}
17
18impl<S, F, N: GenericNode> Render<N> for Switch<S, F, N>
19where
20 F: Fn(bool) -> N + 'static,
21 S: Signal<Item = bool> + 'static,
22{
23 fn render_into(self: Box<Self>, parent: &N) -> Result<(), Error> {
24 let marker = N::marker();
25 parent.append_child(&marker);
26 let state = State::new(parent.clone(), marker);
27 let renderer = self.renderer;
28 struct State<DomType: GenericNode> {
29 holder: DomType,
30 marker: DomType,
31 current: Option<DomType>,
32 }
33
34 impl<DomType: GenericNode> State<DomType> {
35 fn new(element: DomType, marker: DomType) -> Rc<RefCell<Self>> {
36 Rc::new(RefCell::new(State {
37 holder: element,
38 current: None,
39 marker,
40 }))
41 }
42
43 fn clear(&mut self) {
44 {
45 let node = &mut self.holder;
46 if let Some(frag) = &self.current {
47 for child in &frag.children().take() {
48 node.remove_child(child)
49 }
50 };
51 }
52 self.current = None;
53 }
54
55 fn apply(&mut self, dom: DomType) {
56 self.clear();
57 let node = &self.holder;
58 node.insert_child_before(&dom, Some(&self.marker));
59 self.current = Some(dom);
60 }
61 }
62 let fut = self.signal.for_each(move |val| {
63 let mut state = state.borrow_mut();
64 state.apply(renderer(val));
65
66 async {}
67 });
68 parent.effect(fut);
69 Ok(())
70 }
71}