Skip to content

Instantly share code, notes, and snippets.

@alob-mtc
Last active September 17, 2023 15:41
Show Gist options
  • Select an option

  • Save alob-mtc/02d4964db5c27f255db12102905f0fd5 to your computer and use it in GitHub Desktop.

Select an option

Save alob-mtc/02d4964db5c27f255db12102905f0fd5 to your computer and use it in GitHub Desktop.

Revisions

  1. alob-mtc revised this gist Sep 11, 2023. No changes.
  2. alob-mtc created this gist Sep 11, 2023.
    75 changes: 75 additions & 0 deletions lib.rs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,75 @@
    pub trait Delimiter {
    fn find_next(&self, s: &str) -> Option<(usize, usize)>;
    }

    impl Delimiter for &str {
    fn find_next(&self, s: &str) -> Option<(usize, usize)> {
    s.find(self).map(|start| (start, start + self.len()))
    }
    }

    impl Delimiter for char {
    fn find_next(&self, s: &str) -> Option<(usize, usize)> {
    s.char_indices()
    .find(|(_, c)| c == self)
    .map(|(start, _)| (start, start + 1))
    }
    }
    struct StrSplit<'a, D> {
    remainder: Option<&'a str>,
    delimiter: D,
    }

    impl<'a, D> StrSplit<'a, D> {
    pub fn new(haystack: &'a str, delimiter: D) -> Self {
    Self {
    remainder: Some(haystack),
    delimiter,
    }
    }
    }

    impl<'a, D: Delimiter> Iterator for StrSplit<'a, D> {
    type Item = &'a str;

    fn next(&mut self) -> Option<Self::Item> {
    if let Some(ref mut remainder) = self.remainder {
    if let Some((delim_start, delim_end)) = self.delimiter.find_next(remainder) {
    let until_delimiter = &remainder[..delim_start];
    *remainder = &remainder[delim_end..];
    return Some(until_delimiter);
    } else {
    return self.remainder.take();
    }
    }
    None
    }
    }

    #[cfg(test)]
    mod tests {
    use super::*;

    #[test]
    fn case_char() {
    let haystack = "hello world";
    let word = StrSplit::new(haystack, 'o')
    .next()
    .expect("always gives at least one result");
    assert_eq!(word, "hell");
    }

    #[test]
    fn case_str() {
    let haystack = "a b c d e";
    let letters = StrSplit::new(haystack, " ").collect::<Vec<_>>();
    assert_eq!(letters, vec!["a", "b", "c", "d", "e"]);
    }

    #[test]
    fn case2_tail() {
    let haystack = "a b c d ";
    let letters = StrSplit::new(haystack, " ").collect::<Vec<_>>();
    assert_eq!(letters, vec!["a", "b", "c", "d", ""]);
    }
    }