From 1651757d9f1ad6c1854d2849cdfe66a7d87ba22e Mon Sep 17 00:00:00 2001 From: Adam Reichold Date: Mon, 26 Aug 2024 14:36:50 +0200 Subject: [PATCH 1/2] Provide consuming movement methods so that NodeMut can act as a cursor. --- src/lib.rs | 83 +++++++++++++++++++++++++++++++++-------------- tests/node_mut.rs | 24 ++++++++++++++ 2 files changed, 82 insertions(+), 25 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 967bcb1..7bbb39f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -247,39 +247,36 @@ impl<'a, T: 'a> NodeRef<'a, T> { &self.node.value } + fn axis(&self, f: F) -> Option + where + F: FnOnce(&Node) -> Option, + { + f(self.node).map(|id| unsafe { self.tree.get_unchecked(id) }) + } + /// Returns the parent of this node. pub fn parent(&self) -> Option { - self.node - .parent - .map(|id| unsafe { self.tree.get_unchecked(id) }) + self.axis(|node| node.parent) } /// Returns the previous sibling of this node. pub fn prev_sibling(&self) -> Option { - self.node - .prev_sibling - .map(|id| unsafe { self.tree.get_unchecked(id) }) + self.axis(|node| node.prev_sibling) } /// Returns the next sibling of this node. pub fn next_sibling(&self) -> Option { - self.node - .next_sibling - .map(|id| unsafe { self.tree.get_unchecked(id) }) + self.axis(|node| node.next_sibling) } /// Returns the first child of this node. pub fn first_child(&self) -> Option { - self.node - .children - .map(|(id, _)| unsafe { self.tree.get_unchecked(id) }) + self.axis(|node| node.children.map(|(id, _)| id)) } /// Returns the last child of this node. pub fn last_child(&self) -> Option { - self.node - .children - .map(|(_, id)| unsafe { self.tree.get_unchecked(id) }) + self.axis(|node| node.children.map(|(_, id)| id)) } /// Returns true if this node has siblings. @@ -313,34 +310,70 @@ impl<'a, T: 'a> NodeMut<'a, T> { &mut self.node().value } + fn axis(&mut self, f: F) -> Option> + where + F: FnOnce(&mut Node) -> Option, + { + let id = f(self.node()); + id.map(move |id| unsafe { self.tree.get_unchecked_mut(id) }) + } + + fn into_axis(mut self, f: F) -> Option + where + F: FnOnce(&mut Node) -> Option, + { + let id = f(self.node()); + id.map(move |id| unsafe { self.tree.get_unchecked_mut(id) }) + } + /// Returns the parent of this node. pub fn parent(&mut self) -> Option> { - let id = self.node().parent; - id.map(move |id| unsafe { self.tree.get_unchecked_mut(id) }) + self.axis(|node| node.parent) + } + + /// Returns the parent of this node. + pub fn into_parent(self) -> Option { + self.into_axis(|node| node.parent) } /// Returns the previous sibling of this node. pub fn prev_sibling(&mut self) -> Option> { - let id = self.node().prev_sibling; - id.map(move |id| unsafe { self.tree.get_unchecked_mut(id) }) + self.axis(|node| node.prev_sibling) + } + + /// Returns the previous sibling of this node. + pub fn into_prev_sibling(self) -> Option { + self.into_axis(|node| node.prev_sibling) } /// Returns the next sibling of this node. pub fn next_sibling(&mut self) -> Option> { - let id = self.node().next_sibling; - id.map(move |id| unsafe { self.tree.get_unchecked_mut(id) }) + self.axis(|node| node.next_sibling) + } + + /// Returns the next sibling of this node. + pub fn into_next_sibling(self) -> Option { + self.into_axis(|node| node.next_sibling) } /// Returns the first child of this node. pub fn first_child(&mut self) -> Option> { - let ids = self.node().children; - ids.map(move |(id, _)| unsafe { self.tree.get_unchecked_mut(id) }) + self.axis(|node| node.children.map(|(id, _)| id)) + } + + /// Returns the first child of this node. + pub fn into_first_child(self) -> Option { + self.into_axis(|node| node.children.map(|(id, _)| id)) } /// Returns the last child of this node. pub fn last_child(&mut self) -> Option> { - let ids = self.node().children; - ids.map(move |(_, id)| unsafe { self.tree.get_unchecked_mut(id) }) + self.axis(|node| node.children.map(|(_, id)| id)) + } + + /// Returns the last child of this node. + pub fn into_last_child(self) -> Option { + self.into_axis(|node| node.children.map(|(_, id)| id)) } /// Returns true if this node has siblings. diff --git a/tests/node_mut.rs b/tests/node_mut.rs index d9b00af..20aff6b 100644 --- a/tests/node_mut.rs +++ b/tests/node_mut.rs @@ -277,6 +277,30 @@ fn insert_after() { assert_eq!(None, d.next_sibling()); } +#[test] +fn insert_at_index() { + let mut tree = tree!('a' => { 'b', 'c', 'e' }); + + { + let mut root = tree.root_mut(); + let mut child = root.first_child().unwrap(); + + for _ in 0..2 { + child = child.into_next_sibling().unwrap(); + } + + child.insert_before('d'); + } + + let descendants = tree + .root() + .descendants() + .map(|n| n.value()) + .collect::>(); + + assert_eq!(&[&'a', &'b', &'c', &'d', &'e',], &descendants[..]); +} + #[test] fn detach() { let mut tree = tree!('a' => { 'b', 'd' }); From 118d629609da6ab4d637813d0909477464435a0f Mon Sep 17 00:00:00 2001 From: Adam Reichold Date: Tue, 27 Aug 2024 21:44:31 +0200 Subject: [PATCH 2/2] Extend consuming movement methods to yield current node reference if navigation is not possible. --- src/lib.rs | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7bbb39f..566d84d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -318,12 +318,15 @@ impl<'a, T: 'a> NodeMut<'a, T> { id.map(move |id| unsafe { self.tree.get_unchecked_mut(id) }) } - fn into_axis(mut self, f: F) -> Option + fn into_axis(mut self, f: F) -> Result where F: FnOnce(&mut Node) -> Option, { let id = f(self.node()); - id.map(move |id| unsafe { self.tree.get_unchecked_mut(id) }) + match id { + Some(id) => Ok(unsafe { self.tree.get_unchecked_mut(id) }), + None => Err(self), + } } /// Returns the parent of this node. @@ -332,7 +335,10 @@ impl<'a, T: 'a> NodeMut<'a, T> { } /// Returns the parent of this node. - pub fn into_parent(self) -> Option { + /// + /// Returns `Ok(parent)` if possible and `Err(self)` otherwise + /// so the caller can recover the current position. + pub fn into_parent(self) -> Result { self.into_axis(|node| node.parent) } @@ -342,7 +348,10 @@ impl<'a, T: 'a> NodeMut<'a, T> { } /// Returns the previous sibling of this node. - pub fn into_prev_sibling(self) -> Option { + /// + /// Returns `Ok(prev_sibling)` if possible and `Err(self)` otherwise + /// so the caller can recover the current position. + pub fn into_prev_sibling(self) -> Result { self.into_axis(|node| node.prev_sibling) } @@ -352,7 +361,10 @@ impl<'a, T: 'a> NodeMut<'a, T> { } /// Returns the next sibling of this node. - pub fn into_next_sibling(self) -> Option { + /// + /// Returns `Ok(next_sibling)` if possible and `Err(self)` otherwise + /// so the caller can recover the current position. + pub fn into_next_sibling(self) -> Result { self.into_axis(|node| node.next_sibling) } @@ -362,7 +374,10 @@ impl<'a, T: 'a> NodeMut<'a, T> { } /// Returns the first child of this node. - pub fn into_first_child(self) -> Option { + /// + /// Returns `Ok(first_child)` if possible and `Err(self)` otherwise + /// so the caller can recover the current position. + pub fn into_first_child(self) -> Result { self.into_axis(|node| node.children.map(|(id, _)| id)) } @@ -372,7 +387,10 @@ impl<'a, T: 'a> NodeMut<'a, T> { } /// Returns the last child of this node. - pub fn into_last_child(self) -> Option { + /// + /// Returns `Ok(last_child)` if possible and `Err(self)` otherwise + /// so the caller can recover the current position. + pub fn into_last_child(self) -> Result { self.into_axis(|node| node.children.map(|(_, id)| id)) }