1use rustc_hash::FxHashMap;
2use serde::{
3 Deserialize, Serialize,
4 de::Deserializer,
5 ser::{SerializeMap, Serializer},
6};
7
8#[derive(Debug, PartialEq, Clone)]
13struct AttributeMap {
14 all: FxHashMap<AttributeName, AttributeValue>,
16 explicit: FxHashMap<AttributeName, AttributeValue>,
18}
19
20impl Default for AttributeMap {
21 fn default() -> Self {
22 AttributeMap {
23 all: crate::constants::default_attributes(),
24 explicit: FxHashMap::default(), }
26 }
27}
28
29impl AttributeMap {
30 fn empty() -> Self {
31 AttributeMap {
32 all: FxHashMap::default(),
33 explicit: FxHashMap::default(),
34 }
35 }
36
37 fn iter(&self) -> impl Iterator<Item = (&AttributeName, &AttributeValue)> {
38 self.all.iter()
39 }
40
41 fn is_empty(&self) -> bool {
42 self.explicit.is_empty()
45 }
46
47 fn insert(&mut self, name: AttributeName, value: AttributeValue) {
48 if !self.contains_key(&name) {
49 self.all.insert(name.clone(), value.clone());
50 self.explicit.insert(name, value); }
52 }
53
54 fn set(&mut self, name: AttributeName, value: AttributeValue) {
55 self.all.insert(name.clone(), value.clone());
56 self.explicit.insert(name, value); }
58
59 fn get(&self, name: &str) -> Option<&AttributeValue> {
60 self.all.get(name)
61 }
62
63 fn contains_key(&self, name: &str) -> bool {
64 self.all.contains_key(name)
65 }
66
67 fn remove(&mut self, name: &str) -> Option<AttributeValue> {
68 self.explicit.remove(name);
69 self.all.remove(name)
70 }
71
72 fn merge(&mut self, other: AttributeMap) {
73 for (key, value) in other.all {
74 self.insert(key, value);
75 }
76 }
77}
78
79impl Serialize for AttributeMap {
80 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
81 where
82 S: Serializer,
83 {
84 let mut sorted_keys: Vec<_> = self.explicit.keys().collect();
86 sorted_keys.sort();
87
88 let mut state = serializer.serialize_map(Some(self.explicit.len()))?;
89 for key in sorted_keys {
90 if let Some(value) = &self.explicit.get(key) {
91 match value {
92 AttributeValue::Bool(true) => {
93 if key == "toc" {
94 state.serialize_entry(key, "")?;
95 } else {
96 state.serialize_entry(key, &true)?;
97 }
98 }
99 value @ (AttributeValue::Bool(false)
100 | AttributeValue::String(_)
101 | AttributeValue::None) => {
102 state.serialize_entry(key, value)?;
103 }
104 }
105 }
106 }
107 state.end()
108 }
109}
110
111impl<'de> Deserialize<'de> for AttributeMap {
112 fn deserialize<D>(deserializer: D) -> Result<AttributeMap, D::Error>
113 where
114 D: Deserializer<'de>,
115 {
116 let explicit = FxHashMap::deserialize(deserializer).unwrap_or_default();
117 Ok(AttributeMap {
120 all: explicit.clone(),
121 explicit,
122 })
123 }
124}
125
126#[derive(Debug, PartialEq, Clone, Default)]
133pub struct DocumentAttributes(AttributeMap);
134
135impl DocumentAttributes {
136 pub fn iter(&self) -> impl Iterator<Item = (&AttributeName, &AttributeValue)> {
138 self.0.iter()
139 }
140
141 #[must_use]
143 pub fn is_empty(&self) -> bool {
144 self.0.is_empty()
145 }
146
147 pub fn insert(&mut self, name: AttributeName, value: AttributeValue) {
151 self.0.insert(name, value);
152 }
153
154 pub fn set(&mut self, name: AttributeName, value: AttributeValue) {
156 self.0.set(name, value);
157 }
158
159 #[must_use]
161 pub fn get(&self, name: &str) -> Option<&AttributeValue> {
162 self.0.get(name)
163 }
164
165 #[must_use]
167 pub fn contains_key(&self, name: &str) -> bool {
168 self.0.contains_key(name)
169 }
170
171 pub fn remove(&mut self, name: &str) -> Option<AttributeValue> {
173 self.0.remove(name)
174 }
175
176 pub fn merge(&mut self, other: Self) {
178 self.0.merge(other.0);
179 }
180
181 #[must_use]
185 pub fn get_string(&self, name: &str) -> Option<String> {
186 self.get(name).and_then(|v| match v {
187 AttributeValue::String(s) => {
188 let trimmed = s.trim_matches('"');
190 Some(trimmed.to_string())
191 }
192 AttributeValue::None | AttributeValue::Bool(_) => None,
193 })
194 }
195}
196
197impl Serialize for DocumentAttributes {
198 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
199 where
200 S: Serializer,
201 {
202 self.0.serialize(serializer)
203 }
204}
205
206impl<'de> Deserialize<'de> for DocumentAttributes {
207 fn deserialize<D>(deserializer: D) -> Result<DocumentAttributes, D::Error>
208 where
209 D: Deserializer<'de>,
210 {
211 let mut map = AttributeMap::deserialize(deserializer)?;
212
213 for (name, value) in crate::constants::default_attributes() {
216 map.all
217 .entry(name)
218 .and_modify(|v| *v = value.clone())
219 .or_insert(value.clone());
220 }
221
222 Ok(DocumentAttributes(map))
223 }
224}
225
226#[derive(Debug, PartialEq, Clone)]
232pub struct ElementAttributes(AttributeMap);
233
234impl Default for ElementAttributes {
235 fn default() -> Self {
236 ElementAttributes(AttributeMap::empty())
237 }
238}
239
240impl ElementAttributes {
241 pub fn iter(&self) -> impl Iterator<Item = (&AttributeName, &AttributeValue)> {
243 self.0.iter()
244 }
245
246 #[must_use]
248 pub fn is_empty(&self) -> bool {
249 self.0.is_empty()
250 }
251
252 pub fn insert(&mut self, name: AttributeName, value: AttributeValue) {
256 self.0.insert(name, value);
257 }
258
259 pub fn set(&mut self, name: AttributeName, value: AttributeValue) {
261 self.0.set(name, value);
262 }
263
264 #[must_use]
266 pub fn get(&self, name: &str) -> Option<&AttributeValue> {
267 self.0.get(name)
268 }
269
270 #[must_use]
272 pub fn contains_key(&self, name: &str) -> bool {
273 self.0.contains_key(name)
274 }
275
276 pub fn remove(&mut self, name: &str) -> Option<AttributeValue> {
278 self.0.remove(name)
279 }
280
281 pub fn merge(&mut self, other: Self) {
283 self.0.merge(other.0);
284 }
285
286 #[must_use]
290 pub fn get_string(&self, name: &str) -> Option<String> {
291 self.get(name).and_then(|v| match v {
292 AttributeValue::String(s) => {
293 let trimmed = s.trim_matches('"');
295 Some(trimmed.to_string())
296 }
297 AttributeValue::None | AttributeValue::Bool(_) => None,
298 })
299 }
300}
301
302impl Serialize for ElementAttributes {
303 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
304 where
305 S: Serializer,
306 {
307 self.0.serialize(serializer)
308 }
309}
310
311impl<'de> Deserialize<'de> for ElementAttributes {
312 fn deserialize<D>(deserializer: D) -> Result<ElementAttributes, D::Error>
313 where
314 D: Deserializer<'de>,
315 {
316 AttributeMap::deserialize(deserializer).map(ElementAttributes)
317 }
318}
319
320pub type AttributeName = String;
322
323#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
327#[serde(untagged)]
328#[non_exhaustive]
329pub enum AttributeValue {
330 String(String),
332 Bool(bool),
334 None,
336}
337
338impl std::fmt::Display for AttributeValue {
339 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
340 match self {
341 AttributeValue::String(value) => write!(f, "{value}"),
342 AttributeValue::Bool(value) => write!(f, "{value}"),
343 AttributeValue::None => write!(f, "null"),
344 }
345 }
346}
347
348impl From<&str> for AttributeValue {
349 fn from(value: &str) -> Self {
350 AttributeValue::String(value.to_string())
351 }
352}
353
354impl From<String> for AttributeValue {
355 fn from(value: String) -> Self {
356 AttributeValue::String(value)
357 }
358}
359
360impl From<bool> for AttributeValue {
361 fn from(value: bool) -> Self {
362 AttributeValue::Bool(value)
363 }
364}
365
366impl From<()> for AttributeValue {
367 fn from((): ()) -> Self {
368 AttributeValue::None
369 }
370}