1use crate::*;
2
3impl PartialEq for TextNode {
8 fn eq(&self, other: &Self) -> bool {
9 self.get_content() == other.get_content()
10 }
11}
12
13impl<T: Clone> Clone for VirtualNode<T> {
15 fn clone(&self) -> Self {
16 match self {
17 Self::Element {
18 tag,
19 attributes,
20 children,
21 key,
22 props,
23 } => Self::Element {
24 tag: tag.clone(),
25 attributes: attributes.clone(),
26 children: children.clone(),
27 key: key.clone(),
28 props: props.clone(),
29 },
30 Self::Text(text_node) => Self::Text(text_node.clone()),
31 Self::Fragment(children) => Self::Fragment(children.clone()),
32 Self::Dynamic(dynamic_node) => Self::Dynamic(dynamic_node.clone()),
33 Self::Empty => Self::Empty,
34 }
35 }
36}
37
38impl<T: std::fmt::Debug> std::fmt::Debug for VirtualNode<T> {
42 fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
43 match self {
44 Self::Element {
45 tag,
46 attributes,
47 children,
48 key,
49 props,
50 } => formatter
51 .debug_struct("Element")
52 .field("tag", tag)
53 .field("attributes", attributes)
54 .field("children", children)
55 .field("key", key)
56 .field("props", props)
57 .finish(),
58 Self::Text(text_node) => formatter.debug_tuple("Text").field(text_node).finish(),
59 Self::Fragment(children) => formatter.debug_tuple("Fragment").field(children).finish(),
60 Self::Dynamic(_) => formatter.debug_tuple("Dynamic").finish(),
61 Self::Empty => formatter.debug_tuple("Empty").finish(),
62 }
63 }
64}
65
66impl<T> Default for VirtualNode<T> {
68 fn default() -> Self {
69 Self::Empty
70 }
71}
72
73impl<T: PartialEq> PartialEq for VirtualNode<T> {
83 fn eq(&self, other: &Self) -> bool {
84 match (self, other) {
85 (VirtualNode::Text(old_text), VirtualNode::Text(new_text)) => old_text == new_text,
86 (
87 VirtualNode::Element {
88 tag: old_tag,
89 attributes: old_attrs,
90 children: old_children,
91 props: old_props,
92 ..
93 },
94 VirtualNode::Element {
95 tag: new_tag,
96 attributes: new_attrs,
97 children: new_children,
98 props: new_props,
99 ..
100 },
101 ) => {
102 old_tag == new_tag
103 && old_attrs.len() == new_attrs.len()
104 && old_attrs.iter().zip(new_attrs.iter()).all(
105 |(old_attr, new_attr): (&AttributeEntry, &AttributeEntry)| {
106 old_attr == new_attr
107 },
108 )
109 && old_children.len() == new_children.len()
110 && old_children.iter().zip(new_children.iter()).all(
111 |(old_child, new_child): (&VirtualNode, &VirtualNode)| {
112 old_child == new_child
113 },
114 )
115 && old_props == new_props
116 }
117 (VirtualNode::Fragment(old_children), VirtualNode::Fragment(new_children)) => {
118 old_children.len() == new_children.len()
119 && old_children.iter().zip(new_children.iter()).all(
120 |(old_child, new_child): (&VirtualNode, &VirtualNode)| {
121 old_child == new_child
122 },
123 )
124 }
125 (VirtualNode::Dynamic(_), VirtualNode::Dynamic(_)) => false,
126 (VirtualNode::Empty, VirtualNode::Empty) => true,
127 _ => false,
128 }
129 }
130}
131
132impl Default for DynamicNode {
134 fn default() -> Self {
135 let render_fn_inner: Rc<RefCell<RenderFnInner>> =
136 Rc::new(RefCell::new(RenderFnInner::new(Box::new(|| {
137 VirtualNode::Empty
138 }))));
139 Self::new(render_fn_inner, HookContext::default())
140 }
141}
142
143impl Clone for DynamicNode {
145 fn clone(&self) -> Self {
146 let cloned: Self = Self::new(
147 self.get_render_fn().clone(),
148 self.get_hook_context().clone(),
149 );
150 cloned
151 }
152}
153
154impl DynamicNode {
156 pub(crate) fn get_hook_context_value(&self) -> HookContext {
162 self.get_hook_context().clone()
163 }
164
165 pub fn render(&self) -> VirtualNode {
171 let mut inner: RefMut<RenderFnInner> = self.get_render_fn().borrow_mut();
172 (inner.get_mut_render_fn())()
173 }
174}
175
176impl<T> VirtualNode<T> {
178 pub fn try_get_tag_name(&self) -> Option<String> {
184 match self {
185 Self::Element { tag, .. } => match tag {
186 Tag::Element(name) => Some(name.clone()),
187 Tag::Component(name) => Some(name.clone()),
188 },
189 _ => None,
190 }
191 }
192
193 pub fn try_get_children(&self) -> Option<&Vec<VirtualNode>> {
201 match self {
202 Self::Element { children, .. } => Some(children),
203 Self::Fragment(children) => Some(children),
204 _ => None,
205 }
206 }
207
208 pub fn has_children(&self) -> bool {
214 self.try_get_children()
215 .is_some_and(|children: &Vec<VirtualNode>| !children.is_empty())
216 }
217
218 pub fn try_get_props(&self) -> Option<&T> {
226 match self {
227 Self::Element { props, .. } => props.as_deref(),
228 _ => None,
229 }
230 }
231
232 pub fn try_take_props(&mut self) -> Option<T> {
238 match self {
239 Self::Element { props, .. } => props.take().map(|boxed: Box<T>| *boxed),
240 _ => None,
241 }
242 }
243
244 pub fn take_children(&mut self) -> VirtualNode {
252 match self {
253 Self::Element { children, .. } => {
254 let taken: Vec<VirtualNode> = take(children);
255 match taken.len() {
256 0 => VirtualNode::Empty,
257 1 => taken.into_iter().next().unwrap_or(VirtualNode::Empty),
258 _ => VirtualNode::Fragment(taken),
259 }
260 }
261 Self::Fragment(children) => {
262 let taken: Vec<VirtualNode> = take(children);
263 match taken.len() {
264 0 => VirtualNode::Empty,
265 1 => taken.into_iter().next().unwrap_or(VirtualNode::Empty),
266 _ => VirtualNode::Fragment(taken),
267 }
268 }
269 _ => VirtualNode::Empty,
270 }
271 }
272}
273
274impl VirtualNode<()> {
276 pub fn create_dynamic<F>(mut render_fn: F) -> Self
288 where
289 F: FnMut() -> Self + 'static,
290 {
291 let hook_context: HookContext = create_hook_context();
292 let mut hook_context_for_closure: HookContext = hook_context.clone();
293 let inner: Rc<RefCell<RenderFnInner>> =
294 Rc::new(RefCell::new(RenderFnInner::new(Box::new(move || {
295 hook_context_for_closure.reset_hook_index();
296 render_fn()
297 }))));
298 let dynamic_node: DynamicNode = DynamicNode::new(inner, hook_context);
299 Self::Dynamic(dynamic_node)
300 }
301
302 pub fn create_dynamic_with_context<F>(mut render_fn: F) -> Self
316 where
317 F: FnMut(&mut HookContext) -> Self + 'static,
318 {
319 let hook_context: HookContext = create_hook_context();
320 let mut hook_context_for_closure: HookContext = hook_context.clone();
321 let inner: Rc<RefCell<RenderFnInner>> =
322 Rc::new(RefCell::new(RenderFnInner::new(Box::new(move || {
323 hook_context_for_closure.reset_hook_index();
324 render_fn(&mut hook_context_for_closure)
325 }))));
326 let dynamic_node: DynamicNode = DynamicNode::new(inner, hook_context);
327 Self::Dynamic(dynamic_node)
328 }
329}