rama_http/protocols/html/tokenizer/
token.rs1use std::borrow::Cow;
10
11use super::super::decode_entities;
12use super::name::LocalNameHash;
13use super::tag::HtmlTag;
14
15fn decode_lossy(bytes: &[u8]) -> Cow<'_, str> {
18 match String::from_utf8_lossy(bytes) {
19 Cow::Borrowed(s) => decode_entities(s),
20 Cow::Owned(s) => Cow::Owned(decode_entities(&s).into_owned()),
21 }
22}
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub(crate) struct Span {
27 pub(crate) start: usize,
28 pub(crate) end: usize,
29}
30
31impl Span {
32 pub(crate) const fn new(start: usize, end: usize) -> Self {
33 Self { start, end }
34 }
35
36 pub(crate) const fn empty(at: usize) -> Self {
37 Self { start: at, end: at }
38 }
39
40 fn slice(self, input: &[u8]) -> &[u8] {
41 input.get(self.start..self.end).unwrap_or(&[])
42 }
43}
44
45#[derive(Debug, Clone, Copy)]
47pub(crate) struct AttrRange {
48 pub(crate) name: Span,
49 pub(crate) value: Span,
50 pub(crate) has_value: bool,
51}
52
53#[derive(Debug)]
55pub struct StartTag<'i> {
56 pub(crate) input: &'i [u8],
57 pub(crate) raw: Span,
58 pub(crate) name: Span,
59 pub(crate) name_hash: LocalNameHash,
60 pub(crate) attributes: &'i [AttrRange],
61 pub(crate) self_closing: bool,
62}
63
64impl<'i> StartTag<'i> {
65 #[must_use]
68 pub fn tag(&self) -> HtmlTag<'i> {
69 HtmlTag::classify(self.name_hash, self.name())
70 }
71
72 pub(crate) fn name(&self) -> &'i [u8] {
74 self.name.slice(self.input)
75 }
76
77 #[must_use]
79 pub fn name_hash(&self) -> LocalNameHash {
80 self.name_hash
81 }
82
83 #[must_use]
85 pub fn is_self_closing(&self) -> bool {
86 self.self_closing
87 }
88
89 #[must_use]
91 pub fn attributes(&self) -> Attributes<'i> {
92 Attributes {
93 input: self.input,
94 ranges: self.attributes.iter(),
95 }
96 }
97
98 #[must_use]
100 pub fn raw(&self) -> &'i [u8] {
101 self.raw.slice(self.input)
102 }
103}
104
105#[derive(Debug, Clone)]
107pub struct Attributes<'i> {
108 input: &'i [u8],
109 ranges: std::slice::Iter<'i, AttrRange>,
110}
111
112impl<'i> Iterator for Attributes<'i> {
113 type Item = Attribute<'i>;
114
115 fn next(&mut self) -> Option<Self::Item> {
116 let range = self.ranges.next()?;
117 Some(Attribute {
118 name: range.name.slice(self.input),
119 value: range.value.slice(self.input),
120 has_value: range.has_value,
121 })
122 }
123
124 fn size_hint(&self) -> (usize, Option<usize>) {
125 self.ranges.size_hint()
126 }
127}
128
129impl ExactSizeIterator for Attributes<'_> {}
130
131#[derive(Debug, Clone, Copy)]
133pub struct Attribute<'i> {
134 name: &'i [u8],
135 value: &'i [u8],
136 has_value: bool,
137}
138
139impl<'i> Attribute<'i> {
140 #[must_use]
142 pub fn name(&self) -> &'i [u8] {
143 self.name
144 }
145
146 #[must_use]
150 pub fn value(&self) -> &'i [u8] {
151 self.value
152 }
153
154 #[must_use]
158 pub fn value_decoded(&self) -> Cow<'i, str> {
159 decode_lossy(self.value)
160 }
161
162 #[must_use]
164 pub fn has_value(&self) -> bool {
165 self.has_value
166 }
167}
168
169#[derive(Debug)]
171pub struct EndTag<'i> {
172 pub(crate) input: &'i [u8],
173 pub(crate) raw: Span,
174 pub(crate) name: Span,
175 pub(crate) name_hash: LocalNameHash,
176}
177
178impl<'i> EndTag<'i> {
179 #[must_use]
182 pub fn tag(&self) -> HtmlTag<'i> {
183 HtmlTag::classify(self.name_hash, self.name())
184 }
185
186 pub(crate) fn name(&self) -> &'i [u8] {
188 self.name.slice(self.input)
189 }
190
191 #[must_use]
193 pub fn name_hash(&self) -> LocalNameHash {
194 self.name_hash
195 }
196
197 #[must_use]
199 pub fn raw(&self) -> &'i [u8] {
200 self.raw.slice(self.input)
201 }
202}
203
204#[derive(Debug)]
206pub struct Text<'i> {
207 pub(crate) input: &'i [u8],
208 pub(crate) raw: Span,
209}
210
211impl<'i> Text<'i> {
212 #[must_use]
214 pub fn as_bytes(&self) -> &'i [u8] {
215 self.raw.slice(self.input)
216 }
217
218 #[must_use]
222 pub fn decoded(&self) -> Cow<'i, str> {
223 decode_lossy(self.raw.slice(self.input))
224 }
225
226 #[must_use]
228 pub fn raw(&self) -> &'i [u8] {
229 self.raw.slice(self.input)
230 }
231}
232
233#[derive(Debug)]
235pub struct Comment<'i> {
236 pub(crate) input: &'i [u8],
237 pub(crate) raw: Span,
238 pub(crate) data: Span,
239}
240
241impl<'i> Comment<'i> {
242 #[must_use]
244 pub fn data(&self) -> &'i [u8] {
245 self.data.slice(self.input)
246 }
247
248 #[must_use]
250 pub fn raw(&self) -> &'i [u8] {
251 self.raw.slice(self.input)
252 }
253}
254
255#[derive(Debug)]
258pub struct Cdata<'i> {
259 pub(crate) input: &'i [u8],
260 pub(crate) raw: Span,
261 pub(crate) data: Span,
262}
263
264impl<'i> Cdata<'i> {
265 #[must_use]
267 pub fn data(&self) -> &'i [u8] {
268 self.data.slice(self.input)
269 }
270
271 #[must_use]
273 pub fn raw(&self) -> &'i [u8] {
274 self.raw.slice(self.input)
275 }
276}
277
278#[derive(Debug)]
280pub struct Doctype<'i> {
281 pub(crate) input: &'i [u8],
282 pub(crate) raw: Span,
283 pub(crate) name: Option<Span>,
284}
285
286impl<'i> Doctype<'i> {
287 #[must_use]
289 pub fn name(&self) -> Option<&'i [u8]> {
290 self.name.map(|span| span.slice(self.input))
291 }
292
293 #[must_use]
295 pub fn raw(&self) -> &'i [u8] {
296 self.raw.slice(self.input)
297 }
298}