1use crate::{BranchNodeCompact, Nibbles, StoredSubNode, CHILD_INDEX_RANGE};
2use alloy_primitives::B256;
3
4#[derive(Clone)]
6pub struct CursorSubNode {
7 pub key: Nibbles,
9 position: SubNodePosition,
11 pub node: Option<BranchNodeCompact>,
13 full_key: Nibbles,
15}
16
17impl Default for CursorSubNode {
18 fn default() -> Self {
19 Self::new(Nibbles::default(), None)
20 }
21}
22
23impl std::fmt::Debug for CursorSubNode {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 f.debug_struct("CursorSubNode")
26 .field("key", &self.key)
27 .field("position", &self.position)
28 .field("state_flag", &self.state_flag())
29 .field("tree_flag", &self.tree_flag())
30 .field("hash_flag", &self.hash_flag())
31 .field("hash", &self.maybe_hash())
32 .finish()
33 }
34}
35
36impl From<StoredSubNode> for CursorSubNode {
38 fn from(value: StoredSubNode) -> Self {
43 let position = value.nibble.map_or(SubNodePosition::ParentBranch, SubNodePosition::Child);
44 let key = Nibbles::from_nibbles_unchecked(value.key);
45 Self::new_with_full_key(key, value.node, position)
46 }
47}
48
49impl From<CursorSubNode> for StoredSubNode {
50 fn from(value: CursorSubNode) -> Self {
51 Self { key: value.key.to_vec(), nibble: value.position.as_child(), node: value.node }
52 }
53}
54
55impl CursorSubNode {
56 pub fn new(key: Nibbles, node: Option<BranchNodeCompact>) -> Self {
58 let position = node.as_ref().filter(|n| n.root_hash.is_none()).map_or(
60 SubNodePosition::ParentBranch,
61 |n| {
62 SubNodePosition::Child(
63 CHILD_INDEX_RANGE.clone().find(|i| n.state_mask.is_bit_set(*i)).unwrap(),
64 )
65 },
66 );
67 Self::new_with_full_key(key, node, position)
68 }
69
70 fn new_with_full_key(
73 key: Nibbles,
74 node: Option<BranchNodeCompact>,
75 position: SubNodePosition,
76 ) -> Self {
77 let mut full_key = key.clone();
78 if let Some(nibble) = position.as_child() {
79 full_key.push(nibble);
80 }
81 Self { key, node, position, full_key }
82 }
83
84 #[inline]
86 pub const fn full_key(&self) -> &Nibbles {
87 &self.full_key
88 }
89
90 #[inline]
93 fn update_full_key(&mut self, old_position: SubNodePosition) {
94 if let Some(new_nibble) = self.position.as_child() {
95 if old_position.is_child() {
96 let last_index = self.full_key.len() - 1;
97 self.full_key.set_at(last_index, new_nibble);
98 } else {
99 self.full_key.push(new_nibble);
100 }
101 } else if old_position.is_child() {
102 self.full_key.pop();
103 }
104 }
105
106 #[inline]
111 pub fn state_flag(&self) -> bool {
112 self.node.as_ref().is_none_or(|node| {
113 self.position.as_child().is_none_or(|nibble| node.state_mask.is_bit_set(nibble))
114 })
115 }
116
117 #[inline]
122 pub fn tree_flag(&self) -> bool {
123 self.node.as_ref().is_none_or(|node| {
124 self.position.as_child().is_none_or(|nibble| node.tree_mask.is_bit_set(nibble))
125 })
126 }
127
128 pub fn hash_flag(&self) -> bool {
134 self.node.as_ref().is_some_and(|node| match self.position {
135 SubNodePosition::ParentBranch => node.root_hash.is_some(),
137 SubNodePosition::Child(nibble) => node.hash_mask.is_bit_set(nibble),
139 })
140 }
141
142 pub fn hash(&self) -> Option<B256> {
149 self.node.as_ref().and_then(|node| match self.position {
150 SubNodePosition::ParentBranch => node.root_hash,
152 SubNodePosition::Child(nibble) => Some(node.hash_for_nibble(nibble)),
154 })
155 }
156
157 pub fn maybe_hash(&self) -> Option<B256> {
162 self.node.as_ref().and_then(|node| match self.position {
163 SubNodePosition::ParentBranch => node.root_hash,
165 SubNodePosition::Child(nibble) => {
167 node.hash_mask.is_bit_set(nibble).then(|| node.hash_for_nibble(nibble))
168 }
169 })
170 }
171
172 #[inline]
174 pub const fn position(&self) -> SubNodePosition {
175 self.position
176 }
177
178 #[inline]
180 pub fn inc_nibble(&mut self) {
181 let old_position = self.position;
182 self.position.increment();
183 self.update_full_key(old_position);
184 }
185
186 #[inline]
188 pub fn set_nibble(&mut self, nibble: u8) {
189 let old_position = self.position;
190 self.position = SubNodePosition::Child(nibble);
191 self.update_full_key(old_position);
192 }
193}
194
195#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
197pub enum SubNodePosition {
198 ParentBranch,
200 Child(u8),
202}
203
204impl SubNodePosition {
205 pub const fn is_parent(&self) -> bool {
207 matches!(self, Self::ParentBranch)
208 }
209
210 pub const fn is_child(&self) -> bool {
212 matches!(self, Self::Child(_))
213 }
214
215 pub const fn as_child(&self) -> Option<u8> {
217 match self {
218 Self::Child(nibble) => Some(*nibble),
219 _ => None,
220 }
221 }
222
223 pub const fn is_last_child(&self) -> bool {
226 match self {
227 Self::ParentBranch => false,
228 Self::Child(nibble) => *nibble >= 0xf,
229 }
230 }
231
232 const fn increment(&mut self) {
233 match self {
234 Self::ParentBranch => *self = Self::Child(0),
235 Self::Child(nibble) => *nibble += 1,
236 }
237 }
238}
239
240#[cfg(test)]
241mod tests {
242 use super::*;
243
244 #[test]
245 fn subnode_position_ord() {
246 assert!([
247 SubNodePosition::ParentBranch,
248 SubNodePosition::Child(0),
249 SubNodePosition::Child(1),
250 SubNodePosition::Child(2),
251 SubNodePosition::Child(3),
252 SubNodePosition::Child(4),
253 SubNodePosition::Child(5),
254 SubNodePosition::Child(6),
255 SubNodePosition::Child(7),
256 SubNodePosition::Child(8),
257 SubNodePosition::Child(9),
258 SubNodePosition::Child(10),
259 SubNodePosition::Child(11),
260 SubNodePosition::Child(12),
261 SubNodePosition::Child(13),
262 SubNodePosition::Child(14),
263 SubNodePosition::Child(15),
264 ]
265 .is_sorted());
266 }
267
268 #[test]
269 fn subnode_position_is_last_child() {
270 assert!([
271 SubNodePosition::ParentBranch,
272 SubNodePosition::Child(0),
273 SubNodePosition::Child(1),
274 SubNodePosition::Child(2),
275 SubNodePosition::Child(3),
276 SubNodePosition::Child(4),
277 SubNodePosition::Child(5),
278 SubNodePosition::Child(6),
279 SubNodePosition::Child(7),
280 SubNodePosition::Child(8),
281 SubNodePosition::Child(9),
282 SubNodePosition::Child(10),
283 SubNodePosition::Child(11),
284 SubNodePosition::Child(12),
285 SubNodePosition::Child(13),
286 SubNodePosition::Child(14),
287 ]
288 .iter()
289 .all(|position| !position.is_last_child()));
290 assert!(SubNodePosition::Child(15).is_last_child());
291 assert!(SubNodePosition::Child(16).is_last_child());
292 }
293}