Skip to content

Instantly share code, notes, and snippets.

@alob-mtc
Last active September 17, 2023 15:41
Show Gist options
  • Save alob-mtc/02d4964db5c27f255db12102905f0fd5 to your computer and use it in GitHub Desktop.
Save alob-mtc/02d4964db5c27f255db12102905f0fd5 to your computer and use it in GitHub Desktop.
An Implementation of a String Split [str str::split()] from the std
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", ""]);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment