1use minicbor::{Decoder, data::Type, decode::Error};
21
22pub enum Arity {
24 Leaf,
25 Fixed(u64),
26 Indefinite,
28}
29
30impl From<Option<u64>> for Arity {
31 fn from(len: Option<u64>) -> Self {
33 match len {
34 Some(n) => Self::Fixed(n),
35 None => Self::Indefinite,
36 }
37 }
38}
39
40pub trait TreeDecode<'b, C>: Sized {
45 type Builder;
49
50 fn begin(d: &mut Decoder<'b>, ctx: &mut C) -> Result<(Self::Builder, Arity), Error>;
53
54 fn child(builder: &mut Self::Builder, child: Self) -> Result<(), Error>;
57
58 fn end(builder: Self::Builder, d: &mut Decoder<'b>, ctx: &mut C) -> Result<Self, Error>;
60}
61
62struct Frame<B> {
63 builder: B,
64 arity: Arity,
65}
66
67impl<B> Frame<B> {
68 fn begin<'b, C, T>(d: &mut Decoder<'b>, ctx: &mut C) -> Result<Self, Error>
69 where
70 T: TreeDecode<'b, C, Builder = B>,
71 {
72 let (builder, arity) = T::begin(d, ctx)?;
73 Ok(Self { builder, arity })
74 }
75
76 fn expects_child(&mut self, d: &mut Decoder<'_>) -> Result<bool, Error> {
77 match self.arity {
78 Arity::Leaf | Arity::Fixed(0) => Ok(false),
79 Arity::Fixed(_) => Ok(true),
80 Arity::Indefinite if d.datatype()? == Type::Break => {
81 d.skip()?;
82 self.arity = Arity::Leaf;
83 Ok(false)
84 }
85 Arity::Indefinite => Ok(true),
86 }
87 }
88}
89
90pub fn decode_tree<'b, C, T>(d: &mut Decoder<'b>, ctx: &mut C) -> Result<T, Error>
92where
93 T: TreeDecode<'b, C>,
94{
95 let mut parents: Vec<Frame<T::Builder>> = Vec::new();
96 let mut current = Frame::begin::<C, T>(d, ctx)?;
97 loop {
98 if current.expects_child(d)? {
99 parents.push(current);
100 current = Frame::begin::<C, T>(d, ctx)?;
101 continue;
102 }
103 let node = T::end(current.builder, d, ctx)?;
104 let Some(mut parent) = parents.pop() else {
105 return Ok(node);
106 };
107 T::child(&mut parent.builder, node)?;
108 if let Arity::Fixed(remaining) = &mut parent.arity {
109 *remaining -= 1;
110 }
111 current = parent;
112 }
113}
114
115pub trait TreeNode: Sized {
117 fn children(&self) -> &[Self];
118
119 fn children_mut(&mut self) -> Option<&mut Vec<Self>>;
121}
122
123pub fn map_tree<S, T>(
129 root: &S,
130 shallow: impl Fn(&S) -> T,
131 target_children: impl Fn(&mut T) -> Option<&mut Vec<T>>,
132) -> T
133where
134 S: TreeNode,
135{
136 let mut target_root = shallow(root);
137 let mut pending = vec![(root, &mut target_root)];
138 while let Some((source, target)) = pending.pop() {
139 let Some(children) = target_children(target) else {
140 continue;
141 };
142 let source_children = source.children();
143 *children = source_children.iter().map(&shallow).collect();
144 pending.extend(source_children.iter().zip(children.iter_mut()));
145 }
146 target_root
147}
148
149pub enum Visit<'a, S> {
151 Enter(&'a S),
153 Between(&'a S),
155 Exit(&'a S),
157}
158
159pub fn walk_tree<S, E>(
161 root: &S,
162 mut visit: impl FnMut(Visit<'_, S>) -> Result<(), E>,
163) -> Result<(), E>
164where
165 S: TreeNode,
166{
167 let mut stack = vec![Visit::Enter(root)];
168 while let Some(step) = stack.pop() {
169 if let Visit::Enter(node) = step {
170 visit(Visit::Enter(node))?;
171 stack.push(Visit::Exit(node));
172 for (i, child) in node.children().iter().enumerate().rev() {
173 stack.push(Visit::Enter(child));
174 if i > 0 {
175 stack.push(Visit::Between(node));
176 }
177 }
178 } else {
179 visit(step)?;
180 }
181 }
182 Ok(())
183}
184
185pub fn eq_tree<S>(left: &S, right: &S, same_node: impl Fn(&S, &S) -> bool) -> bool
188where
189 S: TreeNode,
190{
191 let mut pending = vec![(left, right)];
192 while let Some((left, right)) = pending.pop() {
193 if !same_node(left, right) || left.children().len() != right.children().len() {
194 return false;
195 }
196 pending.extend(left.children().iter().zip(right.children()));
197 }
198 true
199}
200
201pub fn drop_children<S: TreeNode>(node: &mut S) {
205 let Some(children) = node.children_mut() else {
206 return;
207 };
208 let mut pending = std::mem::take(children);
209 while let Some(mut child) = pending.pop() {
210 if let Some(children) = child.children_mut() {
211 pending.append(children);
212 }
213 }
214}
215
216#[cfg(test)]
217mod tests {
218 use super::*;
219
220 #[derive(Debug, PartialEq)]
221 enum Node {
222 Leaf(u64),
223 List(Vec<Node>),
224 }
225
226 impl TreeNode for Node {
227 fn children(&self) -> &[Self] {
228 match self {
229 Node::List(children) => children,
230 Node::Leaf(_) => &[],
231 }
232 }
233
234 fn children_mut(&mut self) -> Option<&mut Vec<Self>> {
235 match self {
236 Node::List(children) => Some(children),
237 Node::Leaf(_) => None,
238 }
239 }
240 }
241
242 impl Drop for Node {
243 fn drop(&mut self) {
244 drop_children(self);
245 }
246 }
247
248 impl<'b, C> TreeDecode<'b, C> for Node {
249 type Builder = Node;
250
251 fn begin(d: &mut Decoder<'b>, _: &mut C) -> Result<(Node, Arity), Error> {
252 match d.datatype()? {
253 Type::Array | Type::ArrayIndef => Ok((Node::List(vec![]), d.array()?.into())),
254 _ => Ok((Node::Leaf(d.u64()?), Arity::Leaf)),
255 }
256 }
257
258 fn child(builder: &mut Node, child: Node) -> Result<(), Error> {
259 let Node::List(children) = builder else {
260 unreachable!()
261 };
262 children.push(child);
263 Ok(())
264 }
265
266 fn end(builder: Node, _: &mut Decoder<'b>, _: &mut C) -> Result<Node, Error> {
267 Ok(builder)
268 }
269 }
270
271 fn decode(bytes: &[u8]) -> Result<Node, Error> {
272 let mut d = Decoder::new(bytes);
273 let node = decode_tree(&mut d, &mut ())?;
274 assert_eq!(d.position(), bytes.len());
275 Ok(node)
276 }
277
278 #[test]
279 fn decodes_mixed_definite_and_indefinite_lists() {
280 let node = decode(&[0x84, 0x01, 0x80, 0x82, 0x02, 0x81, 0x03, 0x9f, 0xff]).unwrap();
282 let expected = Node::List(vec![
283 Node::Leaf(1),
284 Node::List(vec![]),
285 Node::List(vec![Node::Leaf(2), Node::List(vec![Node::Leaf(3)])]),
286 Node::List(vec![]),
287 ]);
288 assert_eq!(node, expected);
289 }
290
291 #[test]
292 fn rejects_truncated_input() {
293 assert!(decode(&[0x82, 0x01]).is_err());
294 assert!(decode(&[0x9f, 0x01]).is_err());
295 assert!(decode(&[0x81]).is_err());
296 }
297
298 #[test]
299 fn decodes_deep_nesting_on_a_small_stack() {
300 std::thread::Builder::new()
301 .stack_size(64 * 1024)
302 .spawn(|| {
303 let depth = 100_000;
304 let mut bytes = Vec::new();
305 for i in 0..depth {
306 bytes.push(if i % 2 == 0 { 0x81 } else { 0x9f });
307 }
308 bytes.push(0x00);
309 bytes.extend((0..depth).filter(|i| i % 2 == 1).map(|_| 0xff));
310 let mut cursor = &decode(&bytes).unwrap();
311 let mut seen = 0;
312 while let Node::List(children) = cursor {
313 assert_eq!(children.len(), 1);
314 cursor = &children[0];
315 seen += 1;
316 }
317 assert_eq!(seen, depth);
318 bytes.pop();
319 assert!(decode(&bytes).is_err());
320 })
321 .unwrap()
322 .join()
323 .unwrap();
324 }
325
326 fn mixed() -> Node {
327 Node::List(vec![
328 Node::Leaf(1),
329 Node::List(vec![]),
330 Node::List(vec![Node::Leaf(2), Node::List(vec![Node::Leaf(3)])]),
331 Node::List(vec![]),
332 ])
333 }
334
335 fn chain(depth: usize) -> Node {
336 let mut node = Node::Leaf(0);
337 for _ in 0..depth {
338 node = Node::List(vec![node]);
339 }
340 node
341 }
342
343 fn render(node: &Node) -> String {
344 let mut out = String::new();
345 walk_tree::<_, std::fmt::Error>(node, |visit| {
346 match visit {
347 Visit::Enter(Node::Leaf(n)) => out.push_str(&n.to_string()),
348 Visit::Enter(Node::List(_)) => out.push('['),
349 Visit::Between(_) => out.push(','),
350 Visit::Exit(Node::List(_)) => out.push(']'),
351 Visit::Exit(Node::Leaf(_)) => {}
352 }
353 Ok(())
354 })
355 .unwrap();
356 out
357 }
358
359 #[test]
360 fn walks_mixed_shapes_in_order() {
361 assert_eq!(render(&mixed()), "[1,[],[2,[3]],[]]");
362 assert_eq!(render(&Node::Leaf(7)), "7");
363 assert_eq!(render(&Node::List(vec![])), "[]");
364 }
365
366 #[test]
367 fn walk_propagates_errors() {
368 let result = walk_tree(&mixed(), |visit| match visit {
369 Visit::Enter(Node::Leaf(3)) => Err("three"),
370 _ => Ok(()),
371 });
372 assert_eq!(result, Err("three"));
373 }
374
375 #[test]
376 fn maps_mixed_shapes_positionally() {
377 #[derive(Debug, PartialEq)]
379 enum Target {
380 Leaf(u64),
381 List(Vec<Target>),
382 }
383 let mapped = map_tree(
384 &mixed(),
385 |node| match node {
386 Node::Leaf(n) => Target::Leaf(n * 2),
387 Node::List(_) => Target::List(vec![]),
388 },
389 |target| match target {
390 Target::List(children) => Some(children),
391 Target::Leaf(_) => None,
392 },
393 );
394 let expected = Target::List(vec![
395 Target::Leaf(2),
396 Target::List(vec![]),
397 Target::List(vec![Target::Leaf(4), Target::List(vec![Target::Leaf(6)])]),
398 Target::List(vec![]),
399 ]);
400 assert_eq!(mapped, expected);
401 }
402
403 #[test]
404 fn compares_structure_and_node_data() {
405 let same = |a: &Node, b: &Node| match (a, b) {
406 (Node::Leaf(a), Node::Leaf(b)) => a == b,
407 (Node::List(_), Node::List(_)) => true,
408 _ => false,
409 };
410 assert!(eq_tree(&mixed(), &mixed(), same));
411 assert!(!eq_tree(&mixed(), &Node::List(vec![]), same));
412 assert!(!eq_tree(&chain(3), &chain(4), same));
413 assert!(!eq_tree(&Node::Leaf(1), &Node::Leaf(2), same));
414 }
415
416 #[test]
417 fn traverses_deep_nesting_on_a_small_stack() {
418 std::thread::Builder::new()
419 .stack_size(64 * 1024)
420 .spawn(|| {
421 let depth = 100_000;
422 let node = chain(depth);
423 let text = render(&node);
424 assert_eq!(text, format!("{}0{}", "[".repeat(depth), "]".repeat(depth)));
425
426 let copy = map_tree(
427 &node,
428 |node| match node {
429 Node::Leaf(n) => Node::Leaf(*n),
430 Node::List(_) => Node::List(vec![]),
431 },
432 Node::children_mut,
433 );
434 assert!(eq_tree(&node, ©, |a, b| matches!(
435 (a, b),
436 (Node::Leaf(_), Node::Leaf(_)) | (Node::List(_), Node::List(_))
437 )));
438 drop(copy);
439 drop(node);
440 })
441 .unwrap()
442 .join()
443 .unwrap();
444 }
445}