| use crate::libyaml::cstr::CStr; |
| use std::fmt::{self, Debug, Display}; |
| use std::mem::MaybeUninit; |
| use std::ptr::NonNull; |
| use unsafe_libyaml as sys; |
| |
| pub(crate) type Result<T> = std::result::Result<T, Error>; |
| |
| pub(crate) struct Error { |
| kind: sys::yaml_error_type_t, |
| problem: CStr<'static>, |
| problem_offset: u64, |
| problem_mark: Mark, |
| context: Option<CStr<'static>>, |
| context_mark: Mark, |
| } |
| |
| impl Error { |
| pub unsafe fn parse_error(parser: *const sys::yaml_parser_t) -> Self { |
| Error { |
| kind: (*parser).error, |
| problem: match NonNull::new((*parser).problem as *mut _) { |
| Some(problem) => CStr::from_ptr(problem), |
| None => CStr::from_bytes_with_nul(b"libyaml parser failed but there is no error\0"), |
| }, |
| problem_offset: (*parser).problem_offset, |
| problem_mark: Mark { |
| sys: (*parser).problem_mark, |
| }, |
| context: match NonNull::new((*parser).context as *mut _) { |
| Some(context) => Some(CStr::from_ptr(context)), |
| None => None, |
| }, |
| context_mark: Mark { |
| sys: (*parser).context_mark, |
| }, |
| } |
| } |
| |
| pub unsafe fn emit_error(emitter: *const sys::yaml_emitter_t) -> Self { |
| Error { |
| kind: (*emitter).error, |
| problem: match NonNull::new((*emitter).problem as *mut _) { |
| Some(problem) => CStr::from_ptr(problem), |
| None => { |
| CStr::from_bytes_with_nul(b"libyaml emitter failed but there is no error\0") |
| } |
| }, |
| problem_offset: 0, |
| problem_mark: Mark { |
| sys: MaybeUninit::<sys::yaml_mark_t>::zeroed().assume_init(), |
| }, |
| context: None, |
| context_mark: Mark { |
| sys: MaybeUninit::<sys::yaml_mark_t>::zeroed().assume_init(), |
| }, |
| } |
| } |
| |
| pub fn mark(&self) -> Mark { |
| self.problem_mark |
| } |
| } |
| |
| impl Display for Error { |
| fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
| write!(formatter, "{}", self.problem)?; |
| if self.problem_mark.sys.line != 0 || self.problem_mark.sys.column != 0 { |
| write!(formatter, " at {}", self.problem_mark)?; |
| } else if self.problem_offset != 0 { |
| write!(formatter, " at position {}", self.problem_offset)?; |
| } |
| if let Some(context) = &self.context { |
| write!(formatter, ", {}", context)?; |
| if (self.context_mark.sys.line != 0 || self.context_mark.sys.column != 0) |
| && (self.context_mark.sys.line != self.problem_mark.sys.line |
| || self.context_mark.sys.column != self.problem_mark.sys.column) |
| { |
| write!(formatter, " at {}", self.context_mark)?; |
| } |
| } |
| Ok(()) |
| } |
| } |
| |
| impl Debug for Error { |
| fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
| let mut formatter = formatter.debug_struct("Error"); |
| if let Some(kind) = match self.kind { |
| sys::YAML_MEMORY_ERROR => Some("MEMORY"), |
| sys::YAML_READER_ERROR => Some("READER"), |
| sys::YAML_SCANNER_ERROR => Some("SCANNER"), |
| sys::YAML_PARSER_ERROR => Some("PARSER"), |
| sys::YAML_COMPOSER_ERROR => Some("COMPOSER"), |
| sys::YAML_WRITER_ERROR => Some("WRITER"), |
| sys::YAML_EMITTER_ERROR => Some("EMITTER"), |
| _ => None, |
| } { |
| formatter.field("kind", &format_args!("{}", kind)); |
| } |
| formatter.field("problem", &self.problem); |
| if self.problem_mark.sys.line != 0 || self.problem_mark.sys.column != 0 { |
| formatter.field("problem_mark", &self.problem_mark); |
| } else if self.problem_offset != 0 { |
| formatter.field("problem_offset", &self.problem_offset); |
| } |
| if let Some(context) = &self.context { |
| formatter.field("context", context); |
| if self.context_mark.sys.line != 0 || self.context_mark.sys.column != 0 { |
| formatter.field("context_mark", &self.context_mark); |
| } |
| } |
| formatter.finish() |
| } |
| } |
| |
| #[derive(Copy, Clone)] |
| pub(crate) struct Mark { |
| pub(super) sys: sys::yaml_mark_t, |
| } |
| |
| impl Mark { |
| pub fn index(&self) -> u64 { |
| self.sys.index |
| } |
| |
| pub fn line(&self) -> u64 { |
| self.sys.line |
| } |
| |
| pub fn column(&self) -> u64 { |
| self.sys.column |
| } |
| } |
| |
| impl Display for Mark { |
| fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
| if self.sys.line != 0 || self.sys.column != 0 { |
| write!( |
| formatter, |
| "line {} column {}", |
| self.sys.line + 1, |
| self.sys.column + 1, |
| ) |
| } else { |
| write!(formatter, "position {}", self.sys.index) |
| } |
| } |
| } |
| |
| impl Debug for Mark { |
| fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
| let mut formatter = formatter.debug_struct("Mark"); |
| if self.sys.line != 0 || self.sys.column != 0 { |
| formatter.field("line", &(self.sys.line + 1)); |
| formatter.field("column", &(self.sys.column + 1)); |
| } else { |
| formatter.field("index", &self.sys.index); |
| } |
| formatter.finish() |
| } |
| } |