simple_rsx/
lib.rs

1use indexmap::IndexMap;
2pub use simple_rsx_macros::rsx;
3use std::fmt::Display;
4
5/// A trait for attributes
6pub trait Attribute {
7    fn value(&self) -> String;
8}
9
10impl<T: ToString> Attribute for T {
11    fn value(&self) -> String {
12        self.to_string()
13    }
14}
15
16pub struct Element {
17    tag: String,
18    attributes: IndexMap<String, String>,
19    children: Vec<Node>,
20}
21
22impl Element {
23    pub fn new(tag: &str) -> Node {
24        Node::Element(Element {
25            tag: tag.to_string(),
26            attributes: IndexMap::new(),
27            children: Vec::new(),
28        })
29    }
30
31    pub fn set_attribute(&mut self, name: &str, value: impl Attribute) {
32        self.attributes.insert(name.to_string(), value.value());
33    }
34
35    pub fn append_child(&mut self, node: Node) {
36        self.children.push(node);
37    }
38}
39
40impl Node {
41    pub fn as_element_mut(&mut self) -> Option<&mut Element> {
42        match self {
43            Node::Element(el) => Some(el),
44            _ => None,
45        }
46    }
47
48    pub fn append_child(&mut self, node: Node) {
49        if let Node::Element(el) = self {
50            el.children.push(node);
51        }
52    }
53}
54
55pub enum Node {
56    Element(Element),
57    Text(String),
58    Fragment(Vec<Node>),
59}
60
61impl From<String> for Node {
62    fn from(value: String) -> Self {
63        Node::Text(value)
64    }
65}
66
67impl From<&String> for Node {
68    fn from(value: &String) -> Self {
69        Node::Text(value.to_string())
70    }
71}
72
73impl From<&str> for Node {
74    fn from(value: &str) -> Self {
75        Node::Text(value.to_string())
76    }
77}
78
79impl From<&&str> for Node {
80    fn from(value: &&str) -> Self {
81        Node::Text(value.to_string())
82    }
83}
84
85impl<T: ToString> From<Vec<T>> for Node {
86    fn from(value: Vec<T>) -> Self {
87        Node::Fragment(
88            value
89                .into_iter()
90                .map(|t| Node::Text(t.to_string()))
91                .collect(),
92        )
93    }
94}
95
96impl From<i32> for Node {
97    fn from(value: i32) -> Self {
98        Node::Text(value.to_string())
99    }
100}
101
102impl From<u32> for Node {
103    fn from(value: u32) -> Self {
104        Node::Text(value.to_string())
105    }
106}
107
108impl FromIterator<u32> for Node {
109    fn from_iter<T: IntoIterator<Item = u32>>(iter: T) -> Self {
110        let mut result = Vec::new();
111        for i in iter {
112            result.push(Node::Text(i.to_string()));
113        }
114        Node::Fragment(result)
115    }
116}
117
118impl FromIterator<u64> for Node {
119    fn from_iter<T: IntoIterator<Item = u64>>(iter: T) -> Self {
120        let mut result = Vec::new();
121        for i in iter {
122            result.push(Node::Text(i.to_string()));
123        }
124        Node::Fragment(result)
125    }
126}
127
128impl FromIterator<i32> for Node {
129    fn from_iter<T: IntoIterator<Item = i32>>(iter: T) -> Self {
130        let mut result = Vec::new();
131        for i in iter {
132            result.push(Node::Text(i.to_string()));
133        }
134        Node::Fragment(result)
135    }
136}
137
138impl From<f32> for Node {
139    fn from(value: f32) -> Self {
140        Node::Text(value.to_string())
141    }
142}
143
144impl From<bool> for Node {
145    fn from(value: bool) -> Self {
146        Node::Text(value.to_string())
147    }
148}
149
150impl<I, F, R> From<std::iter::Map<I, F>> for Node
151where
152    I: Iterator,
153    F: FnMut(I::Item) -> R,
154    R: Into<Node>,
155    Vec<Node>: FromIterator<R>,
156{
157    fn from(iter: std::iter::Map<I, F>) -> Self {
158        let nodes: Vec<Node> = iter.collect();
159        Node::from(nodes)
160    }
161}
162
163impl Display for Node {
164    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165        match self {
166            Node::Element(el) => {
167                write!(f, "<{}", el.tag)?;
168                for (key, value) in &el.attributes {
169                    write!(f, " {}=\"{}\"", key, value)?;
170                }
171                write!(f, ">")?;
172                for child in &el.children {
173                    write!(f, "{}", child)?;
174                }
175                write!(f, "</{}>", el.tag)?;
176                Ok(())
177            }
178            Node::Text(text) => {
179                write!(f, "{}", text)?;
180                Ok(())
181            }
182            Node::Fragment(nodes) => {
183                for node in nodes {
184                    write!(f, "{}", node)?;
185                }
186                Ok(())
187            }
188        }
189    }
190}