use crate::rules::{ errors::Error, libyaml::{ event::{convert_event, Event}, util::system_mark_to_location, util::Owned, }, path_value::Location, Result, }; use std::{borrow::Cow, mem::MaybeUninit, ptr::addr_of_mut}; use unsafe_libyaml as sys; pub(crate) struct Parser<'input> { pin: Owned>, } struct ParserPinned<'input> { sys: sys::yaml_parser_t, input: Cow<'input, [u8]>, } impl<'input> Parser<'input> { pub fn new(input: Cow<'input, [u8]>) -> Parser<'input> { let owned = Owned::::new_uninit(); let pin = unsafe { let parser = addr_of_mut!((*owned.ptr).sys); if sys::yaml_parser_initialize(parser).fail { panic!( "malloc error: {}", Error::ParseError("error parsing file".to_string()) ); } sys::yaml_parser_set_encoding(parser, sys::YAML_UTF8_ENCODING); sys::yaml_parser_set_input_string(parser, input.as_ptr(), input.len() as u64); addr_of_mut!((*owned.ptr).input).write(input); Owned::assume_init(owned) }; Parser { pin } } pub fn next(&mut self) -> Result<(Event<'input>, Location)> { let mut event = MaybeUninit::::uninit(); unsafe { let parser = addr_of_mut!((*self.pin.ptr).sys); if (*parser).error != sys::YAML_NO_ERROR { return Err(Error::ParseError("error parsing file".to_string())); } let event = event.as_mut_ptr(); if sys::yaml_parser_parse(parser, event).fail { return Err(Error::ParseError("error parsing file".to_string())); } let ret = convert_event(&*event, &(*self.pin.ptr).input); let location = system_mark_to_location((*event).start_mark); sys::yaml_event_delete(event); Ok((ret, location)) } } } impl<'input> Drop for ParserPinned<'input> { fn drop(&mut self) { unsafe { sys::yaml_parser_delete(&mut self.sys) } } }