use unicode_segmentation::UnicodeSegmentation;
use std::io;
use std::mem;
pub struct Graphemes<R: Iterator<Item = io::Result<char>>> {
input: R,
buffer: String,
pending_error: Option<io::Error>,
}
impl<R: Iterator<Item = io::Result<char>>> Iterator for Graphemes<R> {
type Item = io::Result<String>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(err) = self.pending_error.take() {
return Some(Err(err));
}
loop {
match self.input.next() {
Some(Ok(codepoint)) => {
self.buffer.push(codepoint);
}
None => {
if self.buffer.is_empty() {
return None;
} else {
return Some(Ok(mem::replace(&mut self.buffer, String::new())));
}
}
Some(Err(e)) => {
if self.buffer.is_empty() {
return Some(Err(e));
} else {
self.pending_error = Some(e);
return Some(Ok(mem::replace(&mut self.buffer, String::new())));
}
}
}
let mut gi = self.buffer.grapheme_indices(true).fuse();
if let (Some((_, first_grapheme)), Some((second_pos, _))) = (gi.next(), gi.next()) {
let grapheme = first_grapheme.to_owned();
self.buffer = unsafe { self.buffer.get_unchecked(second_pos ..) }.to_owned();
return Some(Ok(grapheme));
}
}
}
}
impl<R: Iterator<Item = io::Result<char>>> From<R> for Graphemes<R> {
fn from(input: R) -> Graphemes<R> {
Graphemes {
input,
buffer: String::new(),
pending_error: None,
}
}
}