1use crate::{
3 generic_node::GenericNode,
4 templating::flow::{Indexed, IndexedProps},
5};
6use futures_signals::{
7 signal::{Mutable, ReadOnlyMutable, SignalExt},
8 signal_vec::{Filter, MutableSignalVec, MutableVec, SignalVec, SignalVecExt},
9};
10use std::{
11 fmt::{Debug, Display},
12 iter::Enumerate,
13 pin::Pin,
14};
15
16#[derive(Debug)]
17pub enum Error {
18 DomError(Box<dyn Debug>),
19}
20
21pub trait Render<N: GenericNode> {
23 fn render_into(self: Box<Self>, parent: &N) -> Result<(), Error>;
25}
26
27impl<N: GenericNode> Render<N> for () {
29 fn render_into(self: Box<Self>, _dom: &N) -> Result<(), Error> {
30 Ok(())
31 }
32}
33
34impl<N: GenericNode> Render<N> for &str {
35 fn render_into(self: Box<Self>, parent: &N) -> Result<(), Error> {
36 let child = &N::text_node(*self);
37 parent.append_child(child);
38 Ok(())
39 }
40}
41
42impl<N: GenericNode> Render<N> for String {
43 fn render_into(self: Box<Self>, parent: &N) -> Result<(), Error> {
44 let child = &N::text_node(&self);
45 parent.append_child(child);
46 Ok(())
47 }
48}
49
50impl<N: GenericNode> Render<N> for &String {
51 fn render_into(self: Box<Self>, parent: &N) -> Result<(), Error> {
52 let child = &N::text_node(&self);
53 parent.append_child(child);
54 Ok(())
55 }
56}
57
58impl<A: Render<N>, B: Render<N>, N: GenericNode> Render<N> for (A, B) {
60 fn render_into(self: Box<Self>, parent: &N) -> Result<(), Error> {
61 Box::new(self.0).render_into(parent)?;
62 Box::new(self.1).render_into(parent)
63 }
64}
65
66impl<A: Render<N>, B: Render<N>, C: Render<N>, N: GenericNode> Render<N> for (A, B, C) {
68 fn render_into(self: Box<Self>, parent: &N) -> Result<(), Error> {
69 Box::new(self.0).render_into(parent)?;
70 Box::new(self.1).render_into(parent)?;
71 Box::new(self.2).render_into(parent)
72 }
73}
74
75impl<T: Render<N>, N: GenericNode> Render<N> for Option<T> {
77 fn render_into(self: Box<Self>, parent: &N) -> Result<(), Error> {
78 match *self {
79 None => Ok(()),
80 Some(x) => Box::new(x).render_into(parent),
81 }
82 }
83}
84
85impl<T: Render<N>, N: GenericNode> Render<N> for Vec<T> {
86 fn render_into(self: Box<Self>, parent: &N) -> Result<(), Error> {
87 for elem in *self {
88 Box::new(elem).render_into(parent)?;
89 }
90 Ok(())
91 }
92}
93
94impl<T: Render<N>, N: GenericNode> Render<N> for Box<T> {
95 fn render_into(self: Box<Self>, parent: &N) -> Result<(), Error> {
96 (*self).render_into(parent)?;
97 Ok(())
98 }
99}
100
101impl<T: Display + Clone + 'static, N: GenericNode> Render<N> for Mutable<T> {
102 fn render_into(self: Box<Self>, parent: &N) -> Result<(), Error> {
103 let child = N::text_node(&self.get_cloned().to_string());
104 parent.append_child(&child);
105 let fut = self.signal_ref(move |e| child.update_inner_text(&e.to_string()));
106 parent.effect(fut.to_future());
107 Ok(())
108 }
109}
110
111pub struct MappedVec<T, G: GenericNode> {
112 pub iter: Pin<Box<dyn SignalVec<Item = T>>>,
113 callback: Box<dyn Fn(T) -> G>,
114}
115
116pub trait MapRender<G: GenericNode> {
122 type Item;
123 type Output;
124 fn map_render(self, callback: impl Fn(Self::Item) -> G + 'static) -> Self::Output;
125}
126
127impl<T: Clone + 'static, G: GenericNode> MapRender<G> for MutableSignalVec<T> {
128 type Item = T;
129 type Output = MappedVec<Self::Item, G>;
130 fn map_render(self, callback: impl Fn(Self::Item) -> G + 'static) -> MappedVec<Self::Item, G> {
131 MappedVec {
132 iter: Box::pin(self),
133 callback: Box::new(callback),
134 }
135 }
136}
137
138impl<
151 T: Clone + 'static,
152 I: SignalVec<Item = T> + 'static,
153 F: FnMut(&T) -> bool + 'static,
154 G: GenericNode,
155 > MapRender<G> for Filter<I, F>
156{
157 type Item = T;
158 type Output = MappedVec<Self::Item, G>;
159
160 fn map_render(self, callback: impl Fn(Self::Item) -> G + 'static) -> MappedVec<Self::Item, G> {
161 MappedVec {
162 iter: Box::pin(self),
163 callback: Box::new(callback),
164 }
165 }
166}
167
168impl<T: Clone + 'static, I: Iterator<Item = T>, G: GenericNode> MapRender<G> for Enumerate<I> {
169 type Item = (usize, T);
170 type Output = MappedVec<Self::Item, G>;
171
172 fn map_render(self, callback: impl Fn(Self::Item) -> G + 'static) -> MappedVec<Self::Item, G> {
173 let items = self.collect();
174 MappedVec {
175 iter: Box::pin(MutableVec::new_with_values(items).signal_vec_cloned()),
176 callback: Box::new(callback),
177 }
178 }
179}
180
181impl<T: Clone + 'static + PartialEq, I: SignalVec<Item = T> + Unpin + 'static, G: GenericNode>
182 MapRender<G> for futures_signals::signal_vec::Enumerate<I>
183{
184 type Item = (ReadOnlyMutable<Option<usize>>, T);
185 type Output = MappedVec<Self::Item, G>;
186
187 fn map_render(self, callback: impl Fn(Self::Item) -> G + 'static) -> MappedVec<Self::Item, G> {
188 MappedVec {
189 iter: Box::pin(self.to_signal_cloned().to_signal_vec()),
190 callback: Box::new(callback),
191 }
192 }
193}
194
195impl<T: Clone + 'static, G: GenericNode> MapRender<G> for Vec<T> {
196 type Item = T;
197 type Output = MappedVec<Self::Item, G>;
198
199 fn map_render(self, callback: impl Fn(Self::Item) -> G + 'static) -> MappedVec<Self::Item, G> {
200 MappedVec {
201 iter: Box::pin(MutableVec::new_with_values(self).signal_vec_cloned()),
202 callback: Box::new(callback),
203 }
204 }
205}
206
207impl<T: 'static + Clone, N: GenericNode> Render<N> for MappedVec<T, N> {
208 fn render_into(self: Box<Self>, parent: &N) -> Result<(), Error> {
209 let template = {
210 #[allow(clippy::type_complexity)]
211 let props: IndexedProps<
212 T,
213 Pin<Box<dyn SignalVec<Item = T>>>,
214 Box<dyn Fn(T) -> N>,
215 N,
216 > = IndexedProps {
217 iterable: self.iter,
218 template: self.callback,
219 };
220
221 Indexed { props }
222 };
223 Box::new(template).render_into(parent)?;
224 Ok(())
225 }
226}
227
228impl<O: Render<N>, E: Render<N>, N: GenericNode> Render<N> for std::result::Result<O, E> {
230 fn render_into(self: Box<Self>, parent: &N) -> Result<(), Error> {
231 match *self {
232 Ok(o) => Box::new(o).render_into(parent),
233 Err(e) => Box::new(e).render_into(parent),
234 }
235 }
236}