Skip to main content

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}