sawp/
error.rs

1#[cfg(feature = "ffi")]
2use sawp_ffi::GenerateFFI;
3
4use std::num::NonZeroUsize;
5
6// Re-export types used for ErrorKind
7use nom::error::ErrorKind as NomErrorKind;
8use nom::Needed as NomNeeded;
9
10/// Helper that uses this module's error type
11pub type Result<T> = std::result::Result<T, Error>;
12
13/// Helper for nom's default error type
14pub type NomError<I> = nom::error::Error<I>;
15
16/// Common protocol or parsing error
17///
18/// This error type is meant to return the errors that
19/// are common across parsers and other sub packages.
20/// Sub packages may choose to implement their own error
21/// types if they wish to avoid adding extra dependencies
22/// to the base crate.
23#[derive(Debug, PartialEq, Eq)]
24#[cfg_attr(feature = "ffi", derive(GenerateFFI))]
25#[cfg_attr(feature = "ffi", sawp_ffi(prefix = "sawp"))]
26pub struct Error {
27    pub kind: ErrorKind,
28}
29
30impl Error {
31    pub fn new(kind: ErrorKind) -> Self {
32        Self { kind }
33    }
34
35    /// Helper for creating an error with a `ErrorKind::Incomplete` and a needed size.
36    pub fn incomplete_needed(size: usize) -> Self {
37        Error::new(ErrorKind::Incomplete(
38            NonZeroUsize::new(size)
39                .map(Needed::Size)
40                .unwrap_or(Needed::Unknown),
41        ))
42    }
43
44    /// Helper for creating an error with a `ErrorKind::Incomplete` and an unknown size.
45    pub fn incomplete() -> Self {
46        Error::new(ErrorKind::Incomplete(Needed::Unknown))
47    }
48
49    /// Helper for creating a parse error.
50    #[cfg(feature = "verbose")]
51    pub fn parse(msg: Option<String>) -> Self {
52        Error::new(ErrorKind::ParseError(msg))
53    }
54
55    /// Helper for creating a parse error.
56    #[cfg(not(feature = "verbose"))]
57    pub fn parse(_msg: Option<String>) -> Self {
58        Error::new(ErrorKind::ParseError(None))
59    }
60}
61
62impl From<ErrorKind> for Error {
63    fn from(kind: ErrorKind) -> Self {
64        Self::new(kind)
65    }
66}
67
68/// Number of bytes needed for the next parsing attempt.
69///
70/// Used in `ErrorKind::Incomplete` to tell the caller how many bytes to wait
71/// for before calling the parser with more data.
72#[derive(Debug, PartialEq, Eq)]
73pub enum Needed {
74    Unknown,
75    Size(NonZeroUsize),
76}
77
78/// Kinds of common errors used by the parsers
79#[derive(Debug, PartialEq, Eq)]
80#[non_exhaustive]
81#[cfg_attr(feature = "ffi", derive(GenerateFFI))]
82#[cfg_attr(feature = "ffi", sawp_ffi(type_only, prefix = "sawp"))]
83pub enum ErrorKind {
84    /// Feature is not yet implemented.
85    Unimplemented,
86    /// Parser could not advance based on the data provided.
87    ///
88    /// Usually indicates the provided input bytes cannot be parsed
89    /// for the protocol.
90    //
91    // Developer note:
92    //
93    // This error should only be used as a last resort. Consider
94    // returning Ok and adding validation error flags to the
95    // parser's `Message` instead.
96    InvalidData,
97    /// Generic parsing error with optional message.
98    ParseError(Option<String>),
99    /// Parser did not advance because more data is required to
100    /// make a decision.
101    ///
102    /// The caller should gather more data and try again.
103    Incomplete(Needed),
104}
105
106impl From<NomErrorKind> for ErrorKind {
107    #[cfg(feature = "verbose")]
108    fn from(kind: NomErrorKind) -> Self {
109        Self::ParseError(Some(format!("{:?}", kind)))
110    }
111
112    #[cfg(not(feature = "verbose"))]
113    fn from(_kind: NomErrorKind) -> Self {
114        Self::ParseError(None)
115    }
116}
117
118impl<I: std::fmt::Debug> From<nom::Err<NomError<I>>> for Error {
119    fn from(nom_err: nom::Err<NomError<I>>) -> Self {
120        match nom_err {
121            nom::Err::Error(err) | nom::Err::Failure(err) => Error::new(err.code.into()),
122            nom::Err::Incomplete(needed) => match needed {
123                NomNeeded::Unknown => Error::incomplete(),
124                NomNeeded::Size(size) => Error::incomplete_needed(size.into()),
125            },
126        }
127    }
128}
129
130impl std::fmt::Display for Error {
131    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
132        match &self.kind {
133            ErrorKind::Unimplemented => write!(f, "Unimplemented feature"),
134            ErrorKind::InvalidData => write!(f, "Encountered invalid data"),
135            ErrorKind::ParseError(err) if err.is_some() => {
136                write!(f, "Parsing error: {}", err.clone().unwrap())
137            }
138            ErrorKind::ParseError(_) => write!(f, "Parsing error"),
139            ErrorKind::Incomplete(Needed::Unknown) => write!(f, "More bytes required to parse"),
140            ErrorKind::Incomplete(Needed::Size(n)) => {
141                write!(f, "{} more bytes required to parse", n)
142            }
143        }
144    }
145}
146
147impl std::error::Error for Error {}
148
149impl<I: std::fmt::Debug> From<NomError<I>> for Error {
150    fn from(nom_err: NomError<I>) -> Self {
151        Error::new(nom_err.code.into())
152    }
153}