14
14
15
15
use super :: decode:: Terminal ;
16
16
use super :: { Miniscript , MiniscriptKey , ScriptContext } ;
17
- use std:: collections:: VecDeque ;
18
17
use std:: ops:: Deref ;
19
18
use std:: sync:: Arc ;
20
19
@@ -51,30 +50,27 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
51
50
/// Enumerates all child nodes of the current AST node (`self`) and returns a `Vec` referencing
52
51
/// them.
53
52
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] ,
76
72
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 ( ) ,
78
74
79
75
_ => vec ! [ ] ,
80
76
}
@@ -87,9 +83,9 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
87
83
/// To obtain a list of all public keys within AST use [`iter_pk()`] function, for example
88
84
/// `miniscript.iter_pubkeys().collect()`.
89
85
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 ( ) ,
93
89
_ => vec ! [ ] ,
94
90
}
95
91
}
@@ -98,43 +94,93 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
98
94
/// Otherwise returns an empty `Vec`.
99
95
///
100
96
/// 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.
102
98
///
103
99
/// NB: The function analyzes only single miniscript item and not any of its descendants in AST.
104
100
/// To obtain a list of all public key hashes within AST use [`iter_pkh()`] function,
105
101
/// for example `miniscript.iter_pubkey_hashes().collect()`.
106
102
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 ( ) ,
111
107
_ => vec ! [ ] ,
112
108
}
113
109
}
114
110
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
116
112
/// hashes, depending on the data from the current miniscript item. If there is no public
117
113
/// keys or hashes, the function returns an empty `Vec`.
118
114
///
119
115
/// NB: The function analyzes only single miniscript item and not any of its descendants in AST.
120
116
/// To obtain a list of all public keys or hashes within AST use [`iter_pk_pkh()`]
121
117
/// function, for example `miniscript.iter_pubkeys_and_hashes().collect()`.
122
118
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 ( ) ,
128
126
_ => vec ! [ ] ,
129
127
}
130
128
}
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
+ }
131
172
}
132
173
133
174
/// Iterator for traversing all [Miniscript] miniscript AST references starting from some specific
134
175
/// node which constructs the iterator via [Miniscript::iter] method.
135
176
pub struct Iter < ' a , Pk : ' a + MiniscriptKey , Ctx : ' a + ScriptContext > {
136
177
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 ) > ,
138
184
}
139
185
140
186
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> {
167
213
/// +--> K
168
214
/// ```
169
215
/// `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`
171
217
///
172
218
/// To enumerate the branches iterator uses [Miniscript::branches] function.
173
219
fn next ( & mut self ) -> Option < Self :: Item > {
174
220
let mut curr = self . next ;
175
221
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) ;
178
224
if curr. is_some ( ) {
179
- self . path . push ( ( node, child + 1 ) ) ;
225
+ self . path . push ( ( node, branches , child + 1 ) ) ;
180
226
break ;
181
227
}
182
228
}
183
229
}
184
230
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 ) ) ;
187
234
}
188
235
curr
189
236
}
@@ -193,14 +240,17 @@ impl<'a, Pk: MiniscriptKey, Ctx: ScriptContext> Iterator for Iter<'a, Pk, Ctx> {
193
240
/// constructs the iterator via [Miniscript::iter_pk] method.
194
241
pub struct PkIter < ' a , Pk : ' a + MiniscriptKey , Ctx : ' a + ScriptContext > {
195
242
node_iter : Iter < ' a , Pk , Ctx > ,
196
- keys_buff : VecDeque < Pk > ,
243
+ curr_node : Option < & ' a Miniscript < Pk , Ctx > > ,
244
+ key_index : usize ,
197
245
}
198
246
199
247
impl < ' a , Pk : MiniscriptKey , Ctx : ScriptContext > PkIter < ' a , Pk , Ctx > {
200
248
fn new ( miniscript : & ' a Miniscript < Pk , Ctx > ) -> Self {
249
+ let mut iter = Iter :: new ( miniscript) ;
201
250
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 ,
204
254
}
205
255
}
206
256
}
@@ -209,30 +259,40 @@ impl<'a, Pk: MiniscriptKey, Ctx: ScriptContext> Iterator for PkIter<'a, Pk, Ctx>
209
259
type Item = Pk ;
210
260
211
261
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
+ }
219
277
}
220
- self . keys_buff . pop_front ( )
221
278
}
222
279
}
223
280
224
281
/// Iterator for traversing all [MiniscriptKey] hashes in AST starting from some specific node which
225
282
/// constructs the iterator via [Miniscript::iter_pkh] method.
226
283
pub struct PkhIter < ' a , Pk : ' a + MiniscriptKey , Ctx : ' a + ScriptContext > {
227
284
node_iter : Iter < ' a , Pk , Ctx > ,
228
- keyhashes_buff : VecDeque < Pk :: Hash > ,
285
+ curr_node : Option < & ' a Miniscript < Pk , Ctx > > ,
286
+ key_index : usize ,
229
287
}
230
288
231
289
impl < ' a , Pk : MiniscriptKey , Ctx : ScriptContext > PkhIter < ' a , Pk , Ctx > {
232
290
fn new ( miniscript : & ' a Miniscript < Pk , Ctx > ) -> Self {
291
+ let mut iter = Iter :: new ( miniscript) ;
233
292
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 ,
236
296
}
237
297
}
238
298
}
@@ -241,15 +301,22 @@ impl<'a, Pk: MiniscriptKey, Ctx: ScriptContext> Iterator for PkhIter<'a, Pk, Ctx
241
301
type Item = Pk :: Hash ;
242
302
243
303
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
+ }
251
319
}
252
- self . keyhashes_buff . pop_front ( )
253
320
}
254
321
}
255
322
@@ -267,14 +334,17 @@ pub enum PkPkh<Pk: MiniscriptKey> {
267
334
/// [Miniscript::iter_keys_and_hashes] method.
268
335
pub struct PkPkhIter < ' a , Pk : ' a + MiniscriptKey , Ctx : ' a + ScriptContext > {
269
336
node_iter : Iter < ' a , Pk , Ctx > ,
270
- buff : VecDeque < PkPkh < Pk > > ,
337
+ curr_node : Option < & ' a Miniscript < Pk , Ctx > > ,
338
+ key_index : usize ,
271
339
}
272
340
273
341
impl < ' a , Pk : MiniscriptKey , Ctx : ScriptContext > PkPkhIter < ' a , Pk , Ctx > {
274
342
fn new ( miniscript : & ' a Miniscript < Pk , Ctx > ) -> Self {
343
+ let mut iter = Iter :: new ( miniscript) ;
275
344
PkPkhIter {
276
- node_iter : Iter :: new ( miniscript) ,
277
- buff : VecDeque :: new ( ) ,
345
+ curr_node : iter. next ( ) ,
346
+ node_iter : iter,
347
+ key_index : 0 ,
278
348
}
279
349
}
280
350
@@ -307,15 +377,22 @@ impl<'a, Pk: MiniscriptKey, Ctx: ScriptContext> Iterator for PkPkhIter<'a, Pk, C
307
377
type Item = PkPkh < Pk > ;
308
378
309
379
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
+ }
317
395
}
318
- self . buff . pop_front ( )
319
396
}
320
397
}
321
398
0 commit comments