1use core::{
6 convert::Infallible,
7 error::Error,
8 ffi::CStr,
9 fmt::{Debug, Display},
10};
11
12use crate::Read;
13
14pub type ParseResult<T> = Result<T, ParseError>;
16
17pub type PacketParseResult<T> = Result<T, PacketParseError>;
19
20#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
22pub enum ParseError {
23 Unwanted,
25 NeedsHint,
28 TooSmall,
31 StraddledHeader,
33 NoRemainingChunks,
37 CannotAccept,
40 Reject,
42 IllegalValue,
44}
45
46impl ParseError {
47 #[inline]
49 pub fn as_cstr(&self) -> &'static CStr {
50 match self {
51 ParseError::Unwanted => c"Unwanted",
52 ParseError::NeedsHint => c"NeedsHint",
53 ParseError::TooSmall => c"TooSmall",
54 ParseError::StraddledHeader => c"StraddledHeader",
55 ParseError::NoRemainingChunks => c"NoRemainingChunks",
56 ParseError::CannotAccept => c"CannotAccept",
57 ParseError::Reject => c"Reject",
58 ParseError::IllegalValue => c"IllegalValue",
59 }
60 }
61
62 #[doc(hidden)]
65 pub fn convert_read_parse(self, reader: &mut impl Read) -> Self {
66 match self {
67 Self::TooSmall if reader.next_chunk().is_ok() => {
68 Self::StraddledHeader
69 }
70 a => a,
71 }
72 }
73}
74
75impl From<Infallible> for ParseError {
76 #[inline]
77 fn from(_: Infallible) -> Self {
78 unreachable!()
81 }
82}
83
84impl Display for ParseError {
85 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
86 match self {
87 ParseError::Unwanted => {
88 write!(f, "encountered header not permitted by the parser")
89 }
90 ParseError::NeedsHint => write!(
91 f,
92 "header/choice requires a hint to parse and none was provided"
93 ),
94 ParseError::TooSmall => {
95 write!(f, "insufficient bytes in buffer to read current header")
96 }
97 ParseError::StraddledHeader => {
98 write!(f, "header is split across more than one buffer")
99 }
100 ParseError::NoRemainingChunks => write!(
101 f,
102 "packet contains no more chunks for parsing outstanding headers"
103 ),
104 ParseError::CannotAccept => write!(
105 f,
106 "tried to accept packet with unfilled mandatory headers"
107 ),
108 ParseError::Reject => write!(f, "packet was explicitly rejected"),
109 ParseError::IllegalValue => {
110 write!(f, "encountered field value not permitted by the parser")
111 }
112 }
113 }
114}
115
116impl Error for ParseError {}
117
118#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
120pub struct PacketParseError {
121 label: &'static CRStr,
122 inner: ParseError,
123}
124
125impl PacketParseError {
126 #[inline]
127 pub const fn new(err: ParseError, label: &'static CRStr) -> Self {
129 Self { label, inner: err }
130 }
131
132 #[inline]
133 pub fn error(&self) -> &ParseError {
135 &self.inner
136 }
137
138 #[inline]
139 pub fn header(&self) -> &CRStr {
141 self.label
142 }
143}
144
145impl From<Infallible> for PacketParseError {
146 #[inline]
147 fn from(_: Infallible) -> Self {
148 unreachable!()
151 }
152}
153
154impl From<PacketParseError> for ParseError {
155 #[inline]
156 fn from(value: PacketParseError) -> Self {
157 value.inner
158 }
159}
160
161impl Display for PacketParseError {
162 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
163 write!(f, "error while parsing {}: {}", self.label, self.inner)
164 }
165}
166
167impl Error for PacketParseError {
168 fn source(&self) -> Option<&(dyn Error + 'static)> {
169 Some(&self.inner)
170 }
171}
172
173#[derive(Clone, Copy, Eq, PartialEq, Hash)]
175pub struct CRStr(&'static str, &'static CStr);
176
177#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
180pub struct CRStrError;
181
182impl Display for CRStrError {
183 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
184 write!(f, "input string was not null-terminated")
185 }
186}
187
188impl Error for CRStrError {}
189
190impl CRStr {
191 #[inline]
192 pub const fn new(data: &'static str) -> Result<Self, CRStrError> {
211 if let Ok(cs) = CStr::from_bytes_with_nul(data.as_bytes()) {
212 if let Some((_nul, actual_str)) = data.as_bytes().split_last() {
213 Ok(Self(
214 unsafe { core::str::from_utf8_unchecked(actual_str) },
219 cs,
220 ))
221 } else {
222 Err(CRStrError)
223 }
224 } else {
225 Err(CRStrError)
226 }
227 }
228
229 #[inline]
230 pub const fn new_unchecked(data: &'static str) -> Self {
244 match Self::new(data) {
245 Ok(v) => v,
246 Err(_) => panic!(),
247 }
248 }
249
250 #[inline]
251 pub fn as_str(&self) -> &'static str {
253 self.0
254 }
255
256 #[inline]
257 pub fn as_cstr(&self) -> &'static CStr {
259 self.1
260 }
261}
262
263impl AsRef<str> for CRStr {
264 #[inline]
265 fn as_ref(&self) -> &'static str {
266 self.as_str()
267 }
268}
269
270impl AsRef<CStr> for CRStr {
271 #[inline]
272 fn as_ref(&self) -> &'static CStr {
273 self.as_cstr()
274 }
275}
276
277impl Error for CRStr {}
278
279impl Debug for CRStr {
280 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
281 write!(f, "{}", self.0)
282 }
283}
284
285impl Display for CRStr {
286 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
287 write!(f, "{}", self.0)
288 }
289}