1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#[cfg(feature = "ffi")]
use sawp_ffi::GenerateFFI;

use std::num::NonZeroUsize;

// Re-export types used for ErrorKind
use nom::error::ErrorKind as NomErrorKind;
use nom::Needed as NomNeeded;

/// Helper that uses this module's error type
pub type Result<T> = std::result::Result<T, Error>;

/// Helper for nom's default error type
// A better nom error will be available once we can migrate
// to nom 6.0+
pub type NomError<I> = (I, NomErrorKind);

/// Common protocol or parsing error
///
/// This error type is meant to return the errors that
/// are common across parsers and other sub packages.
/// Sub packages may choose to implement their own error
/// types if they wish to avoid adding extra dependencies
/// to the base crate.
#[derive(Debug, PartialEq)]
#[cfg_attr(feature = "ffi", derive(GenerateFFI))]
#[cfg_attr(feature = "ffi", sawp_ffi(prefix = "sawp"))]
pub struct Error {
    pub kind: ErrorKind,
}

impl Error {
    pub fn new(kind: ErrorKind) -> Self {
        Self { kind }
    }

    /// Helper for creating an error with a `ErrorKind::Incomplete` and a needed size.
    pub fn incomplete_needed(size: usize) -> Self {
        Error::new(ErrorKind::Incomplete(
            NonZeroUsize::new(size)
                .map(Needed::Size)
                .unwrap_or(Needed::Unknown),
        ))
    }

    /// Helper for creating an error with a `ErrorKind::Incomplete` and an unknown size.
    pub fn incomplete() -> Self {
        Error::new(ErrorKind::Incomplete(Needed::Unknown))
    }

    /// Helper for creating a parse error.
    #[cfg(verbose)]
    pub fn parse(msg: Option<String>) -> Self {
        Error::new(ErrorKind::ParseError(msg))
    }

    /// Helper for creating a parse error.
    #[cfg(not(verbose))]
    pub fn parse(_msg: Option<String>) -> Self {
        Error::new(ErrorKind::ParseError(None))
    }
}

/// Number of bytes needed for the next parsing attempt.
///
/// Used in `ErrorKind::Incomplete` to tell the caller how many bytes to wait
/// for before calling the parser with more data.
#[derive(Debug, PartialEq)]
pub enum Needed {
    Unknown,
    Size(NonZeroUsize),
}

/// Kinds of common errors used by the parsers
#[derive(Debug, PartialEq)]
#[non_exhaustive]
#[cfg_attr(feature = "ffi", derive(GenerateFFI))]
#[cfg_attr(feature = "ffi", sawp_ffi(type_only, prefix = "sawp"))]
pub enum ErrorKind {
    /// Feature is not yet implemented.
    Unimplemented,
    /// Parser could not advance based on the data provided.
    ///
    /// Usually indicates the provided input bytes cannot be parsed
    /// for the protocol.
    //
    // Developer note:
    //
    // This error should only be used as a last resort. Consider
    // returning Ok and adding validation error flags to the
    // parser's `Message` instead.
    InvalidData,
    /// Generic parsing error with optional message.
    ParseError(Option<String>),
    /// Parser did not advance because more data is required to
    /// make a decision.
    ///
    /// The caller should gather more data and try again.
    Incomplete(Needed),
}

impl From<NomErrorKind> for ErrorKind {
    #[cfg(verbose)]
    fn from(kind: NomErrorKind) -> Self {
        Self::ParseError(Some(format!("{:?}", kind)))
    }

    #[cfg(not(verbose))]
    fn from(_kind: NomErrorKind) -> Self {
        Self::ParseError(None)
    }
}

impl<I: std::fmt::Debug> From<nom::Err<NomError<I>>> for Error {
    fn from(nom_err: nom::Err<NomError<I>>) -> Self {
        match nom_err {
            nom::Err::Error(err) | nom::Err::Failure(err) => Error::new(err.1.into()),
            nom::Err::Incomplete(needed) => match needed {
                NomNeeded::Unknown => Error::incomplete(),
                NomNeeded::Size(size) => Error::incomplete_needed(size),
            },
        }
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, _: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
        todo!()
    }
}

impl std::error::Error for Error {}