sauron_core/vdom/
leaf.rs

1//! Leaf node for html dom tree
2use crate::dom::StatefulModel;
3use crate::dom::StatelessModel;
4use crate::vdom::Attribute;
5use crate::vdom::AttributeName;
6use crate::vdom::AttributeValue;
7use crate::vdom::Node;
8use crate::vdom::TemplatedView;
9use derive_where::derive_where;
10use std::borrow::Cow;
11
12/// A leaf node value of html dom tree
13#[derive_where(Clone, Debug)]
14pub enum Leaf<MSG> {
15    /// Text variant of a virtual node
16    Text(Cow<'static, str>),
17    /// Html entities such as &nbsp; &gt;
18    Symbol(Cow<'static, str>),
19    /// A comment node
20    Comment(Cow<'static, str>),
21    /// doctype: html, math, svg
22    /// <https://www.w3.org/QA/2002/04/valid-dtd-list.html>
23    DocType(Cow<'static, str>),
24    /// A node containing nodes, this will be unrolled together with the rest of the children of
25    /// the node
26    NodeList(Vec<Node<MSG>>),
27    /// A document fragment node, will be created using fragment node and attached to the dom
28    Fragment(Vec<Node<MSG>>),
29    /// Stateful Component leaf
30    #[cfg(feature = "with-dom")]
31    StatefulComponent(StatefulModel<MSG>),
32    /// Stateless Component leaf
33    StatelessComponent(StatelessModel<MSG>),
34    /// a view where a template and skip diff is provided
35    TemplatedView(TemplatedView<MSG>),
36}
37
38impl<MSG> PartialEq for Leaf<MSG> {
39    fn eq(&self, other: &Self) -> bool {
40        match (self, other) {
41            (Self::Text(v), Self::Text(o)) => v == o,
42            (Self::Symbol(v), Self::Symbol(o)) => v == o,
43            (Self::Comment(v), Self::Comment(o)) => v == o,
44            (Self::DocType(v), Self::DocType(o)) => v == o,
45            (Self::NodeList(v), Self::NodeList(o)) => v == o,
46            (Self::Fragment(v), Self::Fragment(o)) => v == o,
47            #[cfg(feature = "with-dom")]
48            (Self::StatefulComponent(v), Self::StatefulComponent(o)) => v == o,
49            (Self::StatelessComponent(v), Self::StatelessComponent(o)) => v == o,
50            _ => false,
51        }
52    }
53}
54
55impl<MSG> Eq for Leaf<MSG> {}
56
57impl<MSG> Leaf<MSG> {
58    /// returns true if this a text node
59    pub fn is_text(&self) -> bool {
60        matches!(self, Self::Text(_))
61    }
62
63    /// return the text content if it is a text node
64    pub fn as_text(&self) -> Option<&str> {
65        match self {
66            Self::Text(ref text) => Some(text),
67            _ => None,
68        }
69    }
70
71    /// return the attribute value of this leaf
72    pub fn attribute_value(&self, name: &AttributeName) -> Option<Vec<&AttributeValue<MSG>>> {
73        match self {
74            Self::StatelessComponent(comp) => comp.attribute_value(name),
75            Self::TemplatedView(templated_view) => templated_view.view.attribute_value(name),
76            _ => None,
77        }
78    }
79
80    /// attributes, we are returning the attributes of the top level node of this stateless mode
81    /// view
82    pub fn attributes(&self) -> Option<&[Attribute<MSG>]> {
83        match self {
84            Self::StatelessComponent(comp) => comp.attributes(),
85            Self::TemplatedView(templated_view) => templated_view.view.attributes(),
86            _ => None,
87        }
88    }
89}
90
91impl<MSG> From<&'static str> for Leaf<MSG> {
92    fn from(s: &'static str) -> Self {
93        Self::Text(Cow::from(s))
94    }
95}
96
97impl<MSG> From<String> for Leaf<MSG> {
98    fn from(s: String) -> Self {
99        Self::Text(Cow::from(s))
100    }
101}