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.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 #[inline]
159 pub const fn position(&self) -> SubNodePosition {
160 self.position
161 }
162
163 #[inline]
165 pub fn inc_nibble(&mut self) {
166 let old_position = self.position;
167 self.position.increment();
168 self.update_full_key(old_position);
169 }
170
171 #[inline]
173 pub fn set_nibble(&mut self, nibble: u8) {
174 let old_position = self.position;
175 self.position = SubNodePosition::Child(nibble);
176 self.update_full_key(old_position);
177 }
178}
179
180#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
182pub enum SubNodePosition {
183 ParentBranch,
185 Child(u8),
187}
188
189impl SubNodePosition {
190 pub const fn is_parent(&self) -> bool {
192 matches!(self, Self::ParentBranch)
193 }
194
195 pub const fn is_child(&self) -> bool {
197 matches!(self, Self::Child(_))
198 }
199
200 pub const fn as_child(&self) -> Option<u8> {
202 match self {
203 Self::Child(nibble) => Some(*nibble),
204 _ => None,
205 }
206 }
207
208 pub const fn is_last_child(&self) -> bool {
211 match self {
212 Self::ParentBranch => false,
213 Self::Child(nibble) => *nibble >= 0xf,
214 }
215 }
216
217 const fn increment(&mut self) {
218 match self {
219 Self::ParentBranch => *self = Self::Child(0),
220 Self::Child(nibble) => *nibble += 1,
221 }
222 }
223}
224
225#[cfg(test)]
226mod tests {
227 use super::*;
228
229 #[test]
230 fn subnode_position_ord() {
231 assert!([
232 SubNodePosition::ParentBranch,
233 SubNodePosition::Child(0),
234 SubNodePosition::Child(1),
235 SubNodePosition::Child(2),
236 SubNodePosition::Child(3),
237 SubNodePosition::Child(4),
238 SubNodePosition::Child(5),
239 SubNodePosition::Child(6),
240 SubNodePosition::Child(7),
241 SubNodePosition::Child(8),
242 SubNodePosition::Child(9),
243 SubNodePosition::Child(10),
244 SubNodePosition::Child(11),
245 SubNodePosition::Child(12),
246 SubNodePosition::Child(13),
247 SubNodePosition::Child(14),
248 SubNodePosition::Child(15),
249 ]
250 .is_sorted());
251 }
252
253 #[test]
254 fn subnode_position_is_last_child() {
255 assert!([
256 SubNodePosition::ParentBranch,
257 SubNodePosition::Child(0),
258 SubNodePosition::Child(1),
259 SubNodePosition::Child(2),
260 SubNodePosition::Child(3),
261 SubNodePosition::Child(4),
262 SubNodePosition::Child(5),
263 SubNodePosition::Child(6),
264 SubNodePosition::Child(7),
265 SubNodePosition::Child(8),
266 SubNodePosition::Child(9),
267 SubNodePosition::Child(10),
268 SubNodePosition::Child(11),
269 SubNodePosition::Child(12),
270 SubNodePosition::Child(13),
271 SubNodePosition::Child(14),
272 ]
273 .iter()
274 .all(|position| !position.is_last_child()));
275 assert!(SubNodePosition::Child(15).is_last_child());
276 assert!(SubNodePosition::Child(16).is_last_child());
277 }
278}