Skip to content

Instantly share code, notes, and snippets.

@George-Payne
Created November 20, 2018 00:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save George-Payne/c1c56cb483459d3ce97391ce97868627 to your computer and use it in GitHub Desktop.
Save George-Payne/c1c56cb483459d3ce97391ce97868627 to your computer and use it in GitHub Desktop.
Book as an Iterator
struct Book<'a> {
text: &'a str,
width: usize,
}
impl<'a> IntoIterator for Book<'a> {
type Item = String;
type IntoIter = BookIntoIterator<'a>;
fn into_iter(self) -> Self::IntoIter {
BookIntoIterator::new(self)
}
}
struct BookIntoIterator<'a> {
words: std::str::SplitWhitespace<'a>,
active_word: Option<&'a str>,
width: usize,
}
impl<'a> BookIntoIterator<'a> {
pub fn new(book: Book<'a>) -> Self {
let mut words = book.text.split_whitespace().into_iter();
let width = book.width;
let active_word = words.next();
BookIntoIterator {
words,
width,
active_word,
}
}
}
impl<'a> Iterator for BookIntoIterator<'a> {
type Item = String;
fn next(&mut self) -> Option<String> {
let mut line = "".to_string();
let mut word = match self.active_word {
Some(word) => word,
_ => return None,
};
while line.len() + word.len() + 1 < self.width {
line = if line.len() > 0 {
[&line, word].join(" ")
} else {
word.to_string()
};
self.active_word = self.words.next();
word = match self.active_word {
Some(word) => word,
_ => break,
};
}
if word.len() > self.width && self.width - line.len() > 4 {
let chunk_width = self.width - line.len() - 2;
let (head, tail) = word.split_at(chunk_width);
let dashed_word = [head, "-"].join("");
line = if line.len() > 0 {
[line, dashed_word].join(" ")
} else {
dashed_word.to_string()
};
self.active_word = Some(tail);
}
Some(line)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment