sauron_core/vdom/
node.rs

1use super::{AttributeName, Namespace, Tag};
2use crate::dom::SkipDiff;
3use crate::vdom::Attribute;
4use crate::vdom::AttributeValue;
5use crate::vdom::Element;
6use crate::vdom::Leaf;
7use crate::vdom::Value;
8use derive_where::derive_where;
9use std::fmt;
10use std::fmt::{Debug, Formatter};
11
12/// represents a node in a virtual dom
13/// A node could be an element which can contain one or more children of nodes.
14/// A node could also be just a text node which contains a string
15///
16/// Much of the types are Generics
17///
18/// Namespace - is the type for the namespace, this will be &'static str when used in html based virtual dom implementation
19/// Tag - is the type for the element tag, this will be &'static str when used in html based virtual
20/// dom impmenentation
21/// AttributeName - is the type for the attribute name, this will be &'static str when used in html based
22/// virtual dom implementation
23/// AttributeValue - is the type for the value of the attribute, this will be String, f64, or just another
24/// generics that suits the implementing library which used mt-dom for just dom-diffing purposes
25#[derive_where(Clone, Debug, PartialEq, Eq)]
26pub enum Node<MSG> {
27    /// Element variant of a virtual node
28    Element(Element<MSG>),
29    /// A Leaf node
30    Leaf(Leaf<MSG>),
31}
32
33#[derive(Debug, Copy, Clone)]
34pub enum Error {
35    AddChildrenNotAllowed,
36    AttributesNotAllowed,
37}
38
39impl fmt::Display for Error {
40    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
41        match self {
42            Self::AddChildrenNotAllowed => {
43                write!(f, "Adding children on this node variant is not allowed")
44            }
45            Self::AttributesNotAllowed => {
46                write!(
47                    f,
48                    "Adding or setting attibutes on this node variant is not allowed"
49                )
50            }
51        }
52    }
53}
54
55///TODO: use core::error when it will go out of nightly
56impl std::error::Error for Error {}
57
58impl<MSG> Node<MSG> {
59    /// consume self and return the element if it is an element variant
60    /// None if it is a text node
61    pub fn take_element(self) -> Option<Element<MSG>> {
62        match self {
63            Node::Element(element) => Some(element),
64            _ => None,
65        }
66    }
67
68    /// returns a reference to the Leaf if the node is a Leaf variant
69    pub fn leaf(&self) -> Option<&Leaf<MSG>> {
70        match self {
71            Node::Leaf(leaf) => Some(leaf),
72            _ => None,
73        }
74    }
75
76    /// returns true if the node is an element variant
77    pub fn is_element(&self) -> bool {
78        matches!(self, Node::Element(_))
79    }
80
81    /// returns true if the node is a Leaf
82    pub fn is_leaf(&self) -> bool {
83        matches!(self, Node::Leaf(_))
84    }
85
86    /// returns true if this is a text node
87    pub fn is_text(&self) -> bool {
88        match self {
89            Self::Leaf(leaf) => leaf.is_text(),
90            _ => false,
91        }
92    }
93
94    /// return the text if this is text node leaf
95    pub fn as_text(&self) -> Option<&str> {
96        match self {
97            Self::Leaf(ref leaf) => leaf.as_text(),
98            _ => None,
99        }
100    }
101
102    /// return the html entity if it is a symbol variant
103    pub fn as_symbol(&self) -> Option<&str> {
104        match self {
105            Self::Leaf(Leaf::Symbol(symbol)) => Some(symbol),
106            _ => None,
107        }
108    }
109
110    /// Get a mutable reference to the element, if this node is an element node
111    pub fn element_mut(&mut self) -> Option<&mut Element<MSG>> {
112        match *self {
113            Node::Element(ref mut element) => Some(element),
114            _ => None,
115        }
116    }
117
118    /// returns a reference to the element if this is an element node
119    pub fn element_ref(&self) -> Option<&Element<MSG>> {
120        match *self {
121            Node::Element(ref element) => Some(element),
122            _ => None,
123        }
124    }
125
126    /// Consume a mutable self and add a children to this node it if is an element
127    /// will have no effect if it is a text node.
128    /// This is used in building the nodes in a builder pattern
129    pub fn with_children(mut self, children: impl IntoIterator<Item = Node<MSG>>) -> Self {
130        if let Some(element) = self.element_mut() {
131            element.add_children(children);
132        } else {
133            panic!("Can not add children to a text node");
134        }
135        self
136    }
137
138    /// add children but not consume self
139    pub fn add_children(
140        &mut self,
141        children: impl IntoIterator<Item = Node<MSG>>,
142    ) -> Result<(), Error> {
143        if let Some(element) = self.element_mut() {
144            element.add_children(children);
145            Ok(())
146        } else {
147            Err(Error::AddChildrenNotAllowed)
148        }
149    }
150
151    /// add attributes to the node and returns itself
152    /// this is used in view building
153    pub fn with_attributes(mut self, attributes: impl IntoIterator<Item = Attribute<MSG>>) -> Self {
154        if let Some(elm) = self.element_mut() {
155            elm.add_attributes(attributes);
156        } else {
157            panic!("Can not add attributes to a text node");
158        }
159        self
160    }
161
162    /// add attributes using a mutable reference to self
163    pub fn add_attributes(
164        &mut self,
165        attributes: impl IntoIterator<Item = Attribute<MSG>>,
166    ) -> Result<(), Error> {
167        if let Some(elm) = self.element_mut() {
168            elm.add_attributes(attributes);
169            Ok(())
170        } else {
171            Err(Error::AttributesNotAllowed)
172        }
173    }
174
175    /// get the attributes of this node
176    /// returns None if it is a text node
177    pub fn attributes(&self) -> Option<&[Attribute<MSG>]> {
178        match self {
179            Node::Element(element) => Some(element.attributes()),
180            Node::Leaf(leaf) => leaf.attributes(),
181        }
182    }
183
184    /// returns the tag of this node if it is an element
185    /// otherwise None if it is a text node
186    pub fn tag(&self) -> Option<&Tag> {
187        if let Some(e) = self.element_ref() {
188            Some(&e.tag)
189        } else {
190            None
191        }
192    }
193
194    /// return the children of this node if it is an element
195    /// returns None if it is a text node
196    pub fn children(&self) -> &[Node<MSG>] {
197        match self {
198            Self::Element(elm) => elm.children(),
199            Self::Leaf(Leaf::StatefulComponent(comp)) => &comp.children,
200            _ => &[],
201        }
202    }
203
204    /// Return the count of the children of this node
205    pub fn children_count(&self) -> usize {
206        self.children().len()
207    }
208
209    /// return the children of this node if it is an element
210    /// returns None if it is a text node
211    pub fn children_mut(&mut self) -> Option<&mut [Node<MSG>]> {
212        if let Some(element) = self.element_mut() {
213            Some(element.children_mut())
214        } else {
215            None
216        }
217    }
218
219    /// Removes an child node  from this element and returns it.
220    ///
221    /// The removed child is replaced by the last child of the element's children.
222    ///
223    /// # Panics
224    /// Panics if this is a text node
225    ///
226    pub fn swap_remove_child(&mut self, index: usize) -> Node<MSG> {
227        match self {
228            Node::Element(element) => element.swap_remove_child(index),
229            _ => panic!("text has no child"),
230        }
231    }
232
233    /// Swaps the 2 child node in this element
234    ///
235    /// # Arguments
236    /// * a - The index of the first child node
237    /// * b - The index of the second child node
238    ///
239    /// # Panics
240    /// Panics if both `a` and `b` are out of bounds
241    /// Panics if this is a text node
242    pub fn swap_children(&mut self, a: usize, b: usize) {
243        match self {
244            Node::Element(element) => element.swap_children(a, b),
245            _ => panic!("text has no child"),
246        }
247    }
248
249    /// Returns the total number of nodes on this node tree, that is counting the direct and
250    /// indirect child nodes of this node.
251    pub fn node_count(&self) -> usize {
252        1 + self.descendant_node_count()
253    }
254
255    /// only count the descendant node
256    pub fn descendant_node_count(&self) -> usize {
257        let mut cnt = 0;
258        if let Node::Element(element) = self {
259            for child in element.children().iter() {
260                cnt += child.node_count();
261            }
262        }
263        cnt
264    }
265
266    /// remove the existing attributes and set with the new value
267    pub fn set_attributes(
268        &mut self,
269        attributes: impl IntoIterator<Item = Attribute<MSG>>,
270    ) -> Result<(), Error> {
271        if let Some(elm) = self.element_mut() {
272            elm.set_attributes(attributes);
273            Ok(())
274        } else {
275            Err(Error::AttributesNotAllowed)
276        }
277    }
278
279    /// merge to existing attributes if the attribute name already exist
280    pub fn merge_attributes(
281        mut self,
282        attributes: impl IntoIterator<Item = Attribute<MSG>>,
283    ) -> Self {
284        if let Some(elm) = self.element_mut() {
285            elm.merge_attributes(attributes);
286        }
287        self
288    }
289
290    /// return the attribute values of this node which match the attribute name `name`
291    pub fn attribute_value(&self, name: &AttributeName) -> Option<Vec<&AttributeValue<MSG>>> {
292        match self {
293            Self::Element(elm) => elm.attribute_value(name),
294            Self::Leaf(leaf) => leaf.attribute_value(name),
295        }
296    }
297
298    /// get the first value of the attribute which has the name `att_name` of this node
299    pub fn first_value(&self, att_name: &AttributeName) -> Option<&Value> {
300        self.attribute_value(att_name)
301            .and_then(|att_values| att_values.first().and_then(|v| v.get_simple()))
302    }
303
304    /// return the skip diff if this node has one
305    pub fn skip_diff(&self) -> Option<SkipDiff> {
306        match self {
307            Self::Leaf(Leaf::TemplatedView(view)) => Some((view.skip_diff)()),
308            _ => None,
309        }
310    }
311
312    ///
313    pub fn unwrap_template(self) -> Node<MSG> {
314        match self {
315            Self::Leaf(Leaf::TemplatedView(view)) => *view.view,
316            _ => self,
317        }
318    }
319
320    ///
321    pub fn unwrap_template_ref(&self) -> &Node<MSG> {
322        match self {
323            Self::Leaf(Leaf::TemplatedView(view)) => &view.view,
324            _ => self,
325        }
326    }
327    /// returns true if this node is a templated view
328    pub fn is_template(&self) -> bool {
329        matches!(self, Self::Leaf(Leaf::TemplatedView(_)))
330    }
331}
332
333/// create a virtual node with tag, attrs and children
334/// # Example
335/// ```rust
336/// use sauron::{Node,vdom::element,attr};
337///
338/// let div:Node<()> = element(
339///          "div",
340///          vec![attr("class", "container")],
341///          vec![],
342///      );
343/// ```
344#[inline]
345pub fn element<MSG>(
346    tag: Tag,
347    attrs: impl IntoIterator<Item = Attribute<MSG>>,
348    children: impl IntoIterator<Item = Node<MSG>>,
349) -> Node<MSG> {
350    element_ns(None, tag, attrs, children, false)
351}
352
353/// create a virtual node with namespace, tag, attrs and children
354/// # Example
355/// ```rust
356/// use sauron::{Node, vdom::element_ns,attr};
357///
358/// let svg: Node<()> = element_ns(
359///         Some("http://www.w3.org/2000/svg"),
360///          "svg",
361///          vec![attr("width","400"), attr("height","400")],
362///          vec![],
363///          false
364///      );
365/// ```
366pub fn element_ns<MSG>(
367    namespace: Option<Namespace>,
368    tag: Tag,
369    attrs: impl IntoIterator<Item = Attribute<MSG>>,
370    children: impl IntoIterator<Item = Node<MSG>>,
371    self_closing: bool,
372) -> Node<MSG> {
373    Node::Element(Element::new(namespace, tag, attrs, children, self_closing))
374}
375
376/// create a leaf node
377pub fn leaf<MSG>(leaf: impl Into<Leaf<MSG>>) -> Node<MSG> {
378    Node::Leaf(leaf.into())
379}
380
381/// create a node list
382pub fn node_list<MSG>(nodes: impl IntoIterator<Item = Node<MSG>>) -> Node<MSG> {
383    Node::Leaf(Leaf::NodeList(nodes.into_iter().collect()))
384}
385
386/// create fragment node
387pub fn fragment<MSG>(nodes: impl IntoIterator<Item = Node<MSG>>) -> Node<MSG> {
388    Node::Leaf(Leaf::Fragment(nodes.into_iter().collect()))
389}