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