1use crate::dom::Dom;
25use crate::error::{DomError, Result};
26use crate::node::NodeData;
27use crate::node_id::NodeId;
28use crate::observer::Mutation;
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub enum AdjacentPosition {
39 BeforeBegin,
40 AfterBegin,
41 BeforeEnd,
42 AfterEnd,
43}
44
45impl<Ext: 'static> Dom<Ext> {
46 pub fn append_child(&mut self, parent: NodeId, child: NodeId) -> Result<()> {
52 self.validate_insert(parent, child)?;
53
54 if matches!(
56 self.get_node(child).map(|n| &n.data),
57 Some(NodeData::Fragment)
58 ) {
59 let mut current = self.get_node(child).and_then(|n| n.first_child);
60 if let Some(n) = self.get_node_mut(child) {
62 n.first_child = None;
63 n.last_child = None;
64 }
65 while let Some(c) = current {
66 let next = self.get_node(c).and_then(|n| n.next_sibling);
68 if let Some(n) = self.get_node_mut(c) {
69 n.prev_sibling = None;
70 n.next_sibling = None;
71 n.parent = None;
72 }
73 self.append_child(parent, c)?;
74 current = next;
75 }
76 return Ok(());
77 }
78
79 self.detach_from_parent(child)?;
81
82 let last = self.get_node(parent).and_then(|n| n.last_child);
84 self.get_node_mut(child)
85 .ok_or(DomError::InvalidNode(child))?
86 .parent = Some(parent);
87 self.get_node_mut(child).unwrap().prev_sibling = last;
88 self.get_node_mut(child).unwrap().next_sibling = None;
89
90 match last {
91 Some(prev) => {
92 self.get_node_mut(prev).unwrap().next_sibling = Some(child);
93 }
94 None => {
95 self.get_node_mut(parent).unwrap().first_child = Some(child);
97 }
98 }
99 self.get_node_mut(parent).unwrap().last_child = Some(child);
100 self.fire_mutation(Mutation::ChildListChanged {
101 parent,
102 added: vec![child],
103 removed: vec![],
104 });
105 Ok(())
106 }
107
108 pub fn prepend_child(&mut self, parent: NodeId, child: NodeId) -> Result<()> {
110 let first = self.get_node(parent).and_then(|n| n.first_child);
111 self.insert_before(parent, child, first)
112 }
113
114 pub fn insert_before(
118 &mut self,
119 parent: NodeId,
120 new_child: NodeId,
121 reference_child: Option<NodeId>,
122 ) -> Result<()> {
123 let Some(reference) = reference_child else {
125 return self.append_child(parent, new_child);
126 };
127
128 if self.get_node(reference).and_then(|n| n.parent) != Some(parent) {
130 return Err(DomError::NotFound);
131 }
132
133 self.validate_insert(parent, new_child)?;
134
135 if matches!(
137 self.get_node(new_child).map(|n| &n.data),
138 Some(NodeData::Fragment)
139 ) {
140 let mut current = self.get_node(new_child).and_then(|n| n.first_child);
141 if let Some(n) = self.get_node_mut(new_child) {
142 n.first_child = None;
143 n.last_child = None;
144 }
145 while let Some(c) = current {
146 let next = self.get_node(c).and_then(|n| n.next_sibling);
147 if let Some(n) = self.get_node_mut(c) {
148 n.prev_sibling = None;
149 n.next_sibling = None;
150 n.parent = None;
151 }
152 self.insert_before(parent, c, Some(reference))?;
153 current = next;
154 }
155 return Ok(());
156 }
157
158 self.detach_from_parent(new_child)?;
159
160 let before = self.get_node(reference).and_then(|n| n.prev_sibling);
162 let new_node = self.get_node_mut(new_child).unwrap();
163 new_node.parent = Some(parent);
164 new_node.prev_sibling = before;
165 new_node.next_sibling = Some(reference);
166
167 match before {
168 Some(prev) => {
169 self.get_node_mut(prev).unwrap().next_sibling = Some(new_child);
170 }
171 None => {
172 self.get_node_mut(parent).unwrap().first_child = Some(new_child);
173 }
174 }
175 self.get_node_mut(reference).unwrap().prev_sibling = Some(new_child);
176 self.fire_mutation(Mutation::ChildListChanged {
177 parent,
178 added: vec![new_child],
179 removed: vec![],
180 });
181 Ok(())
182 }
183
184 pub fn remove_child(&mut self, parent: NodeId, child: NodeId) -> Result<()> {
196 if self.get_node(child).and_then(|n| n.parent) != Some(parent) {
197 return Err(DomError::NotFound);
198 }
199 self.detach_from_parent(child)?;
200 self.fire_mutation(Mutation::ChildListChanged {
201 parent,
202 added: vec![],
203 removed: vec![child],
204 });
205 Ok(())
206 }
207
208 pub fn replace_child(
211 &mut self,
212 parent: NodeId,
213 old_child: NodeId,
214 new_child: NodeId,
215 ) -> Result<()> {
216 if self.get_node(old_child).and_then(|n| n.parent) != Some(parent) {
217 return Err(DomError::NotFound);
218 }
219 self.validate_insert(parent, new_child)?;
220
221 let next = self.get_node(old_child).and_then(|n| n.next_sibling);
222 self.detach_from_parent(old_child)?;
223 self.insert_before(parent, new_child, next)
224 }
225
226 pub fn insert_adjacent(
229 &mut self,
230 reference: NodeId,
231 position: AdjacentPosition,
232 new_child: NodeId,
233 ) -> Result<()> {
234 match position {
235 AdjacentPosition::BeforeBegin => {
236 let parent = self
237 .get_node(reference)
238 .and_then(|n| n.parent)
239 .ok_or(DomError::HierarchyRequest)?;
240 self.insert_before(parent, new_child, Some(reference))
241 }
242 AdjacentPosition::AfterBegin => self.prepend_child(reference, new_child),
243 AdjacentPosition::BeforeEnd => self.append_child(reference, new_child),
244 AdjacentPosition::AfterEnd => {
245 let parent = self
246 .get_node(reference)
247 .and_then(|n| n.parent)
248 .ok_or(DomError::HierarchyRequest)?;
249 let after = self.get_node(reference).and_then(|n| n.next_sibling);
250 self.insert_before(parent, new_child, after)
251 }
252 }
253 }
254
255 pub fn clear_children(&mut self, parent: NodeId) -> Result<()> {
261 self.node_or_err(parent)?;
262 let mut removed: Vec<NodeId> = Vec::new();
263 while let Some(first) = self.get_node(parent).and_then(|n| n.first_child) {
264 removed.push(first);
265 self.detach_from_parent(first)?;
266 }
267 if !removed.is_empty() {
268 self.fire_mutation(Mutation::ChildListChanged {
269 parent,
270 added: vec![],
271 removed,
272 });
273 }
274 Ok(())
275 }
276
277 pub fn drop_subtree(&mut self, id: NodeId) -> Result<()> {
285 self.node_or_err(id)?;
286 if id == self.root {
287 return Err(DomError::HierarchyRequest);
288 }
289 let parent = self.get_node(id).and_then(|n| n.parent);
290 let mut to_free = Vec::new();
293 self.collect_descendants(id, &mut to_free);
294 let outcome = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
304 let _ = self.detach_from_parent(id);
305 if let Some(parent) = parent {
306 self.fire_mutation(Mutation::ChildListChanged {
307 parent,
308 added: vec![],
309 removed: vec![id],
310 });
311 }
312 }));
313 self.free_if_detached(id, to_free);
314 if let Err(payload) = outcome {
315 std::panic::resume_unwind(payload);
316 }
317 Ok(())
318 }
319
320 fn free_if_detached(&mut self, root: NodeId, to_free: Vec<NodeId>) {
325 if self.get_node(root).is_some_and(|n| n.parent.is_some()) {
326 return;
327 }
328 for n in to_free {
329 self.free(n);
330 }
331 }
332
333 pub fn remove_child_dropping(&mut self, parent: NodeId, child: NodeId) -> Result<()> {
341 if self.get_node(child).and_then(|n| n.parent) != Some(parent) {
342 return Err(DomError::NotFound);
343 }
344 let mut to_free = Vec::new();
345 self.collect_descendants(child, &mut to_free);
346 let outcome = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
349 self.remove_child(parent, child)
350 }));
351 self.free_if_detached(child, to_free);
352 match outcome {
353 Ok(result) => result,
354 Err(payload) => std::panic::resume_unwind(payload),
355 }
356 }
357
358 pub fn clear_children_dropping(&mut self, parent: NodeId) -> Result<()> {
363 self.node_or_err(parent)?;
364 let mut subtrees: Vec<(NodeId, Vec<NodeId>)> = Vec::new();
366 let mut cur = self.get_node(parent).and_then(|n| n.first_child);
367 while let Some(id) = cur {
368 let mut to_free = Vec::new();
369 self.collect_descendants(id, &mut to_free);
370 subtrees.push((id, to_free));
371 cur = self.get_node(id).and_then(|n| n.next_sibling);
372 }
373 let outcome =
375 std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| self.clear_children(parent)));
376 for (child, to_free) in subtrees {
377 self.free_if_detached(child, to_free);
378 }
379 match outcome {
380 Ok(result) => result,
381 Err(payload) => std::panic::resume_unwind(payload),
382 }
383 }
384
385 fn validate_insert(&self, parent: NodeId, child: NodeId) -> Result<()> {
390 self.node_or_err(parent)?;
391 self.node_or_err(child)?;
392 if self.is_ancestor(child, parent) {
393 return Err(DomError::HierarchyRequest);
394 }
395 Ok(())
396 }
397
398 pub(crate) fn detach_from_parent(&mut self, id: NodeId) -> Result<()> {
422 self.node_or_err(id)?;
423 let focused_in = self.focused.filter(|&f| self.is_ancestor(id, f));
434 let hovered_in = self.hovered.filter(|&h| self.is_ancestor(id, h));
435 if focused_in.is_some() || hovered_in.is_some() {
436 self.fire_mutation(Mutation::PreDetach {
437 detached_root: id,
438 focused: focused_in,
439 hovered: hovered_in,
440 });
441 }
442
443 let purged = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
451 self.purge_interaction_state_for_subtree(id, true);
452 }));
453
454 let node = self.node_or_err(id)?;
455 let parent = node.parent;
456 let prev = node.prev_sibling;
457 let next = node.next_sibling;
458
459 if let Some(prev) = prev {
460 self.get_node_mut(prev).unwrap().next_sibling = next;
461 }
462 if let Some(next) = next {
463 self.get_node_mut(next).unwrap().prev_sibling = prev;
464 }
465 if let Some(parent) = parent {
466 if self.get_node(parent).and_then(|n| n.first_child) == Some(id) {
467 self.get_node_mut(parent).unwrap().first_child = next;
468 }
469 if self.get_node(parent).and_then(|n| n.last_child) == Some(id) {
470 self.get_node_mut(parent).unwrap().last_child = prev;
471 }
472 }
473
474 let n = self.get_node_mut(id).unwrap();
475 n.parent = None;
476 n.prev_sibling = None;
477 n.next_sibling = None;
478
479 if let Err(payload) = purged {
480 self.purge_interaction_state_for_subtree(id, false);
481 std::panic::resume_unwind(payload);
482 }
483 Ok(())
484 }
485
486 fn purge_interaction_state_for_subtree(&mut self, root: NodeId, notify: bool) {
505 let inside =
506 |dom: &Self, node: Option<NodeId>| node.is_some_and(|n| dom.is_ancestor(root, n));
507 if inside(self, self.focused) {
508 if notify {
509 self.set_focused(None);
510 } else {
511 self.focused = None;
512 }
513 }
514 if inside(self, self.hovered) {
515 if notify {
516 self.set_hovered(None);
517 } else {
518 self.hovered = None;
519 }
520 }
521 if inside(self, self.active) {
522 if notify {
523 self.set_active(None);
524 } else {
525 self.active = None;
526 }
527 }
528 if inside(self, self.pointer_capture) {
529 self.pointer_capture = None;
530 }
531 let selected = self
532 .selection
533 .as_ref()
534 .map(|sel| (sel.anchor.node, sel.focus.node));
535 if let Some((anchor, focus)) = selected
536 && (inside(self, Some(anchor)) || inside(self, Some(focus)))
537 {
538 if notify {
539 self.set_selection(None);
540 } else {
541 self.selection = None;
542 self.selection_serial = self.selection_serial.next();
543 }
544 }
545 }
546
547 fn collect_descendants(&self, root: NodeId, out: &mut Vec<NodeId>) {
550 self.walk_subtree(root, &mut |id, _| out.push(id));
551 }
552}
553
554#[cfg(test)]
555mod tests {
556 use super::*;
557
558 fn sample() -> (Dom, NodeId, NodeId, NodeId) {
559 let mut dom: Dom = Dom::new();
560 let a = dom.create_element("a");
561 let b = dom.create_element("b");
562 let c = dom.create_element("c");
563 (dom, a, b, c)
564 }
565
566 #[test]
569 fn append_to_empty_parent() {
570 let (mut dom, a, _, _) = sample();
571 let root = dom.root();
572 dom.append_child(root, a).unwrap();
573 assert_eq!(dom.get_node(root).unwrap().first_child, Some(a));
574 assert_eq!(dom.get_node(root).unwrap().last_child, Some(a));
575 assert_eq!(dom.get_node(a).unwrap().parent, Some(root));
576 assert!(dom.get_node(a).unwrap().prev_sibling.is_none());
577 assert!(dom.get_node(a).unwrap().next_sibling.is_none());
578 }
579
580 #[test]
581 fn append_multiple_maintains_sibling_chain() {
582 let (mut dom, a, b, c) = sample();
583 let root = dom.root();
584 dom.append_child(root, a).unwrap();
585 dom.append_child(root, b).unwrap();
586 dom.append_child(root, c).unwrap();
587
588 assert_eq!(dom.get_node(root).unwrap().first_child, Some(a));
589 assert_eq!(dom.get_node(root).unwrap().last_child, Some(c));
590 assert_eq!(dom.get_node(a).unwrap().next_sibling, Some(b));
591 assert_eq!(dom.get_node(b).unwrap().prev_sibling, Some(a));
592 assert_eq!(dom.get_node(b).unwrap().next_sibling, Some(c));
593 assert_eq!(dom.get_node(c).unwrap().prev_sibling, Some(b));
594 }
595
596 #[test]
597 fn append_moves_node_from_old_parent() {
598 let (mut dom, a, b, _) = sample();
599 let root = dom.root();
600 dom.append_child(root, a).unwrap();
601 dom.append_child(a, b).unwrap();
602 dom.append_child(root, b).unwrap(); assert_eq!(dom.get_node(b).unwrap().parent, Some(root));
604 assert!(dom.get_node(a).unwrap().first_child.is_none());
605 assert!(dom.get_node(a).unwrap().last_child.is_none());
606 }
607
608 #[test]
609 fn append_rejects_cycle() {
610 let (mut dom, a, b, _) = sample();
611 let root = dom.root();
612 dom.append_child(root, a).unwrap();
613 dom.append_child(a, b).unwrap();
614 assert!(matches!(
616 dom.append_child(b, a).unwrap_err(),
617 DomError::HierarchyRequest
618 ));
619 }
620
621 #[test]
627 fn drop_subtree_frees_even_when_an_observer_panics() {
628 struct Bomb;
629 impl crate::MutationObserver<()> for Bomb {
630 fn observe(&mut self, _dom: &mut Dom, _record: &crate::Mutation) {
631 panic!("observer bomb");
632 }
633 }
634 let mut dom: Dom = Dom::new();
635 let root = dom.root();
636 let div = dom.create_element("div");
637 let span = dom.create_element("span");
638 dom.append_child(root, div).unwrap();
639 dom.append_child(div, span).unwrap();
640 dom.add_mutation_observer(Box::new(Bomb));
641
642 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
643 dom.drop_subtree(div).unwrap();
644 }));
645 assert!(result.is_err(), "the bomb must actually fire");
646 assert!(!dom.contains(div), "subtree root was freed");
647 assert!(!dom.contains(span), "subtree descendant was freed");
648 assert_eq!(dom.len(), 1, "only the root remains");
649 assert!(dom.validate().is_empty());
650 }
651
652 #[test]
658 fn drop_subtree_frees_when_the_focus_purge_observer_panics() {
659 struct Bomb;
660 impl crate::MutationObserver<()> for Bomb {
661 fn observe(&mut self, _dom: &mut Dom, record: &crate::Mutation) {
662 if matches!(record, crate::Mutation::InteractionChanged { .. }) {
663 panic!("observer bomb");
664 }
665 }
666 }
667 let mut dom: Dom = Dom::new();
668 let root = dom.root();
669 let div = dom.create_element("div");
670 let span = dom.create_element("span");
671 dom.append_child(root, div).unwrap();
672 dom.append_child(div, span).unwrap();
673 dom.set_focused(Some(span));
674 dom.add_mutation_observer(Box::new(Bomb));
675
676 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
677 dom.drop_subtree(div).unwrap();
678 }));
679 assert!(result.is_err(), "the bomb must actually fire");
680 assert!(
681 !dom.contains(div) && !dom.contains(span),
682 "subtree was freed"
683 );
684 assert_eq!(dom.len(), 1);
685 assert_eq!(dom.focused(), None);
686 assert!(dom.validate().is_empty());
687 }
688
689 #[test]
690 fn drop_subtree_frees_when_the_selection_purge_observer_panics() {
691 struct Bomb;
692 impl crate::MutationObserver<()> for Bomb {
693 fn observe(&mut self, _dom: &mut Dom, record: &crate::Mutation) {
694 if matches!(record, crate::Mutation::SelectionChanged { .. }) {
695 panic!("observer bomb");
696 }
697 }
698 }
699 let mut dom: Dom = Dom::new();
700 let root = dom.root();
701 let div = dom.create_element("div");
702 let text = dom.create_text_node("hello");
703 dom.append_child(root, div).unwrap();
704 dom.append_child(div, text).unwrap();
705 let at = crate::Position {
706 node: text,
707 offset: 1,
708 };
709 dom.set_selection(Some(crate::Selection {
710 anchor: at,
711 focus: at,
712 }));
713 dom.add_mutation_observer(Box::new(Bomb));
714
715 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
716 dom.drop_subtree(div).unwrap();
717 }));
718 assert!(result.is_err(), "the bomb must actually fire");
719 assert!(
720 !dom.contains(div) && !dom.contains(text),
721 "subtree was freed"
722 );
723 assert_eq!(dom.len(), 1);
724 assert!(dom.validate().is_empty());
725 }
726
727 #[test]
731 fn dropping_wrappers_free_when_an_observer_panics() {
732 struct Bomb;
733 impl crate::MutationObserver<()> for Bomb {
734 fn observe(&mut self, _dom: &mut Dom, record: &crate::Mutation) {
735 if matches!(record, crate::Mutation::ChildListChanged { .. }) {
736 panic!("observer bomb");
737 }
738 }
739 }
740 let mut dom: Dom = Dom::new();
741 let root = dom.root();
742 let a = dom.create_element("a");
743 let a_kid = dom.create_element("kid");
744 let b = dom.create_element("b");
745 let c = dom.create_element("c");
746 dom.append_child(root, a).unwrap();
747 dom.append_child(a, a_kid).unwrap();
748 dom.append_child(root, b).unwrap();
749 dom.append_child(root, c).unwrap();
750 dom.add_mutation_observer(Box::new(Bomb));
751
752 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
753 dom.remove_child_dropping(root, a).unwrap();
754 }));
755 assert!(result.is_err());
756 assert!(
757 !dom.contains(a) && !dom.contains(a_kid),
758 "removed subtree was freed"
759 );
760 assert_eq!(dom.len(), 3, "root, b, c");
761
762 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
763 dom.clear_children_dropping(root).unwrap();
764 }));
765 assert!(result.is_err());
766 assert!(
767 !dom.contains(b) && !dom.contains(c),
768 "cleared children were freed"
769 );
770 assert_eq!(dom.len(), 1);
771 assert!(dom.validate().is_empty());
772 }
773
774 #[test]
778 fn drop_subtree_keeps_an_attached_subtree_when_pre_detach_panics() {
779 struct Bomb;
780 impl crate::MutationObserver<()> for Bomb {
781 fn observe(&mut self, _dom: &mut Dom, record: &crate::Mutation) {
782 if matches!(record, crate::Mutation::PreDetach { .. }) {
783 panic!("observer bomb");
784 }
785 }
786 }
787 let mut dom: Dom = Dom::new();
788 let root = dom.root();
789 let div = dom.create_element("div");
790 let span = dom.create_element("span");
791 dom.append_child(root, div).unwrap();
792 dom.append_child(div, span).unwrap();
793 dom.set_focused(Some(span));
794 dom.add_mutation_observer(Box::new(Bomb));
795
796 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
797 dom.drop_subtree(div).unwrap();
798 }));
799 assert!(result.is_err());
800 assert!(
801 dom.contains(div) && dom.contains(span),
802 "still attached, not freed"
803 );
804 assert_eq!(dom.node(root).first_child().map(|n| n.id()), Some(div));
805 assert!(dom.validate().is_empty());
806 }
807
808 #[test]
811 fn drop_subtree_rejects_the_root() {
812 let mut dom: Dom = Dom::new();
813 let root = dom.root();
814 let child = dom.create_element("div");
815 dom.append_child(root, child).unwrap();
816 assert!(matches!(
817 dom.drop_subtree(root).unwrap_err(),
818 DomError::HierarchyRequest
819 ));
820 assert!(dom.contains(root));
821 assert!(dom.contains(child), "nothing was freed");
822 assert!(dom.validate().is_empty());
823 }
824
825 #[test]
826 fn append_rejects_invalid_parent() {
827 let mut dom: Dom = Dom::new();
828 let ghost = NodeId::from_parts(999, std::num::NonZeroU32::MIN);
830 let child = dom.create_element("child");
831 assert!(matches!(
832 dom.append_child(ghost, child).unwrap_err(),
833 DomError::InvalidNode(_)
834 ));
835 }
836
837 #[test]
840 fn insert_before_first_becomes_new_first() {
841 let (mut dom, a, b, _) = sample();
842 let root = dom.root();
843 dom.append_child(root, a).unwrap();
844 dom.insert_before(root, b, Some(a)).unwrap();
845 assert_eq!(dom.get_node(root).unwrap().first_child, Some(b));
846 assert_eq!(dom.get_node(root).unwrap().last_child, Some(a));
847 assert_eq!(dom.get_node(b).unwrap().next_sibling, Some(a));
848 assert_eq!(dom.get_node(a).unwrap().prev_sibling, Some(b));
849 }
850
851 #[test]
852 fn insert_before_middle_updates_chain() {
853 let (mut dom, a, b, c) = sample();
854 let root = dom.root();
855 dom.append_child(root, a).unwrap();
856 dom.append_child(root, c).unwrap();
857 dom.insert_before(root, b, Some(c)).unwrap();
858 let names: Vec<_> = iter_children(&dom, root)
860 .map(|id| dom.get_node(id).unwrap().tag_name().unwrap().to_string())
861 .collect();
862 assert_eq!(names, vec!["a", "b", "c"]);
863 }
864
865 #[test]
866 fn insert_before_null_appends() {
867 let (mut dom, a, b, _) = sample();
868 let root = dom.root();
869 dom.append_child(root, a).unwrap();
870 dom.insert_before(root, b, None).unwrap();
871 assert_eq!(dom.get_node(root).unwrap().last_child, Some(b));
872 }
873
874 #[test]
875 fn insert_before_rejects_non_child_reference() {
876 let (mut dom, a, b, _) = sample();
877 let root = dom.root();
878 dom.append_child(root, a).unwrap();
879 assert!(matches!(
881 dom.insert_before(root, a, Some(b)).unwrap_err(),
882 DomError::NotFound
883 ));
884 }
885
886 #[test]
889 fn remove_child_detaches_but_keeps_in_arena() {
890 let (mut dom, a, _, _) = sample();
891 let root = dom.root();
892 dom.append_child(root, a).unwrap();
893 dom.remove_child(root, a).unwrap();
894 assert!(dom.get_node(root).unwrap().first_child.is_none());
895 assert!(dom.get_node(a).unwrap().parent.is_none());
896 assert!(dom.contains(a)); }
898
899 #[test]
900 fn remove_middle_child_fixes_siblings() {
901 let (mut dom, a, b, c) = sample();
902 let root = dom.root();
903 dom.append_child(root, a).unwrap();
904 dom.append_child(root, b).unwrap();
905 dom.append_child(root, c).unwrap();
906 dom.remove_child(root, b).unwrap();
907 assert_eq!(dom.get_node(a).unwrap().next_sibling, Some(c));
908 assert_eq!(dom.get_node(c).unwrap().prev_sibling, Some(a));
909 }
910
911 #[test]
912 fn remove_nonchild_errors() {
913 let (mut dom, a, _, _) = sample();
914 let root = dom.root();
915 assert!(matches!(
916 dom.remove_child(root, a).unwrap_err(),
917 DomError::NotFound
918 ));
919 }
920
921 #[test]
924 fn replace_child_preserves_position() {
925 let (mut dom, a, b, c) = sample();
926 let root = dom.root();
927 dom.append_child(root, a).unwrap();
928 dom.append_child(root, b).unwrap();
929 dom.append_child(root, c).unwrap();
930
931 let d = dom.create_element("d");
932 dom.replace_child(root, b, d).unwrap();
933 let names: Vec<_> = iter_children(&dom, root)
934 .map(|id| dom.get_node(id).unwrap().tag_name().unwrap().to_string())
935 .collect();
936 assert_eq!(names, vec!["a", "d", "c"]);
937 }
938
939 #[test]
942 fn fragment_unwraps_on_append() {
943 let mut dom: Dom = Dom::new();
944 let root = dom.root();
945 let frag = dom.create_document_fragment();
946 let a = dom.create_element("a");
947 let b = dom.create_element("b");
948 dom.append_child(frag, a).unwrap();
949 dom.append_child(frag, b).unwrap();
950
951 dom.append_child(root, frag).unwrap();
952
953 assert_eq!(dom.get_node(root).unwrap().first_child, Some(a));
955 assert_eq!(dom.get_node(root).unwrap().last_child, Some(b));
956 assert!(dom.get_node(frag).unwrap().first_child.is_none());
957 }
958
959 #[test]
960 fn fragment_unwraps_on_insert_before() {
961 let mut dom: Dom = Dom::new();
962 let root = dom.root();
963 let existing = dom.create_element("existing");
964 dom.append_child(root, existing).unwrap();
965
966 let frag = dom.create_document_fragment();
967 let x = dom.create_element("x");
968 let y = dom.create_element("y");
969 dom.append_child(frag, x).unwrap();
970 dom.append_child(frag, y).unwrap();
971
972 dom.insert_before(root, frag, Some(existing)).unwrap();
973
974 let names: Vec<_> = iter_children(&dom, root)
975 .map(|id| dom.get_node(id).unwrap().tag_name().unwrap().to_string())
976 .collect();
977 assert_eq!(names, vec!["x", "y", "existing"]);
978 }
979
980 #[test]
983 fn insert_adjacent_before_begin() {
984 let (mut dom, a, b, _) = sample();
985 let root = dom.root();
986 dom.append_child(root, a).unwrap();
987 dom.insert_adjacent(a, AdjacentPosition::BeforeBegin, b)
988 .unwrap();
989 assert_eq!(dom.get_node(root).unwrap().first_child, Some(b));
990 assert_eq!(dom.get_node(b).unwrap().next_sibling, Some(a));
991 }
992
993 #[test]
994 fn insert_adjacent_after_end() {
995 let (mut dom, a, b, _) = sample();
996 let root = dom.root();
997 dom.append_child(root, a).unwrap();
998 dom.insert_adjacent(a, AdjacentPosition::AfterEnd, b)
999 .unwrap();
1000 assert_eq!(dom.get_node(a).unwrap().next_sibling, Some(b));
1001 assert_eq!(dom.get_node(root).unwrap().last_child, Some(b));
1002 }
1003
1004 #[test]
1005 fn insert_adjacent_after_begin_prepends() {
1006 let (mut dom, a, b, c) = sample();
1007 let root = dom.root();
1008 dom.append_child(root, a).unwrap();
1009 dom.append_child(root, b).unwrap();
1010 dom.insert_adjacent(root, AdjacentPosition::AfterBegin, c)
1012 .unwrap();
1013 assert_eq!(dom.get_node(root).unwrap().first_child, Some(c));
1014 }
1015
1016 #[test]
1019 fn clear_children_detaches_all() {
1020 let (mut dom, a, b, c) = sample();
1021 let root = dom.root();
1022 dom.append_child(root, a).unwrap();
1023 dom.append_child(root, b).unwrap();
1024 dom.append_child(root, c).unwrap();
1025
1026 dom.clear_children(root).unwrap();
1027 assert!(dom.get_node(root).unwrap().first_child.is_none());
1028 assert!(dom.contains(a));
1030 assert!(dom.contains(b));
1031 assert!(dom.contains(c));
1032 assert!(dom.get_node(a).unwrap().parent.is_none());
1033 }
1034
1035 #[test]
1036 fn remove_child_dropping_frees_the_node() {
1037 let (mut dom, a, b, _c) = sample();
1038 let root = dom.root();
1039 dom.append_child(root, a).unwrap();
1040 dom.append_child(a, b).unwrap();
1041
1042 dom.remove_child_dropping(root, a).unwrap();
1043 assert!(!dom.contains(a));
1045 assert!(!dom.contains(b));
1046 assert!(dom.get_node(root).unwrap().first_child.is_none());
1047 }
1048
1049 #[test]
1050 fn clear_children_dropping_frees_all() {
1051 let (mut dom, a, b, c) = sample();
1052 let root = dom.root();
1053 dom.append_child(root, a).unwrap();
1054 dom.append_child(root, b).unwrap();
1055 dom.append_child(root, c).unwrap();
1056
1057 dom.clear_children_dropping(root).unwrap();
1058 assert!(dom.get_node(root).unwrap().first_child.is_none());
1059 assert!(!dom.contains(a));
1061 assert!(!dom.contains(b));
1062 assert!(!dom.contains(c));
1063 }
1064
1065 #[test]
1066 fn drop_subtree_frees_everything() {
1067 let mut dom: Dom = Dom::new();
1068 let root = dom.root();
1069 let a = dom.create_element("a");
1070 let b = dom.create_element("b");
1071 let c = dom.create_element("c");
1072 dom.append_child(root, a).unwrap();
1073 dom.append_child(a, b).unwrap();
1074 dom.append_child(b, c).unwrap();
1075
1076 dom.drop_subtree(a).unwrap();
1077 assert!(!dom.contains(a));
1078 assert!(!dom.contains(b));
1079 assert!(!dom.contains(c));
1080 assert!(dom.get_node(root).unwrap().first_child.is_none());
1081 }
1082
1083 fn iter_children(dom: &Dom, parent: NodeId) -> impl Iterator<Item = NodeId> + '_ {
1086 let mut cur = dom.get_node(parent).and_then(|n| n.first_child);
1087 std::iter::from_fn(move || {
1088 let c = cur?;
1089 cur = dom.get_node(c).and_then(|n| n.next_sibling);
1090 Some(c)
1091 })
1092 }
1093}