1use pochoir_common::Spanned;
8use pochoir_template_engine::TemplateBlock;
9use std::{borrow::Cow, slice};
10
11pub type AttrKey<'a> = Cow<'a, str>;
12pub type AttrVal<'a> = Vec<Spanned<TemplateBlock<'a>>>;
13pub type Attr<'a> = (Spanned<AttrKey<'a>>, Spanned<AttrVal<'a>>);
14
15#[derive(Debug, Default, Clone, PartialEq)]
17pub struct Attrs<'a>(Vec<Attr<'a>>);
18
19impl<'a> Attrs<'a> {
20 pub fn new() -> Self {
21 Self(vec![])
22 }
23
24 pub fn contains_key<'b, K: Into<AttrKey<'b>>>(&self, key: K) -> bool {
25 let key = key.into();
26 self.0.iter().any(|a| *a.0 == key)
27 }
28
29 pub fn get<'b, K: Into<AttrKey<'b>>>(&self, key: K) -> Option<&AttrVal<'a>> {
30 let key = key.into();
31 self.0.iter().find(|a| *a.0 == key).map(|a| &*a.1)
32 }
33
34 pub fn get_key_value<'b, K: Into<AttrKey<'b>>>(&self, key: K) -> Option<&Attr<'a>> {
35 let key = key.into();
36 self.0.iter().find(|a| *a.0 == key)
37 }
38
39 pub fn get_mut<'b, K: Into<AttrKey<'b>>>(&mut self, key: K) -> Option<&mut AttrVal<'a>> {
40 let key = key.into();
41 self.0.iter_mut().find(|a| *a.0 == key).map(|a| &mut *a.1)
42 }
43
44 pub fn insert<K: Into<AttrKey<'a>>, V: Into<AttrVal<'a>>>(&mut self, key: K, val: V) {
45 let key = key.into();
46 let val = val.into();
47
48 if let Some(attribute) = self.0.iter_mut().find(|a| *a.0 == key) {
49 attribute.0 = Spanned::new(key);
50 attribute.1 = Spanned::new(val);
51 } else {
52 self.0.push((Spanned::new(key), Spanned::new(val)));
53 }
54 }
55
56 pub fn insert_spanned<K: Into<AttrKey<'a>>, V: Into<AttrVal<'a>>>(
57 &mut self,
58 key: Spanned<K>,
59 val: Spanned<V>,
60 ) {
61 let key = key.map_spanned(Into::into);
62 let val = val.map_spanned(Into::into);
63
64 if let Some(attribute) = self.0.iter_mut().find(|a| a.0 == key) {
65 attribute.0 = key;
66 attribute.1 = val;
67 } else {
68 self.0.push((key, val));
69 }
70 }
71
72 pub fn remove<'b, K: Into<AttrKey<'b>>>(&mut self, key: K) -> Option<Attr<'a>> {
73 let key = key.into();
74
75 if let Some(index) = self.0.iter().enumerate().find(|(_, a)| *a.0 == key) {
76 Some(self.0.remove(index.0))
77 } else {
78 None
79 }
80 }
81
82 #[inline]
83 pub fn iter(&self) -> slice::Iter<'_, Attr<'a>> {
84 self.0.iter()
85 }
86
87 #[inline]
88 pub fn iter_mut(&'a mut self) -> slice::IterMut<'a, Attr<'a>> {
89 self.0.iter_mut()
90 }
91
92 pub fn deep_clone<'b>(self) -> Attrs<'b> {
93 self.0
94 .into_iter()
95 .map(|a| {
96 (
97 a.0.map_spanned(|k| Cow::Owned(k.into_owned())),
98 a.1.map_spanned(|v| {
99 v.into_iter()
100 .map(|v| v.map_spanned(TemplateBlock::deep_clone))
101 .collect()
102 }),
103 )
104 })
105 .collect()
106 }
107}
108
109impl<'a> FromIterator<Attr<'a>> for Attrs<'a> {
110 fn from_iter<T: IntoIterator<Item = Attr<'a>>>(iter: T) -> Self {
111 Self(iter.into_iter().collect())
112 }
113}
114impl<'a> FromIterator<(AttrKey<'a>, AttrVal<'a>)> for Attrs<'a> {
115 fn from_iter<T: IntoIterator<Item = (AttrKey<'a>, AttrVal<'a>)>>(iter: T) -> Self {
116 Self(
117 iter.into_iter()
118 .map(|(k, v)| (Spanned::new(k), Spanned::new(v)))
119 .collect(),
120 )
121 }
122}
123
124impl<'a, 'b> IntoIterator for &'a Attrs<'b> {
125 type Item = &'a Attr<'b>;
126 type IntoIter = slice::Iter<'a, Attr<'b>>;
127
128 fn into_iter(self) -> Self::IntoIter {
129 self.0.iter()
130 }
131}
132
133impl<'a, 'b> IntoIterator for &'a mut Attrs<'b> {
134 type Item = &'a mut Attr<'b>;
135 type IntoIter = slice::IterMut<'a, Attr<'b>>;
136
137 fn into_iter(self) -> Self::IntoIter {
138 self.0.iter_mut()
139 }
140}
141
142impl<'a> From<Vec<Attr<'a>>> for Attrs<'a> {
143 fn from(v: Vec<Attr<'a>>) -> Self {
144 Self(v)
145 }
146}
147
148impl<'a> From<&[Attr<'a>]> for Attrs<'a> {
149 fn from(v: &[Attr<'a>]) -> Self {
150 Self(v.to_vec())
151 }
152}
153
154impl<'a, const N: usize> From<[Attr<'a>; N]> for Attrs<'a> {
155 fn from(v: [Attr<'a>; N]) -> Self {
156 Self(v.to_vec())
157 }
158}
159
160#[derive(Debug, Clone, PartialEq)]
162pub enum Node<'a> {
163 Element(Cow<'a, str>, Attrs<'a>),
164 Comment(Cow<'a, str>),
165 Doctype(Cow<'a, str>),
166 TemplateBlock(TemplateBlock<'a>),
167 Root,
168}
169
170impl<'a> Node<'a> {
171 pub(crate) fn node_type(&self) -> &'static str {
172 match self {
173 Node::Element(_, _) => "Element",
174 Node::Comment(_) => "Comment",
175 Node::Doctype(_) => "Doctype",
176 Node::TemplateBlock(_) => "TemplateBlock",
177 Node::Root => "Root",
178 }
179 }
180
181 pub fn new_simple_element<
185 S1: Into<Cow<'a, str>>,
186 S2: Into<Cow<'a, str>>,
187 S3: Into<Cow<'a, str>>,
188 I: IntoIterator<Item = (S2, S3)>,
189 >(
190 element_name: S1,
191 attrs: I,
192 ) -> Self {
193 Self::Element(
194 element_name.into(),
195 attrs
196 .into_iter()
197 .map(|(k, v)| {
198 (
199 k.into(),
200 vec![Spanned::new(TemplateBlock::RawText(v.into()))],
201 )
202 })
203 .collect::<Attrs>(),
204 )
205 }
206
207 pub fn new_element_without_attrs<S: Into<Cow<'a, str>>>(element_name: S) -> Self {
209 Self::Element(element_name.into(), Attrs::new())
210 }
211
212 pub fn new_comment<S: Into<Cow<'a, str>>>(comment_value: S) -> Self {
213 Self::Comment(comment_value.into())
214 }
215
216 pub fn new_doctype<S: Into<Cow<'a, str>>>(doctype_value: S) -> Self {
217 Self::Doctype(doctype_value.into())
218 }
219}
220
221impl Node<'_> {
222 pub fn deep_clone<'b>(self) -> Node<'b> {
223 match self {
224 Node::Element(a, b) => Node::Element(Cow::Owned(a.into_owned()), b.deep_clone()),
225 Node::Comment(a) => Node::Comment(Cow::Owned(a.into_owned())),
226 Node::Doctype(a) => Node::Doctype(Cow::Owned(a.into_owned())),
227 Node::TemplateBlock(a) => Node::TemplateBlock(a.deep_clone()),
228 Node::Root => Node::Root,
229 }
230 }
231}
232
233pub type ParsedNode<'a> = Spanned<Node<'a>>;