Ensure &Node<T> is not removed#198
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #198 +/- ##
=======================================
- Coverage 97.5% 96.7% -0.8%
=======================================
Files 10 10
Lines 1127 1212 +85
=======================================
+ Hits 1099 1173 +74
- Misses 28 39 +11 🚀 New features to boost your workflow:
|
saschagrunert
left a comment
There was a problem hiding this comment.
Good API improvement that addresses the inconsistency in #195. A few suggestions below.
Co-Authored-By: Sascha Grunert <sgrunert@redhat.com>
4823680 to
d0a082e
Compare
|
Thanks for the thorough review @saschagrunert! |
saschagrunert
left a comment
There was a problem hiding this comment.
Second pass review, five inline comments.
| } | ||
| debug_assert!(!previous.is_some_and(|id| arena[id].is_removed())); | ||
| debug_assert!(!next.is_some_and(|id| arena[id].is_removed())); | ||
| } |
There was a problem hiding this comment.
The two debug_assert! lines that checked previous and next are not removed nodes were deleted here (old lines 81-82). Only the parent check survived. Consider restoring them:
debug_assert!(!previous.is_some_and(|id| id.is_removed(arena)));
debug_assert!(!next.is_some_and(|id| id.is_removed(arena)));| } | ||
| } | ||
|
|
||
| /// Returns a mutable reference to the node data. |
There was a problem hiding this comment.
Since nodes is pub(crate), internal code can still construct &Node<T> for a removed node via &arena.nodes[id.index0()]. If that happens, this unreachable! would be misleading. Consider keeping panic!("attempted to access a freed node") as a safety net.
| } | ||
| }; | ||
| let is_last_sibling = traverser.arena()[id].next_sibling().is_none(); | ||
| let is_last_sibling = traverser.arena().nodes[id.index0()] |
There was a problem hiding this comment.
id comes from a live traversal, so traverser.arena().get(id).and_then(Node::next_sibling).is_none() would work here and stay consistent with the rest of the PR.
| /// ``` | ||
| pub fn count(&self) -> usize { | ||
| self.nodes.len() | ||
| self.iter().count() |
There was a problem hiding this comment.
This changes count() from O(1) to O(n) since iter() now filters removed nodes. Worth a doc note about the linear cost, since the old count() was just Vec::len().
|
|
||
| #[test] | ||
| #[should_panic(expected = "index out of bounds")] | ||
| fn inaccessible_node() { |
There was a problem hiding this comment.
No replacement test covers arena.get(id) / id.is_removed(&arena) behavior after arena.clear(). The new is_removed handles out-of-bounds gracefully, but a test would confirm that.
This pull request modifies the design of the API so that an
&Node<T>to a consumer will never be a removed node.Resolves #195