1use crate::error::{CapError, CapResult};
8use crate::DEFAULT_CAP_TABLE_CAPACITY;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub struct DerivationNode {
16 pub is_valid: bool,
18 pub depth: u8,
20 pub epoch: u64,
22 pub first_child: u32,
24 pub next_sibling: u32,
26 pub parent_index: u32,
29}
30
31impl DerivationNode {
32 #[inline]
34 #[must_use]
35 pub const fn empty() -> Self {
36 Self {
37 is_valid: false,
38 depth: 0,
39 epoch: 0,
40 first_child: u32::MAX,
41 next_sibling: u32::MAX,
42 parent_index: u32::MAX,
43 }
44 }
45
46 #[inline]
48 #[must_use]
49 pub const fn new_root(epoch: u64) -> Self {
50 Self {
51 is_valid: true,
52 depth: 0,
53 epoch,
54 first_child: u32::MAX,
55 next_sibling: u32::MAX,
56 parent_index: u32::MAX,
57 }
58 }
59
60 #[inline]
62 #[must_use]
63 pub const fn new_child(depth: u8, epoch: u64) -> Self {
64 Self {
65 is_valid: true,
66 depth,
67 epoch,
68 first_child: u32::MAX,
69 next_sibling: u32::MAX,
70 parent_index: u32::MAX,
71 }
72 }
73
74 #[inline]
76 #[must_use]
77 pub const fn has_children(&self) -> bool {
78 self.first_child != u32::MAX
79 }
80}
81
82impl Default for DerivationNode {
83 fn default() -> Self {
84 Self::empty()
85 }
86}
87
88pub struct DerivationTree<const N: usize = DEFAULT_CAP_TABLE_CAPACITY> {
92 nodes: [DerivationNode; N],
94 count: usize,
96}
97
98impl<const N: usize> DerivationTree<N> {
99 #[inline]
101 #[must_use]
102 pub const fn new() -> Self {
103 Self {
104 nodes: [DerivationNode::empty(); N],
105 count: 0,
106 }
107 }
108
109 #[inline]
111 #[must_use]
112 pub const fn len(&self) -> usize {
113 self.count
114 }
115
116 #[inline]
118 #[must_use]
119 pub const fn is_empty(&self) -> bool {
120 self.count == 0
121 }
122
123 pub fn add_root(&mut self, index: u32, epoch: u64) -> CapResult<()> {
129 let idx = index as usize;
130 if idx >= N {
131 return Err(CapError::TreeFull);
132 }
133 self.nodes[idx] = DerivationNode::new_root(epoch);
134 self.count += 1;
135 Ok(())
136 }
137
138 pub fn add_child(
145 &mut self,
146 parent_index: u32,
147 child_index: u32,
148 depth: u8,
149 epoch: u64,
150 ) -> CapResult<()> {
151 let pidx = parent_index as usize;
152 let cidx = child_index as usize;
153
154 if pidx >= N || cidx >= N {
155 return Err(CapError::TreeFull);
156 }
157 if !self.nodes[pidx].is_valid {
158 return Err(CapError::Revoked);
159 }
160
161 let mut child = DerivationNode::new_child(depth, epoch);
163 child.next_sibling = self.nodes[pidx].first_child;
164 child.parent_index = parent_index;
165 self.nodes[pidx].first_child = child_index;
166 self.nodes[cidx] = child;
167 self.count += 1;
168
169 Ok(())
170 }
171
172 pub fn revoke(&mut self, index: u32) -> CapResult<usize> {
179 let idx = index as usize;
180 if idx >= N {
181 return Err(CapError::InvalidHandle);
182 }
183 if !self.nodes[idx].is_valid {
184 return Err(CapError::Revoked);
185 }
186 Ok(self.revoke_subtree(index))
187 }
188
189 pub fn depth(&self, index: u32) -> CapResult<u8> {
195 let idx = index as usize;
196 if idx >= N || !self.nodes[idx].is_valid {
197 return Err(CapError::InvalidHandle);
198 }
199 Ok(self.nodes[idx].depth)
200 }
201
202 #[must_use]
204 pub fn is_valid(&self, index: u32) -> bool {
205 let idx = index as usize;
206 idx < N && self.nodes[idx].is_valid
207 }
208
209 #[must_use]
211 pub fn get(&self, index: u32) -> Option<&DerivationNode> {
212 let idx = index as usize;
213 if idx < N && self.nodes[idx].is_valid {
214 Some(&self.nodes[idx])
215 } else {
216 None
217 }
218 }
219
220 #[must_use]
227 pub fn collect_subtree(&self, index: u32) -> [u32; N] {
228 let mut result = [u32::MAX; N];
229 let mut result_count = 0;
230 let mut stack = [u32::MAX; N];
231 let mut stack_top = 0;
232
233 let idx = index as usize;
235 if idx < N && self.nodes[idx].is_valid {
236 stack[stack_top] = index;
237 stack_top += 1;
238 }
239
240 while stack_top > 0 {
241 stack_top -= 1;
242 let current = stack[stack_top];
243 let cidx = current as usize;
244 if cidx >= N || !self.nodes[cidx].is_valid {
245 continue;
246 }
247
248 if result_count < N {
249 result[result_count] = current;
250 result_count += 1;
251 }
252
253 let mut child = self.nodes[cidx].first_child;
255 while child != u32::MAX {
256 let child_idx = child as usize;
257 if child_idx >= N {
258 break;
259 }
260 if self.nodes[child_idx].is_valid && stack_top < N {
261 stack[stack_top] = child;
262 stack_top += 1;
263 }
264 child = self.nodes[child_idx].next_sibling;
265 }
266 }
267
268 result
269 }
270
271 #[must_use]
279 pub fn find_parent(&self, child_index: u32) -> Option<u32> {
280 let cidx = child_index as usize;
281 if cidx >= N || !self.nodes[cidx].is_valid {
282 return None;
283 }
284 if self.nodes[cidx].depth == 0 {
286 return None;
287 }
288 let pidx = self.nodes[cidx].parent_index;
290 if pidx != u32::MAX {
291 let pi = pidx as usize;
292 if pi < N && self.nodes[pi].is_valid {
293 return Some(pidx);
294 }
295 }
296 for i in 0..N {
299 if !self.nodes[i].is_valid {
300 continue;
301 }
302 let mut cursor = self.nodes[i].first_child;
303 while cursor != u32::MAX {
304 if cursor == child_index {
305 return Some(u32::try_from(i).unwrap_or(u32::MAX));
306 }
307 let c = cursor as usize;
308 if c >= N {
309 break;
310 }
311 cursor = self.nodes[c].next_sibling;
312 }
313 }
314 None
315 }
316
317 fn revoke_subtree(&mut self, index: u32) -> usize {
324 let mut stack = [u32::MAX; N];
325 let mut stack_top: usize = 0;
326 let mut count: usize = 0;
327
328 let root_idx = index as usize;
330 if root_idx >= N || !self.nodes[root_idx].is_valid {
331 return 0;
332 }
333 stack[stack_top] = index;
334 stack_top += 1;
335
336 while stack_top > 0 {
337 stack_top -= 1;
338 let current = stack[stack_top];
339 let cidx = current as usize;
340
341 if cidx >= N || !self.nodes[cidx].is_valid {
342 continue;
343 }
344
345 self.nodes[cidx].is_valid = false;
347 self.count = self.count.saturating_sub(1);
348 count += 1;
349
350 let mut child = self.nodes[cidx].first_child;
352 while child != u32::MAX {
353 let child_idx = child as usize;
354 if child_idx >= N {
355 break;
356 }
357 if self.nodes[child_idx].is_valid && stack_top < N {
358 stack[stack_top] = child;
359 stack_top += 1;
360 }
361 child = self.nodes[child_idx].next_sibling;
363 }
364 }
365
366 count
367 }
368}
369
370impl<const N: usize> Default for DerivationTree<N> {
371 fn default() -> Self {
372 Self::new()
373 }
374}
375
376#[cfg(test)]
377mod tests {
378 use super::*;
379
380 #[test]
381 fn test_add_root() {
382 let mut tree = DerivationTree::<64>::new();
383 tree.add_root(0, 1).unwrap();
384 assert_eq!(tree.len(), 1);
385 assert!(tree.is_valid(0));
386 assert_eq!(tree.depth(0).unwrap(), 0);
387 }
388
389 #[test]
390 fn test_add_child() {
391 let mut tree = DerivationTree::<64>::new();
392 tree.add_root(0, 1).unwrap();
393 tree.add_child(0, 1, 1, 1).unwrap();
394 assert_eq!(tree.len(), 2);
395 assert!(tree.is_valid(1));
396 assert_eq!(tree.depth(1).unwrap(), 1);
397 assert!(tree.get(0).unwrap().has_children());
398 }
399
400 #[test]
401 fn test_revoke_subtree() {
402 let mut tree = DerivationTree::<64>::new();
403 tree.add_root(0, 1).unwrap();
404 tree.add_child(0, 1, 1, 1).unwrap();
405 tree.add_child(0, 2, 1, 1).unwrap();
406 tree.add_child(1, 3, 2, 1).unwrap();
407
408 let revoked = tree.revoke(0).unwrap();
409 assert_eq!(revoked, 4);
410 assert_eq!(tree.len(), 0);
411 }
412
413 #[test]
414 fn test_partial_revoke() {
415 let mut tree = DerivationTree::<64>::new();
416 tree.add_root(0, 1).unwrap();
417 tree.add_child(0, 1, 1, 1).unwrap();
418 tree.add_child(0, 2, 1, 1).unwrap();
419 tree.add_child(1, 3, 2, 1).unwrap();
420
421 let revoked = tree.revoke(1).unwrap();
422 assert_eq!(revoked, 2);
423 assert!(tree.is_valid(0));
424 assert!(!tree.is_valid(1));
425 assert!(tree.is_valid(2));
426 assert!(!tree.is_valid(3));
427 }
428
429 #[test]
430 fn test_add_child_to_revoked_parent() {
431 let mut tree = DerivationTree::<64>::new();
432 tree.add_root(0, 1).unwrap();
433 tree.revoke(0).unwrap();
434 assert_eq!(tree.add_child(0, 1, 1, 1), Err(CapError::Revoked));
435 }
436
437 #[test]
438 fn test_out_of_bounds() {
439 let mut tree = DerivationTree::<4>::new();
440 assert_eq!(tree.add_root(10, 1), Err(CapError::TreeFull));
441 }
442}