Skip to content

Commit d64e3b2

Browse files
committed
policy: Iterator over fragments and keys
The order of fragments doesn't seem to matter, so I chose preorder which is easy to implement. I would have used the iterators from dag.rs, but Dag doesn't cover nodes with arbitrary but fixed outdegree, like Policy::Threshold. It might be worth to extend Dag in the future, although that could make the generic code in dag.rs more complicated than it already is.
1 parent 1bdedd1 commit d64e3b2

File tree

1 file changed

+49
-0
lines changed

1 file changed

+49
-0
lines changed

src/policy/ast.rs

+49
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,19 @@ impl<Pk: SimplicityKey> Policy<Pk> {
215215
_ => {}
216216
}
217217
}
218+
219+
/// Return an iterator over the fragments of the policy.
220+
pub fn iter(&self) -> PolicyIter<'_, Pk> {
221+
PolicyIter::new(self)
222+
}
223+
224+
/// Return an iterator over the public keys of the policy.
225+
pub fn iter_pk(&self) -> impl Iterator<Item = Pk> + '_ {
226+
self.iter().filter_map(|fragment| match fragment {
227+
Policy::Key(key) => Some(key.clone()),
228+
_ => None,
229+
})
230+
}
218231
}
219232

220233
impl<Pk: SimplicityKey> fmt::Debug for Policy<Pk> {
@@ -244,3 +257,39 @@ impl<Pk: SimplicityKey> fmt::Display for Policy<Pk> {
244257
fmt::Debug::fmt(self, f)
245258
}
246259
}
260+
261+
/// Iterator over the fragments of a Simplicity policy.
262+
///
263+
/// The fragments are visited in preorder:
264+
/// We first visit the parent, then the left subtree, then the right subtree.
265+
pub struct PolicyIter<'a, Pk: SimplicityKey> {
266+
stack: Vec<&'a Policy<Pk>>,
267+
}
268+
269+
impl<'a, Pk: SimplicityKey> PolicyIter<'a, Pk> {
270+
/// Create an iterator for the given policy.
271+
pub fn new(policy: &'a Policy<Pk>) -> Self {
272+
Self {
273+
stack: vec![policy],
274+
}
275+
}
276+
}
277+
278+
impl<'a, Pk: SimplicityKey> Iterator for PolicyIter<'a, Pk> {
279+
type Item = &'a Policy<Pk>;
280+
281+
fn next(&mut self) -> Option<Self::Item> {
282+
let top = self.stack.pop()?;
283+
match top {
284+
Policy::And { left, right } | Policy::Or { left, right } => {
285+
self.stack.push(right);
286+
self.stack.push(left);
287+
}
288+
Policy::Threshold(_, children) => {
289+
self.stack.extend(children.iter().rev());
290+
}
291+
_ => {}
292+
}
293+
Some(top)
294+
}
295+
}

0 commit comments

Comments
 (0)