1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use super::{At, AtValue};
use indexmap::IndexMap;
use std::fmt;
#[derive(Clone, Debug, PartialEq)]
pub struct Attrs {
pub vals: IndexMap<At, AtValue>,
}
impl fmt::Display for Attrs {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let string = self
.vals
.iter()
.filter_map(|(k, v)| match v {
AtValue::Ignored => None,
AtValue::None => Some(k.to_string()),
AtValue::Some(value) => Some(format!("{}=\"{}\"", k.as_str(), value)),
})
.collect::<Vec<_>>()
.join(" ");
write!(f, "{}", string)
}
}
impl Attrs {
pub const fn new(vals: IndexMap<At, AtValue>) -> Self {
Self { vals }
}
pub fn empty() -> Self {
Self {
vals: IndexMap::new(),
}
}
pub fn from_id(name: impl Into<AtValue>) -> Self {
let mut result = Self::empty();
result.add(At::Id, name.into());
result
}
pub fn add(&mut self, key: At, val: impl Into<AtValue>) {
self.vals.insert(key, val.into());
}
pub fn add_multiple(&mut self, key: At, items: &[&str]) {
self.add(
key,
items
.iter()
.filter_map(|item| {
if item.is_empty() {
None
} else {
#[allow(clippy::useless_asref)]
Some(item.as_ref())
}
})
.collect::<Vec<&str>>()
.join(" "),
);
}
pub fn merge(&mut self, other: Self) {
for (other_key, other_value) in other.vals {
match self.vals.get_mut(&other_key) {
Some(original_value) => {
Self::merge_attribute_values(&other_key, original_value, other_value);
}
None => {
self.vals.insert(other_key, other_value);
}
}
}
}
fn merge_attribute_values(
key: &At,
mut original_value: &mut AtValue,
mut other_value: AtValue,
) {
match (key, &mut original_value, &mut other_value) {
(At::Class, AtValue::Some(original), AtValue::Some(other)) => {
if !original.is_empty() {
original.push(' ');
}
original.push_str(other);
}
(..) => *original_value = other_value,
}
}
}