rama_http/protocols/html/selector/
dom.rs1use super::matcher::SelectorSubject;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub struct NodeId(usize);
16
17#[derive(Debug)]
18struct Attribute {
19 name: String,
20 value: String,
21}
22
23#[derive(Debug)]
24struct NodeData {
25 name: String,
26 attributes: Vec<Attribute>,
27 parent: Option<usize>,
28 children: Vec<usize>,
29}
30
31#[derive(Debug, Default)]
33pub struct Dom {
34 nodes: Vec<NodeData>,
35}
36
37impl Dom {
38 #[must_use]
40 pub fn new() -> Self {
41 Self::default()
42 }
43
44 pub fn create(&mut self, name: &str) -> NodeId {
46 self.push(name, None)
47 }
48
49 pub fn append(&mut self, parent: NodeId, name: &str) -> NodeId {
51 let id = self.push(name, Some(parent.0));
52 if let Some(node) = self.nodes.get_mut(parent.0) {
53 node.children.push(id.0);
54 }
55 id
56 }
57
58 pub fn set_attr(&mut self, node: NodeId, name: &str, value: &str) {
60 let Some(data) = self.nodes.get_mut(node.0) else {
61 return;
62 };
63 if let Some(existing) = data
64 .attributes
65 .iter_mut()
66 .find(|attr| attr.name.eq_ignore_ascii_case(name))
67 {
68 existing.value = value.to_owned();
69 } else {
70 data.attributes.push(Attribute {
71 name: name.to_owned(),
72 value: value.to_owned(),
73 });
74 }
75 }
76
77 #[must_use]
79 pub fn element(&self, node: NodeId) -> Element<'_> {
80 Element {
81 dom: self,
82 id: node.0,
83 }
84 }
85
86 fn push(&mut self, name: &str, parent: Option<usize>) -> NodeId {
87 let id = self.nodes.len();
88 self.nodes.push(NodeData {
89 name: name.to_owned(),
90 attributes: Vec::new(),
91 parent,
92 children: Vec::new(),
93 });
94 NodeId(id)
95 }
96}
97
98#[derive(Debug, Clone, Copy)]
100pub struct Element<'a> {
101 dom: &'a Dom,
102 id: usize,
103}
104
105impl Element<'_> {
106 fn data(&self) -> Option<&NodeData> {
107 self.dom.nodes.get(self.id)
108 }
109}
110
111impl SelectorSubject for Element<'_> {
112 fn local_name(&self) -> &str {
113 self.data().map_or("", |d| d.name.as_str())
114 }
115
116 fn attribute(&self, name: &str) -> Option<&str> {
117 self.data()?
118 .attributes
119 .iter()
120 .find(|attr| attr.name.eq_ignore_ascii_case(name))
121 .map(|attr| attr.value.as_str())
122 }
123
124 fn parent(&self) -> Option<Self> {
125 let parent = self.data()?.parent?;
126 Some(Self {
127 dom: self.dom,
128 id: parent,
129 })
130 }
131
132 fn nth_child_index(&self) -> usize {
133 let Some(data) = self.data() else {
134 return 1;
135 };
136 let Some(parent) = data.parent.and_then(|p| self.dom.nodes.get(p)) else {
137 return 1;
138 };
139 parent
140 .children
141 .iter()
142 .position(|&c| c == self.id)
143 .map_or(1, |i| i + 1)
144 }
145
146 fn nth_of_type_index(&self) -> usize {
147 let Some(data) = self.data() else {
148 return 1;
149 };
150 let Some(parent) = data.parent.and_then(|p| self.dom.nodes.get(p)) else {
151 return 1;
152 };
153 let mut index = 0;
154 for &child in &parent.children {
155 if let Some(sibling) = self.dom.nodes.get(child)
156 && sibling.name.eq_ignore_ascii_case(&data.name)
157 {
158 index += 1;
159 }
160 if child == self.id {
161 return index.max(1);
162 }
163 }
164 index.max(1)
165 }
166}