wasm_react/
vnode.rs

1#![allow(non_snake_case)]
2
3use js_sys::{Array, JsString};
4use wasm_bindgen::JsValue;
5
6/// Represents a node in the virtual DOM of React.
7#[non_exhaustive]
8#[derive(Debug, Clone)]
9pub enum VNode {
10  /// Represents a single virtual node.
11  Single(JsValue),
12  /// Represents an array of virtual nodes.
13  List(Array),
14}
15
16impl VNode {
17  /// Creates an empty node that doesn't render anything.
18  pub fn new() -> VNode {
19    VNode::Single(JsValue::null())
20  }
21
22  /// Adds the given node to the list.
23  pub fn push(&mut self, node: &VNode) {
24    match self {
25      VNode::Single(x) => {
26        *self = VNode::List({
27          let arr = Array::new();
28
29          if !x.is_null() {
30            arr.push(x);
31          }
32
33          arr.push(node.as_ref());
34          arr
35        });
36      }
37      VNode::List(arr) => {
38        arr.push(node.as_ref());
39      }
40    }
41  }
42}
43
44impl Default for VNode {
45  fn default() -> Self {
46    Self::new()
47  }
48}
49
50impl AsRef<JsValue> for VNode {
51  fn as_ref(&self) -> &JsValue {
52    match self {
53      VNode::Single(x) => x,
54      VNode::List(x) => x,
55    }
56  }
57}
58
59impl From<VNode> for JsValue {
60  fn from(value: VNode) -> Self {
61    match value {
62      VNode::Single(x) => x,
63      VNode::List(x) => x.into(),
64    }
65  }
66}
67
68impl<T: Into<VNode>> From<Option<T>> for VNode {
69  fn from(value: Option<T>) -> Self {
70    value.map(|value| value.into()).unwrap_or_default()
71  }
72}
73
74impl Extend<VNode> for VNode {
75  fn extend<T: IntoIterator<Item = VNode>>(&mut self, iter: T) {
76    for node in iter.into_iter() {
77      self.push(&node);
78    }
79  }
80}
81
82impl FromIterator<VNode> for VNode {
83  fn from_iter<T: IntoIterator<Item = VNode>>(iter: T) -> Self {
84    let mut result = Self::new();
85
86    for node in iter.into_iter() {
87      result.push(&node);
88    }
89
90    result
91  }
92}
93
94macro_rules! impl_into_vnode {
95  { $( $T:ty ),* $(,)? } => {
96    $(
97      impl From<$T> for VNode {
98        fn from(value: $T) -> Self {
99          VNode::Single(value.into())
100        }
101      }
102    )*
103  };
104}
105
106// Implement `Into<VNode>` for as many `Display` types as possible
107impl_into_vnode! {
108  &str, String, JsString,
109  f32, f64,
110  i8, i16, i32, i64, i128, isize,
111  u8, u16, u32, u64, u128, usize,
112}
113
114impl From<()> for VNode {
115  fn from(_: ()) -> Self {
116    VNode::new()
117  }
118}
119
120macro_rules! impl_into_vnode_for_tuples {
121  (@impl) => {};
122  (@impl $( $x:ident ),+) => {
123    impl<$( $x, )+> From<($( $x, )+)> for VNode
124    where $( $x: Into<VNode>, )+
125    {
126      fn from(($( $x, )+): ($( $x, )+)) -> VNode {
127        let mut result = VNode::new();
128        $( result.push(&$x.into()); )+
129        result
130      }
131    }
132
133    impl_into_vnode_for_tuples!(@next $( $x ),+);
134  };
135  (@next $first:ident) => {};
136  (@next $first:ident, $( $tt:tt )*) => {
137    impl_into_vnode_for_tuples!(@impl $( $tt )*);
138  };
139  ($( $x:ident ),*) => {
140    impl_into_vnode_for_tuples!(@impl $( $x ),*);
141  }
142}
143
144impl_into_vnode_for_tuples!(
145  A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z
146);