miniscript/iter/tree.rs
1// SPDX-License-Identifier: CC0-1.0
2
3//! Abstract Trees
4//!
5//! This module provides the [`TreeLike`] trait which represents a node in a
6//! tree, and several iterators over trees whose nodes implement this trait.
7//!
8
9use crate::prelude::*;
10
11/// Abstract node of a tree.
12///
13/// Tracks the arity (out-degree) of a node, which is the only thing that
14/// is needed for iteration purposes.
15pub enum Tree<T, NT> {
16 /// Combinator with no children.
17 Nullary,
18 /// Combinator with one child.
19 Unary(T),
20 /// Combinator with two children.
21 Binary(T, T),
22 /// Combinator with two children.
23 Ternary(T, T, T),
24 /// Combinator with more than two children.
25 Nary(NT),
26}
27
28/// A trait for any structure which has the shape of a Miniscript tree.
29///
30/// As a general rule, this should be implemented on references to nodes,
31/// rather than nodes themselves, because it provides algorithms that
32/// assume copying is cheap.
33///
34/// To implement this trait, you only need to implement the [`TreeLike::as_node`],
35/// [`TreeLike::nary_len`] and `[TreeLike::nary_index'] methods, which should
36/// be very mechanical. Everything else is provided.
37pub trait TreeLike: Clone + Sized {
38 /// An abstraction over the children of n-ary nodes. Typically when
39 /// implementing the trait for `&a T` this will be `&'a [T]`.
40 type NaryChildren: Clone;
41
42 /// Accessor for the length of a [`Self::NaryChildren`].
43 fn nary_len(tc: &Self::NaryChildren) -> usize;
44
45 /// Accessor for a specific child of a [`Self::NaryChildren`].
46 ///
47 /// # Panics
48 ///
49 /// May panic if asked for an element outside of the range
50 /// `0..Self::nary_len(&tc)`.
51 fn nary_index(tc: Self::NaryChildren, idx: usize) -> Self;
52
53 /// Interpret the node as an abstract node.
54 fn as_node(&self) -> Tree<Self, Self::NaryChildren>;
55
56 /// Accessor for the number of children this node has.
57 fn n_children(&self) -> usize {
58 match self.as_node() {
59 Tree::Nullary => 0,
60 Tree::Unary(..) => 1,
61 Tree::Binary(..) => 2,
62 Tree::Ternary(..) => 3,
63 Tree::Nary(ref children) => Self::nary_len(children),
64 }
65 }
66
67 /// Accessor for the nth child of the node, if a child with that index exists.
68 fn nth_child(&self, n: usize) -> Option<Self> {
69 match (n, self.as_node()) {
70 (_, Tree::Nullary) => None,
71 (0, Tree::Unary(sub)) => Some(sub),
72 (_, Tree::Unary(..)) => None,
73 (0, Tree::Binary(sub, _)) => Some(sub),
74 (1, Tree::Binary(_, sub)) => Some(sub),
75 (_, Tree::Binary(..)) => None,
76 (0, Tree::Ternary(sub, _, _)) => Some(sub),
77 (1, Tree::Ternary(_, sub, _)) => Some(sub),
78 (2, Tree::Ternary(_, _, sub)) => Some(sub),
79 (_, Tree::Ternary(..)) => None,
80 (n, Tree::Nary(children)) if n < Self::nary_len(&children) => {
81 Some(Self::nary_index(children, n))
82 }
83 (_, Tree::Nary(..)) => None,
84 }
85 }
86
87 /// Obtains an iterator of all the nodes rooted at the node, in pre-order.
88 fn pre_order_iter(self) -> PreOrderIter<Self> { PreOrderIter { stack: vec![self] } }
89
90 /// Obtains a verbose iterator of all the nodes rooted at the DAG, in pre-order.
91 ///
92 /// See the documentation of [`VerbosePreOrderIter`] for more information about what
93 /// this does. Essentially, if you find yourself using [`Self::pre_order_iter`] and
94 /// then adding a stack to manually track which items and their children have been
95 /// yielded, you may be better off using this iterator instead.
96 fn verbose_pre_order_iter(self) -> VerbosePreOrderIter<Self> {
97 VerbosePreOrderIter { stack: vec![PreOrderIterItem::initial(self, None)], index: 0 }
98 }
99
100 /// Obtains an iterator of all the nodes rooted at the DAG, in post order.
101 ///
102 /// Each node is only yielded once, at the leftmost position that it
103 /// appears in the DAG.
104 fn post_order_iter(self) -> PostOrderIter<Self> {
105 PostOrderIter { index: 0, stack: vec![IterStackItem::unprocessed(self, None)] }
106 }
107
108 /// Obtains an iterator of all the nodes rooted at the DAG, in right-to-left post order.
109 ///
110 /// This ordering is useful for "translation" algorithms which iterate over a
111 /// structure, pushing translated nodes and popping children.
112 fn rtl_post_order_iter(self) -> RtlPostOrderIter<Self> {
113 RtlPostOrderIter { inner: Rtl(self).post_order_iter() }
114 }
115}
116
117/// Element stored internally on the stack of a [`PostOrderIter`].
118///
119/// This is **not** the type that is yielded by the [`PostOrderIter`];
120/// in fact, this type is not even exported.
121#[derive(Clone, Debug)]
122struct IterStackItem<T> {
123 /// The element on the stack
124 elem: T,
125 /// Whether we have dealt with this item (and pushed its children,
126 /// if any) yet.
127 processed: bool,
128 /// If the item has been processed, the index of its children.
129 child_indices: Vec<usize>,
130 /// Whether the element is a left- or right-child of its parent.
131 parent_stack_idx: Option<usize>,
132}
133
134impl<T: TreeLike> IterStackItem<T> {
135 /// Constructor for a new stack item with a given element and relationship
136 /// to its parent.
137 fn unprocessed(elem: T, parent_stack_idx: Option<usize>) -> Self {
138 IterStackItem {
139 processed: false,
140 child_indices: Vec::with_capacity(elem.n_children()),
141 parent_stack_idx,
142 elem,
143 }
144 }
145}
146
147/// Iterates over a DAG in _post order_.
148///
149/// That means nodes are yielded in the order (left child, right child, parent).
150#[derive(Clone, Debug)]
151pub struct PostOrderIter<T> {
152 /// The index of the next item to be yielded
153 index: usize,
154 /// A stack of elements to be yielded; each element is a node, then its left
155 /// and right children (if they exist and if they have been yielded already)
156 stack: Vec<IterStackItem<T>>,
157}
158
159/// A set of data yielded by a `PostOrderIter`.
160pub struct PostOrderIterItem<T> {
161 /// The actual node data
162 pub node: T,
163 /// The index of this node (equivalent to if you'd called `.enumerate()` on
164 /// the iterator)
165 pub index: usize,
166 /// The indices of this node's children.
167 pub child_indices: Vec<usize>,
168}
169
170impl<T: TreeLike> Iterator for PostOrderIter<T> {
171 type Item = PostOrderIterItem<T>;
172
173 fn next(&mut self) -> Option<Self::Item> {
174 let mut current = self.stack.pop()?;
175
176 if !current.processed {
177 current.processed = true;
178
179 // When we first encounter an item, it is completely unknown; it is
180 // nominally the next item to be yielded, but it might have children,
181 // and if so, they come first
182 let current_stack_idx = self.stack.len();
183 let n_children = current.elem.n_children();
184 self.stack.push(current);
185 for idx in (0..n_children).rev() {
186 self.stack.push(IterStackItem::unprocessed(
187 self.stack[current_stack_idx].elem.nth_child(idx).unwrap(),
188 Some(current_stack_idx),
189 ));
190 }
191 self.next()
192 } else {
193 // The second time we encounter an item, we have dealt with its children,
194 // updated the child indices for this item, and are now ready to yield it
195 // rather than putting it back in the stack.
196 //
197 // Before yielding though, we must the item's parent's child indices with
198 // this item's index.
199 if let Some(idx) = current.parent_stack_idx {
200 self.stack[idx].child_indices.push(self.index);
201 }
202
203 self.index += 1;
204 Some(PostOrderIterItem {
205 node: current.elem,
206 index: self.index - 1,
207 child_indices: current.child_indices,
208 })
209 }
210 }
211}
212
213/// Adaptor structure to allow iterating in right-to-left order.
214#[derive(Clone, Debug)]
215struct Rtl<T>(pub T);
216
217impl<T: TreeLike> TreeLike for Rtl<T> {
218 type NaryChildren = T::NaryChildren;
219
220 fn nary_len(tc: &Self::NaryChildren) -> usize { T::nary_len(tc) }
221 fn nary_index(tc: Self::NaryChildren, idx: usize) -> Self {
222 let rtl_idx = T::nary_len(&tc) - idx - 1;
223 Rtl(T::nary_index(tc, rtl_idx))
224 }
225
226 fn as_node(&self) -> Tree<Self, Self::NaryChildren> {
227 match self.0.as_node() {
228 Tree::Nullary => Tree::Nullary,
229 Tree::Unary(a) => Tree::Unary(Rtl(a)),
230 Tree::Binary(a, b) => Tree::Binary(Rtl(b), Rtl(a)),
231 Tree::Ternary(a, b, c) => Tree::Ternary(Rtl(c), Rtl(b), Rtl(a)),
232 Tree::Nary(data) => Tree::Nary(data),
233 }
234 }
235}
236
237/// Iterates over a DAG in _right-to-left post order_.
238///
239/// That means nodes are yielded in the order (right child, left child, parent).
240#[derive(Clone, Debug)]
241pub struct RtlPostOrderIter<T> {
242 inner: PostOrderIter<Rtl<T>>,
243}
244
245impl<T: TreeLike> Iterator for RtlPostOrderIter<T> {
246 type Item = PostOrderIterItem<T>;
247
248 fn next(&mut self) -> Option<Self::Item> {
249 self.inner.next().map(|mut item| {
250 item.child_indices.reverse();
251 PostOrderIterItem {
252 child_indices: item.child_indices,
253 index: item.index,
254 node: item.node.0,
255 }
256 })
257 }
258}
259
260/// Iterates over a [`TreeLike`] in _pre order_.
261///
262/// Unlike the post-order iterator, this one does not keep track of indices
263/// (this would be impractical since when we yield a node we have not yet
264/// yielded its children, so we cannot know their indices). If you do need
265/// the indices for some reason, the best strategy may be to run the
266/// post-order iterator, collect into a vector, then iterate through that
267/// backward.
268#[derive(Clone, Debug)]
269pub struct PreOrderIter<T> {
270 /// A stack of elements to be yielded. As items are yielded, their right
271 /// children are put onto the stack followed by their left, so that the
272 /// appropriate one will be yielded on the next iteration.
273 stack: Vec<T>,
274}
275
276impl<T: TreeLike> Iterator for PreOrderIter<T> {
277 type Item = T;
278
279 fn next(&mut self) -> Option<Self::Item> {
280 // This algorithm is _significantly_ simpler than the post-order one,
281 // mainly because we don't care about child indices.
282 let top = self.stack.pop()?;
283 match top.as_node() {
284 Tree::Nullary => {}
285 Tree::Unary(next) => self.stack.push(next),
286 Tree::Binary(left, right) => {
287 self.stack.push(right);
288 self.stack.push(left);
289 }
290 Tree::Ternary(a, b, c) => {
291 self.stack.push(c);
292 self.stack.push(b);
293 self.stack.push(a);
294 }
295 Tree::Nary(children) => {
296 for i in (0..T::nary_len(&children)).rev() {
297 self.stack.push(T::nary_index(children.clone(), i));
298 }
299 }
300 }
301 Some(top)
302 }
303}
304
305/// Iterates over a [`TreeLike`] in "verbose pre order", yielding extra state changes.
306///
307/// This yields nodes followed by their children, followed by the node *again*
308/// after each child. This means that each node will be yielded a total of
309/// (n+1) times, where n is its number of children.
310///
311/// The different times that a node is yielded can be distinguished by looking
312/// at the [`PreOrderIterItem::n_children_yielded`] (which, in particular,
313/// will be 0 on the first yield) and [`PreOrderIterItem::is_complete`] (which
314/// will be true on the last yield) fields of the yielded item.
315#[derive(Clone, Debug)]
316pub struct VerbosePreOrderIter<T> {
317 /// A stack of elements to be yielded. As items are yielded, their right
318 /// children are put onto the stack followed by their left, so that the
319 /// appropriate one will be yielded on the next iteration.
320 stack: Vec<PreOrderIterItem<T>>,
321 /// The index of the next item to be yielded.
322 ///
323 /// Note that unlike the [`PostOrderIter`], this value is not monotonic
324 /// and not equivalent to just using `enumerate` on the iterator, because
325 /// elements may be yielded multiple times.
326 index: usize,
327}
328
329impl<T: TreeLike + Clone> Iterator for VerbosePreOrderIter<T> {
330 type Item = PreOrderIterItem<T>;
331
332 fn next(&mut self) -> Option<Self::Item> {
333 // This algorithm is still simpler than the post-order one, because while
334 // we care about node indices, we don't care about their childrens' indices.
335 let mut top = self.stack.pop()?;
336
337 // If this is the first time we're be yielding this element, set its index.
338 if top.n_children_yielded == 0 {
339 top.index = self.index;
340 self.index += 1;
341 }
342 // Push the next child.
343 let n_children = top.node.n_children();
344 if top.n_children_yielded < n_children {
345 self.stack.push(top.clone().increment(n_children));
346 let child = top.node.nth_child(top.n_children_yielded).unwrap();
347 self.stack
348 .push(PreOrderIterItem::initial(child, Some(top.node.clone())));
349 }
350
351 // Then yield the element.
352 Some(top)
353 }
354}
355
356/// A set of data yielded by a [`VerbosePreOrderIter`].
357#[derive(Clone, Debug)]
358pub struct PreOrderIterItem<T> {
359 /// The actual element being yielded.
360 pub node: T,
361 /// The parent of this node. `None` for the initial node, but will be
362 /// populated for all other nodes.
363 pub parent: Option<T>,
364 /// The index when the element was first yielded.
365 pub index: usize,
366 /// How many of this item's children have been yielded.
367 ///
368 /// This can also be interpreted as a count of how many times this
369 /// item has been yielded before.
370 pub n_children_yielded: usize,
371 /// Whether this item is done (will not be yielded again).
372 pub is_complete: bool,
373}
374
375impl<T: TreeLike + Clone> PreOrderIterItem<T> {
376 /// Creates a `PreOrderIterItem` which yields a given element for the first time.
377 ///
378 /// Marks the index as 0. The index must be manually set before yielding.
379 fn initial(node: T, parent: Option<T>) -> Self {
380 PreOrderIterItem {
381 is_complete: node.n_children() == 0,
382 node,
383 parent,
384 index: 0,
385 n_children_yielded: 0,
386 }
387 }
388
389 /// Creates a `PreOrderIterItem` which yields a given element again.
390 fn increment(self, n_children: usize) -> Self {
391 PreOrderIterItem {
392 node: self.node,
393 index: self.index,
394 parent: self.parent,
395 n_children_yielded: self.n_children_yielded + 1,
396 is_complete: self.n_children_yielded + 1 == n_children,
397 }
398 }
399}