Skip to content

Commit b9d7d6a

Browse files
committed
Miniscript iterators: applying PR review suggestions
1 parent 6edc698 commit b9d7d6a

File tree

1 file changed

+155
-78
lines changed

1 file changed

+155
-78
lines changed

src/miniscript/iter.rs

Lines changed: 155 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515
use super::decode::Terminal;
1616
use super::{Miniscript, MiniscriptKey, ScriptContext};
17-
use std::collections::VecDeque;
1817
use std::ops::Deref;
1918
use std::sync::Arc;
2019

@@ -51,30 +50,27 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
5150
/// Enumerates all child nodes of the current AST node (`self`) and returns a `Vec` referencing
5251
/// them.
5352
pub fn branches(&self) -> Vec<&Miniscript<Pk, Ctx>> {
54-
use Terminal::*;
55-
match &self.node {
56-
&PkK(_) | &PkH(_) | &Multi(_, _) => vec![],
57-
58-
&Alt(ref node)
59-
| &Swap(ref node)
60-
| &Check(ref node)
61-
| &DupIf(ref node)
62-
| &Verify(ref node)
63-
| &NonZero(ref node)
64-
| &ZeroNotEqual(ref node) => vec![node.deref()],
65-
66-
&AndV(ref node1, ref node2)
67-
| &AndB(ref node1, ref node2)
68-
| &OrB(ref node1, ref node2)
69-
| &OrD(ref node1, ref node2)
70-
| &OrC(ref node1, ref node2)
71-
| &OrI(ref node1, ref node2) => vec![node1.deref(), node2.deref()],
72-
73-
&AndOr(ref node1, ref node2, ref node3) => {
74-
vec![node1.deref(), node2.deref(), node3.deref()]
75-
}
53+
match self.node {
54+
Terminal::PkK(_) | Terminal::PkH(_) | Terminal::Multi(_, _) => vec![],
55+
56+
Terminal::Alt(ref node)
57+
| Terminal::Swap(ref node)
58+
| Terminal::Check(ref node)
59+
| Terminal::DupIf(ref node)
60+
| Terminal::Verify(ref node)
61+
| Terminal::NonZero(ref node)
62+
| Terminal::ZeroNotEqual(ref node) => vec![node],
63+
64+
Terminal::AndV(ref node1, ref node2)
65+
| Terminal::AndB(ref node1, ref node2)
66+
| Terminal::OrB(ref node1, ref node2)
67+
| Terminal::OrD(ref node1, ref node2)
68+
| Terminal::OrC(ref node1, ref node2)
69+
| Terminal::OrI(ref node1, ref node2) => vec![node1, node2],
70+
71+
Terminal::AndOr(ref node1, ref node2, ref node3) => vec![node1, node2, node3],
7672

77-
&Thresh(_, ref node_vec) => node_vec.iter().map(Arc::deref).collect(),
73+
Terminal::Thresh(_, ref node_vec) => node_vec.iter().map(Arc::deref).collect(),
7874

7975
_ => vec![],
8076
}
@@ -87,9 +83,9 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
8783
/// To obtain a list of all public keys within AST use [`iter_pk()`] function, for example
8884
/// `miniscript.iter_pubkeys().collect()`.
8985
pub fn get_leaf_pk(&self) -> Vec<Pk> {
90-
match self.node.clone() {
91-
Terminal::PkK(key) => vec![key],
92-
Terminal::Multi(_, keys) => keys,
86+
match self.node {
87+
Terminal::PkK(ref key) => vec![key.clone()],
88+
Terminal::Multi(_, ref keys) => keys.clone(),
9389
_ => vec![],
9490
}
9591
}
@@ -98,43 +94,93 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
9894
/// Otherwise returns an empty `Vec`.
9995
///
10096
/// For each public key the function computes hash; for each hash of the public key the function
101-
/// returns it's cloned copy.
97+
/// returns it cloned copy.
10298
///
10399
/// NB: The function analyzes only single miniscript item and not any of its descendants in AST.
104100
/// To obtain a list of all public key hashes within AST use [`iter_pkh()`] function,
105101
/// for example `miniscript.iter_pubkey_hashes().collect()`.
106102
pub fn get_leaf_pkh(&self) -> Vec<Pk::Hash> {
107-
match self.node.clone() {
108-
Terminal::PkH(hash) => vec![hash],
109-
Terminal::PkK(key) => vec![key.to_pubkeyhash()],
110-
Terminal::Multi(_, keys) => keys.iter().map(Pk::to_pubkeyhash).collect(),
103+
match self.node {
104+
Terminal::PkH(ref hash) => vec![hash.clone()],
105+
Terminal::PkK(ref key) => vec![key.to_pubkeyhash()],
106+
Terminal::Multi(_, ref keys) => keys.iter().map(Pk::to_pubkeyhash).collect(),
111107
_ => vec![],
112108
}
113109
}
114110

115-
/// Returns `Vec` of [PubkeyOrHash] entries, representing either public keys or public key
111+
/// Returns `Vec` of [PkPkh] entries, representing either public keys or public key
116112
/// hashes, depending on the data from the current miniscript item. If there is no public
117113
/// keys or hashes, the function returns an empty `Vec`.
118114
///
119115
/// NB: The function analyzes only single miniscript item and not any of its descendants in AST.
120116
/// To obtain a list of all public keys or hashes within AST use [`iter_pk_pkh()`]
121117
/// function, for example `miniscript.iter_pubkeys_and_hashes().collect()`.
122118
pub fn get_leaf_pk_pkh(&self) -> Vec<PkPkh<Pk>> {
123-
use self::PkPkh::*;
124-
match self.node.clone() {
125-
Terminal::PkH(hash) => vec![HashedPubkey(hash)],
126-
Terminal::PkK(key) => vec![PlainPubkey(key)],
127-
Terminal::Multi(_, keys) => keys.into_iter().map(PlainPubkey).collect(),
119+
match self.node {
120+
Terminal::PkH(ref hash) => vec![PkPkh::HashedPubkey(hash.clone())],
121+
Terminal::PkK(ref key) => vec![PkPkh::PlainPubkey(key.clone())],
122+
Terminal::Multi(_, ref keys) => keys
123+
.into_iter()
124+
.map(|key| PkPkh::PlainPubkey(key.clone()))
125+
.collect(),
128126
_ => vec![],
129127
}
130128
}
129+
130+
/// Returns `Option::Some` with cloned n'th public key from the current miniscript item,
131+
/// if any. Otherwise returns `Option::None`.
132+
///
133+
/// NB: The function analyzes only single miniscript item and not any of its descendants in AST.
134+
pub fn get_nth_pk(&self, n: usize) -> Option<Pk> {
135+
match (&self.node, n) {
136+
(&Terminal::PkK(ref key), 0) => Some(key.clone()),
137+
(&Terminal::Multi(_, ref keys), _) => keys.get(n).cloned(),
138+
_ => None,
139+
}
140+
}
141+
142+
/// Returns `Option::Some` with hash of n'th public key from the current miniscript item,
143+
/// if any. Otherwise returns `Option::None`.
144+
///
145+
/// For each public key the function computes hash; for each hash of the public key the function
146+
/// returns it cloned copy.
147+
///
148+
/// NB: The function analyzes only single miniscript item and not any of its descendants in AST.
149+
pub fn get_nth_pkh(&self, n: usize) -> Option<Pk::Hash> {
150+
match (&self.node, n) {
151+
(&Terminal::PkH(ref hash), 0) => Some(hash.clone()),
152+
(&Terminal::PkK(ref key), 0) => Some(key.to_pubkeyhash()),
153+
(&Terminal::Multi(_, ref keys), _) => keys.get(n).map(Pk::to_pubkeyhash),
154+
_ => None,
155+
}
156+
}
157+
158+
/// Returns `Option::Some` with hash of n'th public key or hash from the current miniscript item,
159+
/// if any. Otherwise returns `Option::None`.
160+
///
161+
/// NB: The function analyzes only single miniscript item and not any of its descendants in AST.
162+
pub fn get_nth_pk_pkh(&self, n: usize) -> Option<PkPkh<Pk>> {
163+
match (&self.node, n) {
164+
(&Terminal::PkH(ref hash), 0) => Some(PkPkh::HashedPubkey(hash.clone())),
165+
(&Terminal::PkK(ref key), 0) => Some(PkPkh::PlainPubkey(key.clone())),
166+
(&Terminal::Multi(_, ref keys), _) => {
167+
keys.get(n).map(|key| PkPkh::PlainPubkey(key.clone()))
168+
}
169+
_ => None,
170+
}
171+
}
131172
}
132173

133174
/// Iterator for traversing all [Miniscript] miniscript AST references starting from some specific
134175
/// node which constructs the iterator via [Miniscript::iter] method.
135176
pub struct Iter<'a, Pk: 'a + MiniscriptKey, Ctx: 'a + ScriptContext> {
136177
next: Option<&'a Miniscript<Pk, Ctx>>,
137-
path: Vec<(&'a Miniscript<Pk, Ctx>, usize)>,
178+
// Here we store vec of path elements, where each element is a tuple, consisting of:
179+
// 1. Miniscript node on the path
180+
// 2. It's branches stored as a vec (used for avoiding multiple vec allocations
181+
// during path traversal)
182+
// 3. Index of the current branch
183+
path: Vec<(&'a Miniscript<Pk, Ctx>, Vec<&'a Miniscript<Pk, Ctx>>, usize)>,
138184
}
139185

140186
impl<'a, Pk: MiniscriptKey, Ctx: ScriptContext> Iter<'a, Pk, Ctx> {
@@ -167,23 +213,24 @@ impl<'a, Pk: MiniscriptKey, Ctx: ScriptContext> Iterator for Iter<'a, Pk, Ctx> {
167213
/// +--> K
168214
/// ```
169215
/// `Iter::next()` will iterate over the nodes in the following order:
170-
/// `A > B > C > D > E > F > G > I > J > K`
216+
/// `A > B > C > D > E > F > G > H > I > J > K`
171217
///
172218
/// To enumerate the branches iterator uses [Miniscript::branches] function.
173219
fn next(&mut self) -> Option<Self::Item> {
174220
let mut curr = self.next;
175221
if let None = curr {
176-
while let Some((node, child)) = self.path.pop() {
177-
curr = node.branches().get(child).map(|x| *x);
222+
while let Some((node, branches, child)) = self.path.pop() {
223+
curr = branches.get(child).map(|x| *x);
178224
if curr.is_some() {
179-
self.path.push((node, child + 1));
225+
self.path.push((node, branches, child + 1));
180226
break;
181227
}
182228
}
183229
}
184230
if let Some(node) = curr {
185-
self.next = node.branches().first().map(|x| *x);
186-
self.path.push((node, 1));
231+
let branches = node.branches();
232+
self.next = branches.first().map(|x| *x);
233+
self.path.push((node, branches, 1));
187234
}
188235
curr
189236
}
@@ -193,14 +240,17 @@ impl<'a, Pk: MiniscriptKey, Ctx: ScriptContext> Iterator for Iter<'a, Pk, Ctx> {
193240
/// constructs the iterator via [Miniscript::iter_pk] method.
194241
pub struct PkIter<'a, Pk: 'a + MiniscriptKey, Ctx: 'a + ScriptContext> {
195242
node_iter: Iter<'a, Pk, Ctx>,
196-
keys_buff: VecDeque<Pk>,
243+
curr_node: Option<&'a Miniscript<Pk, Ctx>>,
244+
key_index: usize,
197245
}
198246

199247
impl<'a, Pk: MiniscriptKey, Ctx: ScriptContext> PkIter<'a, Pk, Ctx> {
200248
fn new(miniscript: &'a Miniscript<Pk, Ctx>) -> Self {
249+
let mut iter = Iter::new(miniscript);
201250
PkIter {
202-
node_iter: Iter::new(miniscript),
203-
keys_buff: VecDeque::new(),
251+
curr_node: iter.next(),
252+
node_iter: iter,
253+
key_index: 0,
204254
}
205255
}
206256
}
@@ -209,30 +259,40 @@ impl<'a, Pk: MiniscriptKey, Ctx: ScriptContext> Iterator for PkIter<'a, Pk, Ctx>
209259
type Item = Pk;
210260

211261
fn next(&mut self) -> Option<Self::Item> {
212-
if self.keys_buff.is_empty() {
213-
self.keys_buff = VecDeque::from(loop {
214-
let data = self.node_iter.next()?.get_leaf_pk();
215-
if !data.is_empty() {
216-
break data;
217-
}
218-
});
262+
loop {
263+
match self.curr_node {
264+
None => break None,
265+
Some(node) => match node.get_nth_pk(self.key_index) {
266+
None => {
267+
self.curr_node = self.node_iter.next();
268+
self.key_index = 0;
269+
continue;
270+
}
271+
Some(pk) => {
272+
self.key_index += 1;
273+
break Some(pk);
274+
}
275+
},
276+
}
219277
}
220-
self.keys_buff.pop_front()
221278
}
222279
}
223280

224281
/// Iterator for traversing all [MiniscriptKey] hashes in AST starting from some specific node which
225282
/// constructs the iterator via [Miniscript::iter_pkh] method.
226283
pub struct PkhIter<'a, Pk: 'a + MiniscriptKey, Ctx: 'a + ScriptContext> {
227284
node_iter: Iter<'a, Pk, Ctx>,
228-
keyhashes_buff: VecDeque<Pk::Hash>,
285+
curr_node: Option<&'a Miniscript<Pk, Ctx>>,
286+
key_index: usize,
229287
}
230288

231289
impl<'a, Pk: MiniscriptKey, Ctx: ScriptContext> PkhIter<'a, Pk, Ctx> {
232290
fn new(miniscript: &'a Miniscript<Pk, Ctx>) -> Self {
291+
let mut iter = Iter::new(miniscript);
233292
PkhIter {
234-
node_iter: Iter::new(miniscript),
235-
keyhashes_buff: VecDeque::new(),
293+
curr_node: iter.next(),
294+
node_iter: iter,
295+
key_index: 0,
236296
}
237297
}
238298
}
@@ -241,15 +301,22 @@ impl<'a, Pk: MiniscriptKey, Ctx: ScriptContext> Iterator for PkhIter<'a, Pk, Ctx
241301
type Item = Pk::Hash;
242302

243303
fn next(&mut self) -> Option<Self::Item> {
244-
if self.keyhashes_buff.is_empty() {
245-
self.keyhashes_buff = VecDeque::from(loop {
246-
let data = self.node_iter.next()?.get_leaf_pkh();
247-
if !data.is_empty() {
248-
break data;
249-
}
250-
});
304+
loop {
305+
match self.curr_node {
306+
None => break None,
307+
Some(node) => match node.get_nth_pkh(self.key_index) {
308+
None => {
309+
self.curr_node = self.node_iter.next();
310+
self.key_index = 0;
311+
continue;
312+
}
313+
Some(pk) => {
314+
self.key_index += 1;
315+
break Some(pk);
316+
}
317+
},
318+
}
251319
}
252-
self.keyhashes_buff.pop_front()
253320
}
254321
}
255322

@@ -267,14 +334,17 @@ pub enum PkPkh<Pk: MiniscriptKey> {
267334
/// [Miniscript::iter_keys_and_hashes] method.
268335
pub struct PkPkhIter<'a, Pk: 'a + MiniscriptKey, Ctx: 'a + ScriptContext> {
269336
node_iter: Iter<'a, Pk, Ctx>,
270-
buff: VecDeque<PkPkh<Pk>>,
337+
curr_node: Option<&'a Miniscript<Pk, Ctx>>,
338+
key_index: usize,
271339
}
272340

273341
impl<'a, Pk: MiniscriptKey, Ctx: ScriptContext> PkPkhIter<'a, Pk, Ctx> {
274342
fn new(miniscript: &'a Miniscript<Pk, Ctx>) -> Self {
343+
let mut iter = Iter::new(miniscript);
275344
PkPkhIter {
276-
node_iter: Iter::new(miniscript),
277-
buff: VecDeque::new(),
345+
curr_node: iter.next(),
346+
node_iter: iter,
347+
key_index: 0,
278348
}
279349
}
280350

@@ -307,15 +377,22 @@ impl<'a, Pk: MiniscriptKey, Ctx: ScriptContext> Iterator for PkPkhIter<'a, Pk, C
307377
type Item = PkPkh<Pk>;
308378

309379
fn next(&mut self) -> Option<Self::Item> {
310-
if self.buff.is_empty() {
311-
self.buff = VecDeque::from(loop {
312-
let data = self.node_iter.next()?.get_leaf_pk_pkh();
313-
if !data.is_empty() {
314-
break data;
315-
}
316-
});
380+
loop {
381+
match self.curr_node {
382+
None => break None,
383+
Some(node) => match node.get_nth_pk_pkh(self.key_index) {
384+
None => {
385+
self.curr_node = self.node_iter.next();
386+
self.key_index = 0;
387+
continue;
388+
}
389+
Some(pk) => {
390+
self.key_index += 1;
391+
break Some(pk);
392+
}
393+
},
394+
}
317395
}
318-
self.buff.pop_front()
319396
}
320397
}
321398

0 commit comments

Comments
 (0)