use std::{error::Error, io::Read};
use crate::{
CharStream, CharacterStream, CharacterStreamResult, MultiPeek, MultiPeekable, Peek, Peekable,
PeekableCharacterStream, ToCharacterStream, TryToCharacterStream,
};
pub(crate) const INTERRUPTED_MAX: usize = 5;
pub struct CharacterIterator<Stream: CharStream> {
pub(crate) stream: Stream,
pub(crate) interrupted_max: usize,
pub interrupted_count: usize,
}
impl<Stream: CharStream> CharacterIterator<Stream> {
pub fn new(stream: Stream, interrupted_max: usize) -> Self {
Self {
stream,
interrupted_max,
interrupted_count: 0,
}
}
pub fn stream(&self) -> &Stream {
&self.stream
}
pub fn stream_mut(&mut self) -> &mut Stream {
&mut self.stream
}
pub fn is_lossy(&self) -> bool {
self.stream.is_lossy()
}
}
impl<Reader: Read> CharacterIterator<CharacterStream<Reader>> {
pub fn peek(self) -> CharacterIterator<PeekableCharacterStream<Reader, Peek>> {
CharacterIterator::new(self.stream.peeky(), self.interrupted_max)
}
pub fn peek_multi(self) -> CharacterIterator<PeekableCharacterStream<Reader, MultiPeek>> {
CharacterIterator::new(self.stream.peeky_multi(), self.interrupted_max)
}
}
impl<Reader: Read> CharacterIterator<PeekableCharacterStream<Reader, Peek>> {
pub fn peek(&mut self) -> Option<&<Self as Iterator>::Item> {
self.stream.peek()
}
}
impl<Reader: Read> CharacterIterator<PeekableCharacterStream<Reader, MultiPeek>> {
pub fn peek(&mut self) -> Option<&<Self as Iterator>::Item> {
self.stream.peek()
}
pub fn reset_peek(&mut self) {
self.stream.reset_peek()
}
}
impl<Stream: CharStream + std::fmt::Debug> std::fmt::Debug for CharacterIterator<Stream> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
impl<Stream: CharStream> Iterator for CharacterIterator<Stream> {
type Item = CharacterStreamResult;
fn next(&mut self) -> Option<Self::Item> {
match self.stream.read_char() {
Ok(character) => {
if self.interrupted_count > 0 {
self.interrupted_count = 0;
}
Some(Ok(character))
}
Err(error) => match error {
crate::CharacterError::NoBytesRead => None,
crate::CharacterError::IoError {
bytes: _,
error: ref err,
} => match err.kind() {
std::io::ErrorKind::Interrupted => {
if self.interrupted_count <= self.interrupted_max {
self.interrupted_count += 1;
self.next()
} else {
None
}
}
std::io::ErrorKind::UnexpectedEof => None,
_ => Some(Err(error)),
},
other => Some(Err(other)),
},
}
}
}
pub trait ToCharacterIterator<Reader: Read> {
fn to_character_iterator(&self) -> CharacterIterator<CharacterStream<Reader>>;
fn to_character_iterator_lossy(&self) -> CharacterIterator<CharacterStream<Reader>>;
}
impl<Reader: Read, T: ToCharacterStream<Reader>> ToCharacterIterator<Reader> for T {
fn to_character_iterator(&self) -> CharacterIterator<CharacterStream<Reader>> {
self.to_character_stream().into_iter()
}
fn to_character_iterator_lossy(&self) -> CharacterIterator<CharacterStream<Reader>> {
self.to_character_stream_lossy().into_iter()
}
}
pub trait TryToCharacterIterator<Reader: Read> {
fn try_to_character_iterator(
&self,
) -> Result<CharacterIterator<CharacterStream<Reader>>, Box<dyn Error>>;
fn try_to_character_iterator_lossy(
&self,
) -> Result<CharacterIterator<CharacterStream<Reader>>, Box<dyn Error>>;
}
impl<Reader: Read, T: TryToCharacterStream<Reader>> TryToCharacterIterator<Reader> for T {
fn try_to_character_iterator(
&self,
) -> Result<CharacterIterator<CharacterStream<Reader>>, Box<dyn Error>> {
Ok(self.try_to_character_stream()?.into_iter())
}
fn try_to_character_iterator_lossy(
&self,
) -> Result<CharacterIterator<CharacterStream<Reader>>, Box<dyn Error>> {
Ok(self.try_to_character_stream_lossy()?.into_iter())
}
}