Skip to content

Instantly share code, notes, and snippets.

@nathanbabcock
Created February 13, 2023 19:20
Show Gist options
  • Save nathanbabcock/a7ed7bf7404e443d388baf491900e96c to your computer and use it in GitHub Desktop.
Save nathanbabcock/a7ed7bf7404e443d388baf491900e96c to your computer and use it in GitHub Desktop.

Revisions

  1. nathanbabcock created this gist Feb 13, 2023.
    59 changes: 59 additions & 0 deletions comma_iter.rs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,59 @@
    use std::str::Chars;

    /// An iterator over comma-separated values, **ignoring commas inside parentheses**.
    ///
    /// ## Examples
    ///
    /// ```rust
    /// use ffmpeg_sidecar::util::CommaIter;
    ///
    /// let string = "foo(bar,baz),quux";
    /// let mut iter = CommaIter::new(string);
    ///
    /// assert_eq!(iter.next(), Some("foo(bar,baz)"));
    /// assert_eq!(iter.next(), Some("quux"));
    /// assert_eq!(iter.next(), None);
    /// ```
    pub struct CommaIter<'a> {
    chars: Chars<'a>,
    }

    impl<'a> CommaIter<'a> {
    pub fn new(string: &'a str) -> Self {
    Self {
    chars: string.chars(),
    }
    }
    }

    impl<'a> Iterator for CommaIter<'a> {
    type Item = &'a str;

    /// Return the next comma-separated section, not including the comma.
    fn next(&mut self) -> Option<Self::Item> {
    let chars_clone = self.chars.clone();
    let mut i = 0;

    while let Some(char) = self.chars.next() {
    match char {
    '(' => {
    // advance until closing paren (only handles one level nesting)
    while let Some(close_paren) = self.chars.next() {
    i += 1;
    if close_paren == ')' {
    break;
    }
    }
    }
    ',' => break,
    _ => {}
    }
    i += 1;
    }

    match i {
    0 => None,
    _ => Some(&chars_clone.as_str()[..i]),
    }
    }
    }