react/node/
node.rs

1use wasm_bindgen::JsValue;
2
3use crate::{AnyNode, AnyNodeValue, Children, IntoElement, Keyed};
4
5/// Corresponding to `ReactNode` in typescript
6///
7/// ```typescript
8/// type ReactNode = ReactElement | string | number | ReactNodeArray | boolean | null | undefined;
9/// ```
10pub trait Node {
11    fn to_node(&self) -> AnyNode;
12
13    #[inline]
14    fn to_children(&self) -> Option<Children> {
15        Some(Children::from_single(self.to_node()))
16    }
17
18    #[inline]
19    fn into_node(self) -> AnyNode
20    where
21        Self: Sized,
22    {
23        self.to_node()
24    }
25
26    #[inline]
27    fn into_children(self) -> Option<Children>
28    where
29        Self: Sized,
30    {
31        self.to_children()
32    }
33}
34
35impl Node for () {
36    #[inline]
37    fn to_node(&self) -> AnyNode {
38        AnyNode::Null
39    }
40
41    #[inline]
42    fn to_children(&self) -> Option<Children> {
43        None
44    }
45}
46
47impl<T: Node> Node for Option<T> {
48    #[inline]
49    fn to_node(&self) -> AnyNode {
50        if let Some(node) = self {
51            node.to_node()
52        } else {
53            AnyNode::Null
54        }
55    }
56
57    #[inline]
58    fn to_children(&self) -> Option<Children> {
59        self.as_ref().and_then(Node::to_children)
60    }
61
62    #[inline]
63    fn into_node(self) -> AnyNode {
64        self.map(Node::into_node).unwrap_or(AnyNode::Null)
65    }
66
67    #[inline]
68    fn into_children(self) -> Option<Children> {
69        self.and_then(Node::into_children)
70    }
71}
72
73macro_rules! into_js_node {
74    (into_f64: $($n:ty)*) => ($(
75        impl Node for $n {
76            #[inline]
77            fn to_node(&self) -> AnyNode {
78                (*self).into_node()
79            }
80            #[inline]
81            fn into_node(self) -> AnyNode {
82                AnyNode::Value(AnyNodeValue::unsafe_from_js_react_node(JsValue::from_f64(self.into())))
83            }
84        }
85    )*);
86    (deref: $($n:ty)*) => ($(
87        impl Node for $n {
88            #[inline]
89            fn to_node(&self) -> AnyNode {
90                AnyNode::Value(AnyNodeValue::unsafe_from_js_react_node(JsValue::from(*self)))
91            }
92        }
93    )*);
94    (bigint_to_string: $($n:ty)*) => ($(
95        impl Node for $n {
96            #[inline]
97            fn to_node(&self) -> AnyNode {
98                (*self).into_node()
99            }
100            #[inline]
101            fn into_node(self) -> AnyNode {
102                let js_bigint = js_sys::BigInt::from(self);
103                let js_string = js_bigint.to_string(10).unwrap();
104                AnyNode::Value(AnyNodeValue::unsafe_from_js_react_node(JsValue::from(js_string)))
105            }
106        }
107    )*);
108    ($($n:ty)*) => ($(
109        impl Node for $n {
110            #[inline]
111            fn to_node(&self) -> AnyNode {
112                AnyNode::Value(AnyNodeValue::unsafe_from_js_react_node(JsValue::from(self)))
113            }
114        }
115    )*);
116}
117
118into_js_node! {
119    str
120    react_sys::Element
121    String
122    js_sys::JsString
123    js_sys::Number
124    js_sys::BigInt
125    js_sys::Boolean
126}
127
128into_js_node! {
129    into_f64:
130    // numbers https://docs.rs/wasm-bindgen/0.2.78/src/wasm_bindgen/lib.rs.html#849
131    i8 u8 i16 u16 i32 u32 f32 f64
132}
133
134into_js_node! {
135    bigint_to_string:
136    // big_numbers https://docs.rs/wasm-bindgen/0.2.78/src/wasm_bindgen/lib.rs.html#869
137    i64 u64 i128 u128 isize usize
138}
139
140into_js_node! {
141    deref:
142    bool
143}
144
145#[inline]
146fn into_keyed_element<E: IntoElement>(el: Keyed<E>) -> Keyed<crate::Element> {
147    Keyed(el.0.into_element())
148}
149
150#[inline]
151fn option_into_keyed_element<E: IntoElement>(
152    el: Option<Keyed<E>>,
153) -> Option<Keyed<crate::Element>> {
154    el.map(into_keyed_element)
155}
156
157macro_rules! impl_node_for_iter {
158    (impl into_children) => {
159        #[inline]
160        fn into_children(self) -> Option<Children> {
161            Some(Children::from_single(self.into_node()))
162        }
163    };
164    (impl sized) => {
165        #[inline]
166        fn into_node(self) -> AnyNode {
167            AnyNode::Multiple(std::rc::Rc::new(self.into_iter().map(into_keyed_element).collect()))
168        }
169
170        impl_node_for_iter! { impl into_children }
171    };
172    (impl sized opt) => {
173        #[inline]
174        fn into_node(self) -> AnyNode {
175            AnyNode::Multiple(std::rc::Rc::new(
176                self.into_iter()
177                    .filter_map(option_into_keyed_element)
178                    .collect()
179            ))
180        }
181
182        impl_node_for_iter! { impl into_children }
183
184    };
185    ( $($sized:ident)? {$($t:tt)+} {$($t_opt:tt)+}) => {
186        $($t)+ {
187            #[inline]
188            fn to_node(&self) -> AnyNode {
189                self.to_vec().into_node()
190            }
191
192            $( impl_node_for_iter! { impl $sized } )?
193        }
194        $($t_opt)+ {
195            #[inline]
196            fn to_node(&self) -> AnyNode {
197                self.iter().filter_map(Clone::clone).collect::<Vec<_>>().into_node()
198            }
199
200            $( impl_node_for_iter! { impl $sized opt } )?
201        }
202    };
203}
204
205impl_node_for_iter! {
206    sized
207    { impl<E: IntoElement + Clone> Node for Vec<Keyed<E>> }
208    { impl<E: IntoElement + Clone> Node for Vec<Option<Keyed<E>>> }
209}
210impl_node_for_iter! {
211    { impl<E: IntoElement + Clone> Node for [Keyed<E>] }
212    { impl<E: IntoElement + Clone> Node for [Option<Keyed<E>>] }
213}
214impl_node_for_iter! {
215    sized
216    { impl<E: IntoElement + Clone, const S: usize> Node for [Keyed<E>; S] }
217    { impl<E: IntoElement + Clone, const S: usize> Node for [Option<Keyed<E>>; S] }
218}
219
220macro_rules! impl_node_for_tuple {
221    (@impl ( $($t:ident),+ $(,)? )) => {
222        impl<$($t: Node),+> Node for ($($t),+ ,) {
223            #[inline]
224            fn to_node(&self) -> AnyNode {
225                #![allow(non_snake_case)]
226                let ($($t),+ ,) = self;
227                let v = Children::from_static_nodes([
228                    $($t.to_node()),+
229                ]);
230                v.to_node()
231            }
232            #[inline]
233            fn to_children(&self) -> Option<Children> {
234                #![allow(non_snake_case)]
235                let ($($t),+ ,) = self;
236                let v = Children::from_static_nodes([
237                    $($t.to_node()),+
238                ]);
239                Some(v)
240            }
241            #[inline]
242            fn into_node(self) -> AnyNode {
243                #![allow(non_snake_case)]
244                let ($($t),+ ,) = self;
245                let v = Children::from_static_nodes([
246                    $($t.into_node()),+
247                ]);
248                v.into_node()
249            }
250            #[inline]
251            fn into_children(self) -> Option<Children> {
252                #![allow(non_snake_case)]
253                let ($($t),+ ,) = self;
254                Some(Children::from_static_nodes([
255                    $($t.into_node()),+
256                ]))
257            }
258        }
259    };
260    ( $(( $($t:ident),+ $(,)? ))* ) => {
261        $(
262            impl_node_for_tuple! { @impl ($($t),+ ,) }
263        )*
264    };
265}
266
267impl_node_for_tuple! {
268    (T0,)
269    (T0,T1)
270    (T0,T1,T2)
271    (T0,T1,T2,T3)
272    (T0,T1,T2,T3,T4)
273    (T0,T1,T2,T3,T4,T5)
274    (T0,T1,T2,T3,T4,T5,T6)
275    (T0,T1,T2,T3,T4,T5,T6,T7)
276    (T0,T1,T2,T3,T4,T5,T6,T7,T8)
277    (T0,T1,T2,T3,T4,T5,T6,T7,T8,T9)
278    (T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10)
279    (T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11)
280    (T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12)
281    (T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13)
282    (T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14)
283    (T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15)
284    (T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16)
285}
286
287impl<N: Node> Node for Box<N> {
288    #[inline]
289    fn to_node(&self) -> AnyNode {
290        self.as_ref().to_node()
291    }
292    #[inline]
293    fn to_children(&self) -> Option<Children> {
294        self.as_ref().to_children()
295    }
296    #[inline]
297    fn into_node(self) -> AnyNode {
298        (*self).into_node()
299    }
300    #[inline]
301    fn into_children(self) -> Option<Children> {
302        (*self).into_children()
303    }
304}
305
306impl<N: ?Sized + Node> Node for &N {
307    #[inline]
308    fn to_node(&self) -> AnyNode {
309        (*self).to_node()
310    }
311
312    #[inline]
313    fn to_children(&self) -> Option<Children> {
314        (*self).to_children()
315    }
316}