ip/
error.rs

1use core::fmt;
2
3/// An error describing a failed operation on an IP object.
4#[derive(Clone, Copy, Debug)]
5pub struct Error {
6    kind: Kind,
7    msg: Option<&'static str>,
8    source: Option<SourceError>,
9}
10
11impl Error {
12    pub(crate) fn new<S: AsRef<str> + ?Sized + 'static>(
13        kind: Kind,
14        msg: Option<&'static S>,
15        source: Option<SourceError>,
16    ) -> Self {
17        Self {
18            kind,
19            msg: msg.map(S::as_ref),
20            source,
21        }
22    }
23
24    /// Returns the [`Kind`] of error.
25    ///
26    /// # Examples
27    ///
28    /// ``` rust
29    /// use ip::{error::Kind, Address, Ipv4};
30    ///
31    /// let err = "10.0.0.256".parse::<Address<Ipv4>>().unwrap_err();
32    /// assert_eq!(err.kind(), Kind::ParserError);
33    /// ```
34    #[must_use]
35    pub const fn kind(&self) -> Kind {
36        self.kind
37    }
38}
39
40impl fmt::Display for Error {
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        if let Some(msg) = self.msg {
43            write!(f, "{}: {}", self.kind, msg)
44        } else {
45            self.kind.fmt(f)
46        }
47    }
48}
49
50#[cfg(feature = "std")]
51#[allow(trivial_casts)]
52impl std::error::Error for Error {
53    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
54        self.source.map(|err| err as _)
55    }
56}
57
58#[cfg(not(feature = "std"))]
59impl Error {
60    /// Returns the underyling source error, if it exists.
61    ///
62    /// This method is provided for interface compatibility with
63    /// `std::error::Error` in a `no_std` environment.
64    #[must_use]
65    pub fn source(&self) -> Option<SourceError> {
66        self.source
67    }
68}
69
70/// The "kind" of an [`Error`].
71#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
72pub enum Kind {
73    /// An [`Error`] resulting from an operation on a prefix-length.
74    PrefixLength,
75    /// An [`Error`] resulting from a parser failure.
76    ParserError,
77    /// An [`Error`] resulting from an attempt to convert between incompatible
78    /// address families.
79    AfiMismatch,
80    /// An [`Error`] resulting from an invalid prefix-length range.
81    PrefixLengthRange,
82    /// An [`Error`] resulting from an attempt to construct an address from a
83    /// byte-slice too long for the address family.
84    OctetSliceOverrun,
85}
86
87impl fmt::Display for Kind {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        match self {
90            Self::PrefixLength => {
91                write!(f, "prefix-length out of bounds")
92            }
93            Self::ParserError => write!(f, "parser error"),
94            Self::AfiMismatch => write!(f, "address family mis-match"),
95            Self::PrefixLengthRange => write!(f, "invalid prefix-length range"),
96            Self::OctetSliceOverrun => write!(f, "octet slice too long for address-family"),
97        }
98    }
99}
100
101#[cfg(feature = "std")]
102type SourceError = &'static (dyn std::error::Error + Send + Sync + 'static);
103#[cfg(not(feature = "std"))]
104type SourceError = &'static (dyn core::any::Any);
105
106macro_rules! err {
107    ( $kind:expr ) => {
108        $crate::error::Error::new::<&'static str>($kind, None, None)
109    };
110    ( $kind:expr, $msg:expr ) => {
111        $crate::error::Error::new($kind, Some($msg), None)
112    };
113}
114pub(crate) use err;
115
116#[cfg(test)]
117pub(crate) type TestResult = Result<(), Error>;