mt_dom/
node.rs

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