use std::io;
use granit_parser::{ErrorKind, Event, InputIoError, Parser, ScanError};
struct CheckedChars<I> {
input: I,
bytes_read: usize,
byte_limit: usize,
finished: bool,
}
impl<I> CheckedChars<I> {
fn new(input: I, byte_limit: usize) -> Self {
Self {
input,
bytes_read: 0,
byte_limit,
finished: false,
}
}
}
impl<I> Iterator for CheckedChars<I>
where
I: Iterator<Item = io::Result<char>>,
{
type Item = Result<char, ErrorKind>;
fn next(&mut self) -> Option<Self::Item> {
if self.finished {
return None;
}
let Some(next) = self.input.next() else {
self.finished = true;
return None;
};
match next {
Ok(c) => {
let char_bytes = c.len_utf8();
if char_bytes > self.byte_limit.saturating_sub(self.bytes_read) {
self.finished = true;
Some(Err(ErrorKind::InputByteLimitExceeded {
limit: self.byte_limit,
}))
} else {
self.bytes_read += char_bytes;
Some(Ok(c))
}
}
Err(error) => {
self.finished = true;
Some(Err(ErrorKind::InputIo {
error: InputIoError::from(error),
}))
}
}
}
}
fn main() -> Result<(), ScanError> {
let yaml = "service:\n enabled: true\n retries: 3\n";
let decoded = yaml.chars().map(Ok::<_, io::Error>);
let input = CheckedChars::new(decoded, 1024);
for next in Parser::new_from_fallible_iter(input) {
let (event, _) = next?;
if let Event::Scalar(value, ..) = event {
println!("{value}");
}
}
Ok(())
}