Skip to content

Commit 102efbd

Browse files
committed
Add Iterator for KeyExpr
1 parent af960e9 commit 102efbd

File tree

1 file changed

+66
-0
lines changed

1 file changed

+66
-0
lines changed

src/miniscript/musig_key.rs

+66
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,35 @@ impl<Pk: MiniscriptKey + FromStr> FromStr for KeyExpr<Pk> {
4040
}
4141
}
4242

43+
#[derive(Debug, Clone)]
44+
/// Iterator for keyexpr
45+
pub struct KeyExprIter<'a, Pk: MiniscriptKey> {
46+
stack: Vec<&'a KeyExpr<Pk>>,
47+
}
48+
49+
impl<'a, Pk> Iterator for KeyExprIter<'a, Pk>
50+
where
51+
Pk: MiniscriptKey + 'a,
52+
{
53+
type Item = &'a Pk;
54+
55+
fn next(&mut self) -> Option<Self::Item> {
56+
while !self.stack.is_empty() {
57+
let last = self.stack.pop().expect("Size checked above");
58+
match &*last {
59+
KeyExpr::MuSig(key_vec) => {
60+
// push the elements in reverse order
61+
for key in key_vec.iter().rev() {
62+
self.stack.push(key)
63+
}
64+
}
65+
KeyExpr::SingleKey(ref pk) => return Some(pk),
66+
}
67+
}
68+
None
69+
}
70+
}
71+
4372
impl<Pk: MiniscriptKey> fmt::Debug for KeyExpr<Pk> {
4473
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4574
match *self {
@@ -79,6 +108,14 @@ impl<Pk: MiniscriptKey> fmt::Display for KeyExpr<Pk> {
79108
}
80109
}
81110
}
111+
112+
impl<Pk: MiniscriptKey> KeyExpr<Pk> {
113+
/// Iterate over all keys
114+
pub fn iter(&self) -> KeyExprIter<Pk> {
115+
KeyExprIter { stack: vec![self] }
116+
}
117+
}
118+
82119
#[cfg(test)]
83120
mod tests {
84121
use super::*;
@@ -97,4 +134,33 @@ mod tests {
97134
test_one("A");
98135
test_one("musig(,,)");
99136
}
137+
138+
#[test]
139+
fn test_iterator() {
140+
let pk = KeyExpr::<String>::from_str("musig(A,B,musig(C,musig(D,E)))").unwrap();
141+
let mut my_iter = pk.iter();
142+
assert_eq!(my_iter.next(), Some(&String::from("A")));
143+
assert_eq!(my_iter.next(), Some(&String::from("B")));
144+
assert_eq!(my_iter.next(), Some(&String::from("C")));
145+
assert_eq!(my_iter.next(), Some(&String::from("D")));
146+
assert_eq!(my_iter.next(), Some(&String::from("E")));
147+
assert_eq!(my_iter.next(), None);
148+
}
149+
150+
fn test_helper(musig_key: &str, comma_separated_key: &str) {
151+
let pk = KeyExpr::<String>::from_str(musig_key).unwrap();
152+
let var: Vec<&str> = comma_separated_key.split(",").collect();
153+
let key_names: Vec<&String> = pk.iter().collect();
154+
for (key1, key2) in key_names.iter().zip(var.iter()) {
155+
assert_eq!(key1, key2);
156+
}
157+
}
158+
159+
#[test]
160+
fn test_iterator_multi() {
161+
test_helper("musig(A)", "A");
162+
test_helper("A", "A");
163+
test_helper("musig(,,)", "");
164+
test_helper("musig(musig(A,B),musig(musig(C)))", "A,B,C");
165+
}
100166
}

0 commit comments

Comments
 (0)