serde_yaml/libyaml/
error.rs

1use crate::libyaml::cstr::CStr;
2use std::fmt::{self, Debug, Display};
3use std::mem::MaybeUninit;
4use std::ptr::NonNull;
5use unsafe_libyaml as sys;
6
7pub(crate) type Result<T> = std::result::Result<T, Error>;
8
9pub(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
18impl Error {
19    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
40    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
60    pub fn mark(&self) -> Mark {
61        self.problem_mark
62    }
63}
64
65impl Display for Error {
66    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
86impl Debug for Error {
87    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)]
118pub(crate) struct Mark {
119    pub(super) sys: sys::yaml_mark_t,
120}
121
122impl Mark {
123    pub fn index(&self) -> u64 {
124        self.sys.index
125    }
126
127    pub fn line(&self) -> u64 {
128        self.sys.line
129    }
130
131    pub fn column(&self) -> u64 {
132        self.sys.column
133    }
134}
135
136impl Display for Mark {
137    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
151impl Debug for Mark {
152    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}