1use core::marker::PhantomData;
23
24use crate::dom::document_cell::DocumentCell;
25use crate::dom::node::NodeType;
26use crate::id::{INVALID, RawId};
27
28#[derive(Copy, Clone)]
35pub struct Handle {
36 pub(crate) id: RawId,
37 pub(crate) cell: DocumentCell,
38 _no_sync: PhantomData<*const ()>,
41}
42
43unsafe impl Send for Handle {}
46
47impl Handle {
48 #[inline]
49 pub(crate) fn new(id: RawId, cell: DocumentCell) -> Self {
50 Self {
51 id,
52 cell,
53 _no_sync: PhantomData,
54 }
55 }
56
57 #[inline]
59 #[must_use]
60 pub fn raw(&self) -> RawId {
61 self.id
62 }
63
64 #[inline]
66 #[must_use]
67 pub fn is_alive(&self) -> bool {
68 self.cell.read(|doc| doc.is_alive_id(self.id))
69 }
70
71 #[inline]
75 pub fn read_data<D: 'static, R: 'static>(&self, f: impl FnOnce(&D) -> R) -> Option<R> {
76 self.cell.check_alive();
77 self.cell.read(|doc| doc.read_data(self.id, f))
78 }
79
80 #[inline]
82 pub fn write_data<D: 'static, R: 'static>(&self, f: impl FnOnce(&mut D) -> R) -> Option<R> {
83 self.cell.check_alive();
84 self.cell.write(|doc| doc.write_data(self.id, f))
85 }
86
87 pub(crate) fn mark_parent_needs_layout(&self) {
93 let index = self.id.index();
94 self.cell.write(|doc| {
95 let parent_idx = doc
96 .tree
97 .get(index)
98 .map(|td| td.parent)
99 .filter(|&p| p != crate::id::INVALID);
100 if let Some(_parent) = parent_idx {
101 doc.dirty_layout_nodes.push(index);
105 doc.mark_layout_dirty(index);
106 }
107 });
108 }
109
110 #[must_use]
114 pub fn tag_name(&self) -> Option<&'static str> {
115 self.cell
116 .read(|doc| doc.read_element_data(self.id, |ed| ed.tag_name))
117 }
118
119 #[must_use]
121 pub fn id(&self) -> String {
122 self.attribute("id").unwrap_or_default()
123 }
124
125 pub fn set_id(&self, id: impl Into<String>) {
127 self.set_attribute("id", id);
128 }
129
130 #[must_use]
132 pub fn class_name(&self) -> String {
133 self.attribute("class").unwrap_or_default()
134 }
135
136 pub fn set_class_name(&self, class: impl Into<String>) {
138 self.set_attribute("class", class);
139 }
140
141 #[must_use]
143 pub fn attribute(&self, name: &str) -> Option<String> {
144 self.cell
145 .read(|doc| {
146 doc.read_element_data(self.id, |ed| ed.attributes.get(name).map(|v| v.to_string()))
147 })
148 .flatten()
149 }
150
151 pub fn set_attribute(&self, name: &str, value: impl Into<String>) {
153 let value = value.into();
154 let index = self.id.index();
155 self.cell.write(|doc| {
156 let guard = doc.style_engine.shared_lock().clone();
157 doc.write_element_data(self.id, |ed| {
158 ed.on_attribute_set(name, &value, &guard);
159 ed.attributes.set(name, value);
160 });
161 doc.mark_for_restyle(index);
162 });
163 }
164
165 #[must_use]
167 pub fn remove_attribute(&self, name: &str) -> Option<String> {
168 let index = self.id.index();
169 self.cell.write(|doc| {
170 let removed = doc
171 .write_element_data(self.id, |ed| {
172 ed.on_attribute_removed(name);
173 ed.attributes.remove(name)
174 })
175 .flatten();
176 doc.mark_for_restyle(index);
177 removed
178 })
179 }
180
181 pub fn class_add(&self, name: &str) {
186 let index = self.id.index();
187 self.cell.write(|doc| {
188 let changed = doc
189 .write_element_data(self.id, |ed| ed.class_add(name))
190 .unwrap_or(false);
191 if changed {
192 doc.mark_for_restyle(index);
193 }
194 });
195 }
196
197 pub fn class_remove(&self, name: &str) {
200 let index = self.id.index();
201 self.cell.write(|doc| {
202 let changed = doc
203 .write_element_data(self.id, |ed| ed.class_remove(name))
204 .unwrap_or(false);
205 if changed {
206 doc.mark_for_restyle(index);
207 }
208 });
209 }
210
211 #[must_use]
214 pub fn class_toggle(&self, name: &str) -> bool {
215 let index = self.id.index();
216 self.cell.write(|doc| {
217 let present = doc
218 .write_element_data(self.id, |ed| ed.class_toggle(name))
219 .unwrap_or(false);
220 doc.mark_for_restyle(index);
221 present
222 })
223 }
224
225 #[must_use]
228 pub fn class_contains(&self, name: &str) -> bool {
229 self.cell
230 .read(|doc| doc.read_element_data(self.id, |ed| ed.class_contains(name)))
231 .unwrap_or(false)
232 }
233
234 pub fn append(&self, child: impl Into<Handle>) -> &Self {
240 let child = child.into();
241 self.cell.check_alive();
242 self.cell.write(|doc| doc.append_child(self.id, child.id));
243 self
244 }
245
246 pub fn child(self, child: impl Into<Handle>) -> Self {
254 self.append(child);
255 self
256 }
257
258 pub fn add_children<I, C>(self, items: I) -> Self
260 where
261 I: IntoIterator<Item = C>,
262 C: Into<Handle>,
263 {
264 self.cell.check_alive();
265 self.cell.write(|doc| {
266 for child in items {
267 doc.append_child(self.id, child.into().id);
268 }
269 });
270 self
271 }
272
273 pub fn insert_before(&self, child: impl Into<Handle>) {
275 let child = child.into();
276 self.cell.check_alive();
277 self.cell.write(|doc| doc.insert_before(self.id, child.id));
278 }
279
280 pub fn detach(&self) {
282 self.cell.check_alive();
283 self.cell.write(|doc| doc.detach_node(self.id));
284 }
285
286 pub fn destroy(&self) {
288 self.cell.check_alive();
289 self.cell.write(|doc| doc.destroy_node(self.id));
290 }
291
292 #[must_use]
296 pub fn parent(&self) -> Option<Handle> {
297 self.cell
298 .read(|doc| {
299 let tree = doc.tree_data(self.id)?;
300 if tree.parent == INVALID {
301 return None;
302 }
303 let id = doc.raw_id(tree.parent)?;
304 Some(id)
305 })
306 .map(|id| Handle::new(id, self.cell))
307 }
308
309 #[must_use]
311 pub fn first_child(&self) -> Option<Handle> {
312 self.cell
313 .read(|doc| {
314 let tree = doc.tree_data(self.id)?;
315 if tree.first_child == INVALID {
316 return None;
317 }
318 doc.raw_id(tree.first_child)
319 })
320 .map(|id| Handle::new(id, self.cell))
321 }
322
323 #[must_use]
325 pub fn last_child(&self) -> Option<Handle> {
326 self.cell
327 .read(|doc| {
328 let tree = doc.tree_data(self.id)?;
329 if tree.last_child == INVALID {
330 return None;
331 }
332 doc.raw_id(tree.last_child)
333 })
334 .map(|id| Handle::new(id, self.cell))
335 }
336
337 #[must_use]
339 pub fn next_sibling(&self) -> Option<Handle> {
340 self.cell
341 .read(|doc| {
342 let tree = doc.tree_data(self.id)?;
343 if tree.next_sibling == INVALID {
344 return None;
345 }
346 doc.raw_id(tree.next_sibling)
347 })
348 .map(|id| Handle::new(id, self.cell))
349 }
350
351 #[must_use]
353 pub fn prev_sibling(&self) -> Option<Handle> {
354 self.cell
355 .read(|doc| {
356 let tree = doc.tree_data(self.id)?;
357 if tree.prev_sibling == INVALID {
358 return None;
359 }
360 doc.raw_id(tree.prev_sibling)
361 })
362 .map(|id| Handle::new(id, self.cell))
363 }
364
365 #[must_use]
367 pub fn children(&self) -> Vec<Handle> {
368 let ids = self.cell.read(|doc| doc.children_ids(self.id));
369 ids.into_iter()
370 .map(|id| Handle::new(id, self.cell))
371 .collect()
372 }
373
374 #[must_use]
377 pub fn node_kind(&self) -> Option<NodeType> {
378 self.cell.read(|doc| doc.node_kind(self.id))
379 }
380 #[must_use]
381 pub fn is_element(&self) -> bool {
382 self.node_kind() == Some(NodeType::Element)
383 }
384 #[must_use]
385 pub fn is_text(&self) -> bool {
386 self.node_kind() == Some(NodeType::Text)
387 }
388 #[must_use]
389 pub fn is_document(&self) -> bool {
390 self.node_kind() == Some(NodeType::Document)
391 }
392
393 #[must_use]
402 pub fn style(&self) -> crate::styling::builder::StyleAccess {
403 crate::styling::builder::StyleAccess::new(self.cell, self.id)
404 }
405
406 pub fn dispatch_event(&self, event: &dyn crate::events::Event) -> bool {
418 if !self.is_alive() {
419 return false;
420 }
421 let mut store = crate::events::dispatcher::EventStoreAccess::new(self.cell);
422 crate::events::dispatch(self.cell, self.id, event, &mut store)
423 }
424}
425
426impl<T: crate::dom::traits::HasHandle> From<T> for Handle {
429 #[inline]
430 fn from(value: T) -> Self {
431 value.handle()
432 }
433}
434
435impl core::fmt::Debug for Handle {
436 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
437 write!(f, "Handle({:?})", self.id)
438 }
439}