1use std::fmt;
2use std::slice::Iter;
3
4use crate::{
5 Document, Name, NameData,
6 nodes::{Node, NodeId},
7};
8
9impl<'doc, 'input> Node<'doc, 'input> {
10 pub fn has_attributes(self) -> bool {
11 self.element_data()
12 .is_some_and(|element| element.attributes_len != 0)
13 }
14
15 pub fn attributes(self) -> Attributes<'doc, 'input> {
16 let data = self
17 .element_data()
18 .map(|element| {
19 let start = element.attributes_start as usize;
20 let end = start + element.attributes_len as usize;
21
22 &self.doc.attributes[start..end]
23 })
24 .unwrap_or_default();
25
26 Attributes {
27 data: data.iter(),
28 doc: self.doc,
29 }
30 }
31
32 pub fn attribute<N>(self, name: N) -> Option<&'doc str>
40 where
41 Name<'doc, 'input>: PartialEq<N>,
42 {
43 self.attributes()
44 .find(|attribute| attribute.name() == name)
45 .map(|attribute| attribute.value())
46 }
47}
48
49#[derive(Clone, Copy)]
50pub struct Attribute<'doc, 'input> {
51 data: &'doc AttributeData<'input>,
52 doc: &'doc Document<'input>,
53}
54
55impl<'doc, 'input> Attribute<'doc, 'input> {
56 pub fn document(self) -> &'doc Document<'input> {
57 self.doc
58 }
59
60 pub fn name(self) -> Name<'doc, 'input> {
61 self.data.name.get(self.doc)
62 }
63
64 pub fn value(self) -> &'doc str {
65 self.doc.strings.get(self.data.value)
66 }
67}
68
69#[repr(Rust, packed)]
70pub(crate) struct AttributeData<'input> {
71 pub(crate) name: NameData<'input>,
72 pub(crate) value: NodeId,
73}
74
75const _SIZE_OF_ATTRIBUTE_DATA: () = assert!(
76 size_of::<AttributeData<'static>>()
77 == size_of::<u16>() + 2 * size_of::<usize>() + size_of::<u32>()
78);
79
80#[derive(Clone)]
81pub struct Attributes<'doc, 'input> {
82 data: Iter<'doc, AttributeData<'input>>,
83 doc: &'doc Document<'input>,
84}
85
86impl<'doc, 'input> Attributes<'doc, 'input> {
87 fn get(&self, data: &'doc AttributeData<'input>) -> Attribute<'doc, 'input> {
88 Attribute {
89 data,
90 doc: self.doc,
91 }
92 }
93}
94
95impl<'doc, 'input> Iterator for Attributes<'doc, 'input> {
96 type Item = Attribute<'doc, 'input>;
97
98 fn next(&mut self) -> Option<Self::Item> {
99 self.data.next().map(|data| self.get(data))
100 }
101
102 fn nth(&mut self, n: usize) -> Option<Self::Item> {
103 self.data.nth(n).map(|data| self.get(data))
104 }
105
106 fn size_hint(&self) -> (usize, Option<usize>) {
107 self.data.size_hint()
108 }
109}
110
111impl ExactSizeIterator for Attributes<'_, '_> {}
112
113impl DoubleEndedIterator for Attributes<'_, '_> {
114 fn next_back(&mut self) -> Option<Self::Item> {
115 self.data.next_back().map(|data| self.get(data))
116 }
117}
118
119impl fmt::Debug for Attribute<'_, '_> {
120 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
121 fmt.debug_struct("Attribute")
122 .field("name", &self.name())
123 .field("value", &self.value())
124 .finish()
125 }
126}
127
128impl fmt::Debug for Attributes<'_, '_> {
129 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
130 let mut fmt = fmt.debug_map();
131
132 for attribute in self.clone() {
133 fmt.entry(&attribute.name(), &attribute.value());
134 }
135
136 fmt.finish()
137 }
138}