1 use crate::libyaml::cstr::CStr; 2 use std::fmt::{self, Debug, Display}; 3 use std::mem::MaybeUninit; 4 use std::ptr::NonNull; 5 use unsafe_libyaml as sys; 6 7 pub(crate) type Result<T> = std::result::Result<T, Error>; 8 9 pub(crate) struct Error { 10 kind: sys::yaml_error_type_t, 11 problem: CStr<'static>, 12 problem_offset: u64, 13 problem_mark: Mark, 14 context: Option<CStr<'static>>, 15 context_mark: Mark, 16 } 17 18 impl Error { parse_error(parser: *const sys::yaml_parser_t) -> Self19 pub unsafe fn parse_error(parser: *const sys::yaml_parser_t) -> Self { 20 Error { 21 kind: unsafe { (*parser).error }, 22 problem: match NonNull::new(unsafe { (*parser).problem as *mut _ }) { 23 Some(problem) => unsafe { CStr::from_ptr(problem) }, 24 None => CStr::from_bytes_with_nul(b"libyaml parser failed but there is no error\0"), 25 }, 26 problem_offset: unsafe { (*parser).problem_offset }, 27 problem_mark: Mark { 28 sys: unsafe { (*parser).problem_mark }, 29 }, 30 context: match NonNull::new(unsafe { (*parser).context as *mut _ }) { 31 Some(context) => Some(unsafe { CStr::from_ptr(context) }), 32 None => None, 33 }, 34 context_mark: Mark { 35 sys: unsafe { (*parser).context_mark }, 36 }, 37 } 38 } 39 emit_error(emitter: *const sys::yaml_emitter_t) -> Self40 pub unsafe fn emit_error(emitter: *const sys::yaml_emitter_t) -> Self { 41 Error { 42 kind: unsafe { (*emitter).error }, 43 problem: match NonNull::new(unsafe { (*emitter).problem as *mut _ }) { 44 Some(problem) => unsafe { CStr::from_ptr(problem) }, 45 None => { 46 CStr::from_bytes_with_nul(b"libyaml emitter failed but there is no error\0") 47 } 48 }, 49 problem_offset: 0, 50 problem_mark: Mark { 51 sys: unsafe { MaybeUninit::<sys::yaml_mark_t>::zeroed().assume_init() }, 52 }, 53 context: None, 54 context_mark: Mark { 55 sys: unsafe { MaybeUninit::<sys::yaml_mark_t>::zeroed().assume_init() }, 56 }, 57 } 58 } 59 mark(&self) -> Mark60 pub fn mark(&self) -> Mark { 61 self.problem_mark 62 } 63 } 64 65 impl Display for Error { fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result66 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 67 write!(formatter, "{}", self.problem)?; 68 if self.problem_mark.sys.line != 0 || self.problem_mark.sys.column != 0 { 69 write!(formatter, " at {}", self.problem_mark)?; 70 } else if self.problem_offset != 0 { 71 write!(formatter, " at position {}", self.problem_offset)?; 72 } 73 if let Some(context) = &self.context { 74 write!(formatter, ", {}", context)?; 75 if (self.context_mark.sys.line != 0 || self.context_mark.sys.column != 0) 76 && (self.context_mark.sys.line != self.problem_mark.sys.line 77 || self.context_mark.sys.column != self.problem_mark.sys.column) 78 { 79 write!(formatter, " at {}", self.context_mark)?; 80 } 81 } 82 Ok(()) 83 } 84 } 85 86 impl Debug for Error { fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result87 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 88 let mut formatter = formatter.debug_struct("Error"); 89 if let Some(kind) = match self.kind { 90 sys::YAML_MEMORY_ERROR => Some("MEMORY"), 91 sys::YAML_READER_ERROR => Some("READER"), 92 sys::YAML_SCANNER_ERROR => Some("SCANNER"), 93 sys::YAML_PARSER_ERROR => Some("PARSER"), 94 sys::YAML_COMPOSER_ERROR => Some("COMPOSER"), 95 sys::YAML_WRITER_ERROR => Some("WRITER"), 96 sys::YAML_EMITTER_ERROR => Some("EMITTER"), 97 _ => None, 98 } { 99 formatter.field("kind", &format_args!("{}", kind)); 100 } 101 formatter.field("problem", &self.problem); 102 if self.problem_mark.sys.line != 0 || self.problem_mark.sys.column != 0 { 103 formatter.field("problem_mark", &self.problem_mark); 104 } else if self.problem_offset != 0 { 105 formatter.field("problem_offset", &self.problem_offset); 106 } 107 if let Some(context) = &self.context { 108 formatter.field("context", context); 109 if self.context_mark.sys.line != 0 || self.context_mark.sys.column != 0 { 110 formatter.field("context_mark", &self.context_mark); 111 } 112 } 113 formatter.finish() 114 } 115 } 116 117 #[derive(Copy, Clone)] 118 pub(crate) struct Mark { 119 pub(super) sys: sys::yaml_mark_t, 120 } 121 122 impl Mark { index(&self) -> u64123 pub fn index(&self) -> u64 { 124 self.sys.index 125 } 126 line(&self) -> u64127 pub fn line(&self) -> u64 { 128 self.sys.line 129 } 130 column(&self) -> u64131 pub fn column(&self) -> u64 { 132 self.sys.column 133 } 134 } 135 136 impl Display for Mark { fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result137 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 138 if self.sys.line != 0 || self.sys.column != 0 { 139 write!( 140 formatter, 141 "line {} column {}", 142 self.sys.line + 1, 143 self.sys.column + 1, 144 ) 145 } else { 146 write!(formatter, "position {}", self.sys.index) 147 } 148 } 149 } 150 151 impl Debug for Mark { fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result152 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 153 let mut formatter = formatter.debug_struct("Mark"); 154 if self.sys.line != 0 || self.sys.column != 0 { 155 formatter.field("line", &(self.sys.line + 1)); 156 formatter.field("column", &(self.sys.column + 1)); 157 } else { 158 formatter.field("index", &self.sys.index); 159 } 160 formatter.finish() 161 } 162 } 163