use std::io;
use std::mem;
use std::os::raw;
use std::slice;
use crate::{Event, ParserError, ParserIter};
use crate::sys;
pub struct Parser<'a> {
inner: sys::yaml_parser_t,
reader: Box<dyn io::Read + 'a>,
reader_error: Option<io::Error>,
}
impl<'a> Parser<'a> {
pub fn new<R: io::Read + 'a>(reader: R) -> Result<Box<Self>, ParserError> {
let mut inner = unsafe { mem::MaybeUninit::zeroed().assume_init() };
if unsafe { sys::yaml_parser_initialize(&mut inner) }.ok {
let mut parser = Box::new(Self {
inner,
reader: Box::new(reader),
reader_error: None,
});
unsafe {
sys::yaml_parser_set_input(
&mut parser.inner,
read_handler,
parser.as_mut() as *mut _ as *mut _,
);
}
Ok(parser)
} else {
Err(ParserError::LibYamlError)
}
}
pub fn parse(&mut self) -> Result<Event, ParserError> {
let mut event = unsafe { mem::MaybeUninit::zeroed().assume_init() };
if unsafe { sys::yaml_parser_parse(&mut self.inner, &mut event) }.ok {
debug_assert!(self.reader_error.is_none());
Ok(Event::from_raw(event)?)
} else {
match mem::replace(&mut self.reader_error, None) {
Some(e) => Err(ParserError::IoError(e)),
None => Err(ParserError::LibYamlError),
}
}
}
pub fn as_raw_ptr(&mut self) -> *mut sys::yaml_parser_t {
&mut self.inner
}
}
impl Drop for Parser<'_> {
fn drop(&mut self) {
unsafe {
sys::yaml_parser_delete(&mut self.inner);
}
}
}
impl<'a> IntoIterator for Box<Parser<'a>> {
type Item = <ParserIter<'a> as Iterator>::Item;
type IntoIter = ParserIter<'a>;
fn into_iter(self) -> Self::IntoIter {
ParserIter::new(self)
}
}
unsafe fn read_handler(
data: *mut raw::c_void,
buffer: *mut raw::c_uchar,
size: u64,
size_read: *mut u64,
) -> raw::c_int {
let parser = &mut *(data as *mut Parser);
match parser.reader.read(slice::from_raw_parts_mut(buffer, size.min(usize::MAX as _) as _)) {
Ok(n) => {
*size_read = n as _;
parser.reader_error = None;
1
},
Err(e) => {
*size_read = 0;
parser.reader_error = Some(e);
0
},
}
}