Skip to content

Instantly share code, notes, and snippets.

@bouyagas
Forked from jonhoo/strsplit.rs
Created November 24, 2021 18:14
Show Gist options
  • Save bouyagas/878e1f4ebf7aedd21cf331011d64df3f to your computer and use it in GitHub Desktop.
Save bouyagas/878e1f4ebf7aedd21cf331011d64df3f to your computer and use it in GitHub Desktop.

Revisions

  1. @jonhoo jonhoo created this gist Apr 22, 2020.
    76 changes: 76 additions & 0 deletions strsplit.rs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,76 @@
    #![warn(rust_2018_idioms)]

    #[derive(Debug)]
    pub struct StrSplit<'haystack, D> {
    remainder: Option<&'haystack str>,
    delimiter: D,
    }

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

    pub trait Delimiter {
    fn find_next(&self, s: &str) -> Option<(usize, usize)>;
    }

    impl<'haystack, D> Iterator for StrSplit<'haystack, D>
    where
    D: Delimiter,
    {
    type Item = &'haystack str;
    fn next(&mut self) -> Option<Self::Item> {
    let remainder = self.remainder.as_mut()?;
    if let Some((delim_start, delim_end)) = self.delimiter.find_next(remainder) {
    let until_delimiter = &remainder[..delim_start];
    *remainder = &remainder[delim_end..];
    Some(until_delimiter)
    } else {
    self.remainder.take()
    }
    }
    }

    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 + self.len_utf8()))
    }
    }

    pub fn until_char(s: &str, c: char) -> &'_ str {
    StrSplit::new(s, c)
    .next()
    .expect("StrSplit always gives at least one result")
    }

    #[test]
    fn until_char_test() {
    assert_eq!(until_char("hello world", 'o'), "hell");
    }

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

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