use std::io;
use std::mem;
use std::os::raw;
use std::slice;
use libyaml_sys as sys;
use crate::{EmitterError, Event};
pub struct Emitter<'a> {
inner: sys::yaml_emitter_t,
writer: Box<dyn io::Write + 'a>,
writer_error: Option<io::Error>,
}
impl<'a> Emitter<'a> {
pub fn new<W: io::Write + 'a>(writer: W) -> Result<Box<Self>, EmitterError> {
let mut inner = unsafe { mem::MaybeUninit::zeroed().assume_init() };
if unsafe { sys::yaml_emitter_initialize(&mut inner) } == 1 {
let mut emitter = Box::new(Self {
inner,
writer: Box::new(writer),
writer_error: None,
});
unsafe {
sys::yaml_emitter_set_output(
&mut emitter.inner,
Some(write_handler),
emitter.as_mut() as *mut _ as *mut _,
);
}
Ok(emitter)
} else {
Err(EmitterError::LibYamlError)
}
}
pub fn emit(&mut self, event: Event) -> Result<(), EmitterError> {
if unsafe { sys::yaml_emitter_emit(&mut self.inner, &mut event.into_raw()?) } == 1 {
debug_assert!(self.writer_error.is_none());
Ok(())
} else {
match mem::replace(&mut self.writer_error, None) {
Some(e) => Err(EmitterError::IoError(e)),
None => Err(EmitterError::LibYamlError),
}
}
}
pub fn flush(&mut self) -> Result<(), EmitterError> {
if unsafe { sys::yaml_emitter_flush(&mut self.inner) } == 1 {
Ok(())
} else {
Err(EmitterError::LibYamlError)
}
}
pub fn as_raw_ptr(&mut self) -> *mut sys::yaml_emitter_t {
&mut self.inner
}
}
impl Drop for Emitter<'_> {
fn drop(&mut self) {
unsafe {
sys::yaml_emitter_delete(&mut self.inner)
}
}
}
unsafe extern fn write_handler(
data: *mut raw::c_void,
buffer: *mut raw::c_uchar,
size: usize,
) -> raw::c_int {
let emitter = &mut *(data as *mut Emitter);
emitter.writer_error = emitter.writer
.write_all(slice::from_raw_parts(buffer, size))
.err();
if emitter.writer_error.is_none() { 1 } else { 0 }
}