Skip to main content

embassy_shell/
error.rs

1use core::fmt;
2
3use embedded_io::ErrorKind;
4
5/// Error type used by the shell and returned by command handlers.
6///
7/// Transport errors are wrapped into [`Error::Io`] so that every command
8/// handler can use the same concrete error type regardless of the underlying
9/// transport.
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum Error {
12    /// An I/O error occurred on the underlying transport.
13    Io(ErrorKind),
14    /// An operation failed for another reason.
15    Other,
16}
17
18impl core::error::Error for Error {}
19
20impl embedded_io::Error for Error {
21    fn kind(&self) -> ErrorKind {
22        match self {
23            Error::Io(kind) => *kind,
24            Error::Other => ErrorKind::Other,
25        }
26    }
27}
28
29impl From<ErrorKind> for Error {
30    fn from(kind: ErrorKind) -> Self {
31        Error::Io(kind)
32    }
33}
34
35#[cfg(feature = "defmt")]
36impl defmt::Format for Error {
37    fn format(&self, f: defmt::Formatter<'_>) {
38        match self {
39            // `embedded_io::ErrorKind` does not implement `defmt::Format`,
40            // so the kind is not carried on the wire.
41            Error::Io(_) => defmt::write!(f, "io error"),
42            Error::Other => defmt::write!(f, "shell error"),
43        }
44    }
45}
46
47impl Error {
48    /// Short, allocation-free description used by the shell's error line.
49    ///
50    /// Unlike [`Display`](core::fmt::Display) this returns a `&'static str`
51    /// so the shell never has to run `core::fmt` (or allocate a buffer) just
52    /// to report a failed command.
53    pub fn message(&self) -> &'static str {
54        match self {
55            Error::Other => "shell error",
56            Error::Io(kind) => match *kind {
57                ErrorKind::NotFound => "not found",
58                ErrorKind::PermissionDenied => "permission denied",
59                ErrorKind::ConnectionRefused => "connection refused",
60                ErrorKind::ConnectionReset => "connection reset",
61                ErrorKind::ConnectionAborted => "connection aborted",
62                ErrorKind::NotConnected => "not connected",
63                ErrorKind::AddrInUse => "address in use",
64                ErrorKind::AddrNotAvailable => "address not available",
65                ErrorKind::BrokenPipe => "broken pipe",
66                ErrorKind::AlreadyExists => "already exists",
67                ErrorKind::InvalidInput => "invalid input",
68                ErrorKind::InvalidData => "invalid data",
69                ErrorKind::TimedOut => "timed out",
70                ErrorKind::Interrupted => "interrupted",
71                ErrorKind::Unsupported => "unsupported",
72                ErrorKind::OutOfMemory => "out of memory",
73                ErrorKind::WriteZero => "write zero",
74                _ => "io error",
75            },
76        }
77    }
78}
79
80impl fmt::Display for Error {
81    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82        match self {
83            Error::Io(kind) => write!(f, "io error: {kind:?}"),
84            Error::Other => write!(f, "shell error"),
85        }
86    }
87}
88
89/// Convenience alias used throughout the crate and by command handlers.
90pub type Result<T> = core::result::Result<T, Error>;