1use alloc::vec;
2use alloc::vec::Vec;
3use core::fmt;
4
5pub trait MergeError: Sized {
7 fn merge(self, other: Self) -> Self;
8}
9
10pub trait ContextError: Sized {
12 fn add_context(self, context: &'static str) -> Self;
13}
14
15#[derive(Debug, Clone, PartialEq, Eq)]
17pub enum Expected {
18 Char(char),
20 Tag(&'static str),
22 Byte(u8),
24 ByteTag(&'static [u8]),
26 Description(&'static str),
28 Eof,
30}
31
32#[derive(Debug, Clone, PartialEq, Eq)]
34pub struct ParseError {
35 pub position: usize,
37 pub expected: Vec<Expected>,
39 pub context: Vec<&'static str>,
41}
42
43impl ParseError {
44 pub fn new(position: usize, expected: Expected) -> Self {
45 ParseError {
46 position,
47 expected: vec![expected],
48 context: Vec::new(),
49 }
50 }
51
52 pub fn expected_char(position: usize, c: char) -> Self {
53 Self::new(position, Expected::Char(c))
54 }
55
56 pub fn expected_tag(position: usize, tag: &'static str) -> Self {
57 Self::new(position, Expected::Tag(tag))
58 }
59
60 pub fn expected_description(position: usize, desc: &'static str) -> Self {
61 Self::new(position, Expected::Description(desc))
62 }
63
64 pub fn expected_eof(position: usize) -> Self {
65 Self::new(position, Expected::Eof)
66 }
67}
68
69impl MergeError for ParseError {
70 fn merge(mut self, other: Self) -> Self {
71 use core::cmp::Ordering;
72 match self.position.cmp(&other.position) {
73 Ordering::Greater => self,
74 Ordering::Less => other,
75 Ordering::Equal => {
76 for e in other.expected {
77 if !self.expected.contains(&e) {
78 self.expected.push(e);
79 }
80 }
81 self
82 }
83 }
84 }
85}
86
87impl ContextError for ParseError {
88 fn add_context(mut self, context: &'static str) -> Self {
89 self.context.push(context);
90 self
91 }
92}
93
94impl fmt::Display for ParseError {
95 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96 write!(f, "parse error at position {}", self.position)?;
97
98 if !self.expected.is_empty() {
99 write!(f, ": expected ")?;
100 for (i, e) in self.expected.iter().enumerate() {
101 if i > 0 {
102 write!(f, " or ")?;
103 }
104 match e {
105 Expected::Char(c) => write!(f, "'{}'", c)?,
106 Expected::Tag(s) => write!(f, "\"{}\"", s)?,
107 Expected::Byte(b) => write!(f, "0x{:02X}", b)?,
108 Expected::ByteTag(bs) => write!(f, "{:?}", bs)?,
109 Expected::Description(d) => write!(f, "{}", d)?,
110 Expected::Eof => write!(f, "end of input")?,
111 }
112 }
113 }
114
115 if !self.context.is_empty() {
116 write!(f, " in ")?;
117 for (i, ctx) in self.context.iter().rev().enumerate() {
118 if i > 0 {
119 write!(f, " > ")?;
120 }
121 write!(f, "{}", ctx)?;
122 }
123 }
124
125 Ok(())
126 }
127}