serde_yaml/libyaml/
error.rs

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