hirola_core/templating/
switch.rs

1use 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}