diff --git a/src/lib.rs b/src/lib.rs index 967bcb1..566d84d 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,88 @@ 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) -> Result + where + F: FnOnce(&mut Node) -> Option, + { + let id = f(self.node()); + match id { + Some(id) => Ok(unsafe { self.tree.get_unchecked_mut(id) }), + None => Err(self), + } + } + /// 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. + /// + /// 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) } /// 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. + /// + /// 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) } /// 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. + /// + /// 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) } /// 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. + /// + /// 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)) } /// 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. + /// + /// 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)) } /// 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' });