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}