1#![allow(non_snake_case)]
2
3use js_sys::{Array, JsString};
4use wasm_bindgen::JsValue;
5
6#[non_exhaustive]
8#[derive(Debug, Clone)]
9pub enum VNode {
10 Single(JsValue),
12 List(Array),
14}
15
16impl VNode {
17 pub fn new() -> VNode {
19 VNode::Single(JsValue::null())
20 }
21
22 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
106impl_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);