Skip to content

Commit

Permalink
Add Iterator for KeyExpr
Browse files Browse the repository at this point in the history
  • Loading branch information
kanishk779 committed Jul 6, 2022
1 parent af960e9 commit 102efbd
Showing 1 changed file with 66 additions and 0 deletions.
66 changes: 66 additions & 0 deletions src/miniscript/musig_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,35 @@ impl<Pk: MiniscriptKey + FromStr> FromStr for KeyExpr<Pk> {
}
}

#[derive(Debug, Clone)]
/// Iterator for keyexpr
pub struct KeyExprIter<'a, Pk: MiniscriptKey> {
stack: Vec<&'a KeyExpr<Pk>>,
}

impl<'a, Pk> Iterator for KeyExprIter<'a, Pk>
where
Pk: MiniscriptKey + 'a,
{
type Item = &'a Pk;

fn next(&mut self) -> Option<Self::Item> {
while !self.stack.is_empty() {
let last = self.stack.pop().expect("Size checked above");
match &*last {
KeyExpr::MuSig(key_vec) => {
// push the elements in reverse order
for key in key_vec.iter().rev() {
self.stack.push(key)
}
}
KeyExpr::SingleKey(ref pk) => return Some(pk),
}
}
None
}
}

impl<Pk: MiniscriptKey> fmt::Debug for KeyExpr<Pk> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Expand Down Expand Up @@ -79,6 +108,14 @@ impl<Pk: MiniscriptKey> fmt::Display for KeyExpr<Pk> {
}
}
}

impl<Pk: MiniscriptKey> KeyExpr<Pk> {
/// Iterate over all keys
pub fn iter(&self) -> KeyExprIter<Pk> {
KeyExprIter { stack: vec![self] }
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand All @@ -97,4 +134,33 @@ mod tests {
test_one("A");
test_one("musig(,,)");
}

#[test]
fn test_iterator() {
let pk = KeyExpr::<String>::from_str("musig(A,B,musig(C,musig(D,E)))").unwrap();
let mut my_iter = pk.iter();
assert_eq!(my_iter.next(), Some(&String::from("A")));
assert_eq!(my_iter.next(), Some(&String::from("B")));
assert_eq!(my_iter.next(), Some(&String::from("C")));
assert_eq!(my_iter.next(), Some(&String::from("D")));
assert_eq!(my_iter.next(), Some(&String::from("E")));
assert_eq!(my_iter.next(), None);
}

fn test_helper(musig_key: &str, comma_separated_key: &str) {
let pk = KeyExpr::<String>::from_str(musig_key).unwrap();
let var: Vec<&str> = comma_separated_key.split(",").collect();
let key_names: Vec<&String> = pk.iter().collect();
for (key1, key2) in key_names.iter().zip(var.iter()) {
assert_eq!(key1, key2);
}
}

#[test]
fn test_iterator_multi() {
test_helper("musig(A)", "A");
test_helper("A", "A");
test_helper("musig(,,)", "");
test_helper("musig(musig(A,B),musig(musig(C)))", "A,B,C");
}
}

0 comments on commit 102efbd

Please sign in to comment.