write_html/
attributes.rs

1use std::fmt::Write;
2
3use crate::{TagOpening, Empty, Sum};
4
5
6/// Represents a list of attributes.
7pub trait Attributes {
8    /// Writes the attributes to `w`.
9    ///
10    /// # Arguments
11    /// * `w` - The tag opening to write to.
12    fn write_attributes<'a, 't, W: Write>(self, w: &mut TagOpening<'a, 't, W>) -> std::fmt::Result;
13} // TODO TagOpening into trait and rename to TagOpening struct into something else
14
15impl<A: Attributes, B: Attributes> Attributes for Sum<A, B> {
16    fn write_attributes<'a, 't, W: Write>(self, w: &mut TagOpening<'a, 't, W>) -> std::fmt::Result {
17        self.0.write_attributes(w)?;
18        self.1.write_attributes(w)?;
19        Ok(())
20    }
21}
22
23impl<I: IntoIterator<Item = (Name, Value)>, Name, Value> Attributes for I
24where
25    Name: AttributeName,
26    Value: AttributeValue,
27{
28    fn write_attributes<'a, 't, W: Write>(self, w: &mut TagOpening<'a, 't, W>) -> std::fmt::Result {
29        for (n, v) in self {
30            w.attr(n, v)?;
31        }
32        Ok(())
33    }
34}
35
36impl Attributes for Empty {
37    fn write_attributes<'a, 't, W: Write>(self, _w: &mut TagOpening<'a, 't, W>) -> std::fmt::Result {
38        Ok(())
39    }
40}
41
42
43/// Tells whether the given string is a valid attribute name.
44pub fn is_valid_attribute_name(name: &str) -> bool {
45    if name.is_empty() {
46        return false;
47    }
48
49    if name.trim() != name {
50        return false;
51    }
52
53    let mut chars = name.chars();
54    let first_char = chars.next().unwrap();
55
56    if !first_char.is_ascii_alphabetic() {
57        return false;
58    }
59
60    for c in chars {
61        if !c.is_ascii_alphanumeric() && c != '-' && c != '_' {
62            return false;
63        }
64    }
65
66    true
67}
68
69/// Represents a name of an attribute.
70pub trait AttributeName {
71    /// Tells whether the attribute name is valid.
72    fn is_valid_attribute_name(&self) -> bool;
73    /// Writes the attribute name to `w`.
74    ///
75    /// # Arguments
76    /// * `w` - The writer to write to.
77    fn write_attribute_name(self, w: &mut impl Write) -> std::fmt::Result;
78}
79
80impl AttributeName for &str {
81    fn is_valid_attribute_name(&self) -> bool {
82        is_valid_attribute_name(self)
83    }
84    fn write_attribute_name(self, w: &mut impl Write) -> std::fmt::Result {
85        w.write_str(self)
86    }
87}
88
89impl AttributeName for &&str {
90    fn is_valid_attribute_name(&self) -> bool {
91        is_valid_attribute_name(self)
92    }
93    fn write_attribute_name(self, w: &mut impl Write) -> std::fmt::Result {
94        w.write_str(*self)
95    }
96}
97
98impl AttributeName for String {
99    fn is_valid_attribute_name(&self) -> bool {
100        is_valid_attribute_name(&self)
101    }
102    fn write_attribute_name(self, w: &mut impl Write) -> std::fmt::Result {
103        w.write_str(&self)
104    }
105}
106
107impl AttributeName for &String {
108    fn is_valid_attribute_name(&self) -> bool {
109        is_valid_attribute_name(self)
110    }
111    fn write_attribute_name(self, w: &mut impl Write) -> std::fmt::Result {
112        w.write_str(self)
113    }
114}
115
116/// Represents a value of an attribute.
117pub trait AttributeValue {
118    /// Tells whether the attribute value is a unit value, meaning that it is not written.
119    fn is_unit(&self) -> bool {
120        false
121    }
122    /// Writes the attribute value to `w`.
123    ///
124    /// # Arguments
125    /// * `w` - The writer to write to.
126    fn write_attribute_value(self, w: &mut impl Write) -> std::fmt::Result;
127}
128
129impl AttributeValue for &str {
130    fn is_unit(&self) -> bool {
131        false
132    }
133    fn write_attribute_value(self, w: &mut impl Write) -> std::fmt::Result {
134        w.write_str(self)
135    }
136}
137
138impl AttributeValue for &&str {
139    fn is_unit(&self) -> bool {
140        false
141    }
142    fn write_attribute_value(self, w: &mut impl Write) -> std::fmt::Result {
143        w.write_str(*self)
144    }
145}
146
147impl AttributeValue for String {
148    fn is_unit(&self) -> bool {
149        false
150    }
151    fn write_attribute_value(self, w: &mut impl Write) -> std::fmt::Result {
152        w.write_str(&self)
153    }
154}
155
156impl AttributeValue for &String {
157    fn is_unit(&self) -> bool {
158        false
159    }
160    fn write_attribute_value(self, w: &mut impl Write) -> std::fmt::Result {
161        w.write_str(self)
162    }
163}
164
165impl AttributeValue for () {
166    fn is_unit(&self) -> bool {
167        true
168    }
169    fn write_attribute_value(self, _w: &mut impl Write) -> std::fmt::Result {
170        Ok(())
171    }
172}
173
174/*impl<F: FnOnce(&mut dyn Write) -> std::fmt::Result> AttributeValue for F {
175    fn is_unit(&self) -> bool {
176        false
177    }
178    fn write_attribute_value(self, w: &mut impl Write) -> std::fmt::Result {
179        self(w)
180    }
181}*/