1use super::*;
2
3#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
11#[allow(missing_docs)]
12pub struct TagAttribute<'s> {
13 pub key: &'s str,
14 pub value: &'s str,
15}
16
17#[derive(Debug, Clone, Default)]
24pub struct TagAttributeIterator<'s> {
25 attrs: &'s str,
26}
27impl<'s> TagAttributeIterator<'s> {
28 #[inline]
30 #[must_use]
31 pub fn new(attrs: &'s str) -> Self {
32 Self { attrs: attrs.trim() }
33 }
34
35 #[inline]
46 #[must_use]
47 pub fn find_by_key(&self, key: &str) -> Option<&'s str> {
48 self.clone().find(|ta| ta.key == key).map(|ta| ta.value)
49 }
50}
51impl<'s> Iterator for TagAttributeIterator<'s> {
52 type Item = TagAttribute<'s>;
53
54 #[inline]
55 #[must_use]
56 fn next(&mut self) -> Option<Self::Item> {
57 debug_assert_eq!(self.attrs, self.attrs.trim());
58 if self.attrs.is_empty() {
59 return None;
60 }
61 #[allow(clippy::never_loop)]
62 'clear_and_return_none: loop {
63 let (key, rest) = match break_on_first_char(self.attrs, '=') {
65 Some((key, rest)) => (key, rest),
66 None => break 'clear_and_return_none,
67 };
68 self.attrs = rest;
69 let quote_marker = match self.attrs.chars().next() {
71 Some(q) if q == '\'' || q == '\"' => {
72 self.attrs = &self.attrs[1..];
73 q
74 }
75 _ => break 'clear_and_return_none,
76 };
77 let (value, rest) = match break_on_first_char(self.attrs, quote_marker) {
79 Some((key, rest)) => (key, rest),
80 None => break 'clear_and_return_none,
81 };
82 self.attrs = rest.trim_start();
83 return Some(TagAttribute { key, value });
84 }
85 self.attrs = "";
86 None
87 }
88}
89impl<'s> core::iter::FusedIterator for TagAttributeIterator<'s> {}