1#[cfg(feature = "alloc")]
2use alloc::vec;
3#[cfg(feature = "alloc")]
4use alloc::vec::Vec;
5use core::fmt;
6
7pub trait MergeError: Sized {
9 fn merge(self, other: Self) -> Self;
10}
11
12pub trait ContextError: Sized {
14 fn add_context(self, context: &'static str) -> Self;
15}
16
17pub trait ExpectError: Sized {
19 fn from_expected(position: usize, expected: Expected) -> Self;
20}
21
22#[derive(Debug, Clone, PartialEq, Eq)]
24pub enum Expected {
25 Char(char),
27 Tag(&'static str),
29 Byte(u8),
31 ByteTag(&'static [u8]),
33 Description(&'static str),
35 Eof,
37}
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq)]
41pub struct MinimalError {
42 pub position: usize,
43}
44
45impl ExpectError for MinimalError {
46 #[inline]
47 fn from_expected(position: usize, _expected: Expected) -> Self {
48 Self { position }
49 }
50}
51
52impl MergeError for MinimalError {
53 #[inline]
54 fn merge(self, other: Self) -> Self {
55 if self.position >= other.position {
56 self
57 } else {
58 other
59 }
60 }
61}
62
63impl ContextError for MinimalError {
64 #[inline]
65 fn add_context(self, _context: &'static str) -> Self {
66 self
67 }
68}
69
70impl fmt::Display for MinimalError {
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 write!(f, "parse error at position {}", self.position)
73 }
74}
75
76#[cfg(feature = "alloc")]
78#[derive(Debug, Clone, PartialEq, Eq)]
79pub struct ParseError {
80 pub position: usize,
82 pub expected: Vec<Expected>,
84 pub context: Vec<&'static str>,
86}
87
88#[cfg(feature = "alloc")]
89impl ExpectError for ParseError {
90 #[inline(always)]
91 fn from_expected(position: usize, expected: Expected) -> Self {
92 ParseError {
93 position,
94 expected: vec![expected],
95 context: Vec::new(),
96 }
97 }
98}
99
100#[cfg(feature = "alloc")]
101impl MergeError for ParseError {
102 fn merge(mut self, other: Self) -> Self {
103 use core::cmp::Ordering;
104 match self.position.cmp(&other.position) {
105 Ordering::Greater => self,
106 Ordering::Less => other,
107 Ordering::Equal => {
108 for e in other.expected {
109 if !self.expected.contains(&e) {
110 self.expected.push(e);
111 }
112 }
113 self
114 }
115 }
116 }
117}
118
119#[cfg(feature = "alloc")]
120impl ContextError for ParseError {
121 fn add_context(mut self, context: &'static str) -> Self {
122 self.context.push(context);
123 self
124 }
125}
126
127#[cfg(feature = "alloc")]
128impl fmt::Display for ParseError {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 write!(f, "parse error at position {}", self.position)?;
131
132 if !self.expected.is_empty() {
133 write!(f, ": expected ")?;
134 for (i, e) in self.expected.iter().enumerate() {
135 if i > 0 {
136 write!(f, " or ")?;
137 }
138 match e {
139 Expected::Char(c) => write!(f, "'{}'", c)?,
140 Expected::Tag(s) => write!(f, "\"{}\"", s)?,
141 Expected::Byte(b) => write!(f, "0x{:02X}", b)?,
142 Expected::ByteTag(bs) => write!(f, "{:?}", bs)?,
143 Expected::Description(d) => write!(f, "{}", d)?,
144 Expected::Eof => write!(f, "end of input")?,
145 }
146 }
147 }
148
149 if !self.context.is_empty() {
150 write!(f, " in ")?;
151 for (i, ctx) in self.context.iter().rev().enumerate() {
152 if i > 0 {
153 write!(f, " > ")?;
154 }
155 write!(f, "{}", ctx)?;
156 }
157 }
158
159 Ok(())
160 }
161}