rustyline/
error.rs

1//! Contains error type for handling I/O and Errno errors
2#[cfg(windows)]
3use std::char;
4use std::error::Error;
5use std::fmt;
6use std::io;
7
8/// The error type for Rustyline errors that can arise from
9/// I/O related errors or Errno when using the nix-rust library
10// #[non_exhaustive]
11#[expect(clippy::module_name_repetitions)]
12#[derive(Debug)]
13#[non_exhaustive]
14pub enum ReadlineError {
15    /// I/O Error
16    Io(io::Error),
17    /// EOF (VEOF / Ctrl-D)
18    Eof,
19    /// Interrupt signal (VINTR / VQUIT / Ctrl-C)
20    Interrupted,
21    /// Unix Error from syscall
22    #[cfg(unix)]
23    Errno(nix::Error),
24    /// Error generated on `WINDOW_BUFFER_SIZE_EVENT` / `SIGWINCH` signal
25    Signal(Signal),
26    /// Like `Utf8Error` on unix
27    #[cfg(windows)]
28    Decode(char::DecodeUtf16Error),
29    /// Something went wrong calling a Windows API
30    #[cfg(windows)]
31    SystemError(clipboard_win::ErrorCode),
32    /// Error related to SQLite history backend
33    #[cfg(feature = "with-sqlite-history")]
34    SQLiteError(rusqlite::Error),
35}
36
37impl fmt::Display for ReadlineError {
38    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39        match *self {
40            Self::Io(ref err) => err.fmt(f),
41            Self::Eof => write!(f, "EOF"),
42            Self::Interrupted => write!(f, "Interrupted"),
43            #[cfg(unix)]
44            Self::Errno(ref err) => err.fmt(f),
45            Self::Signal(ref sig) => write!(f, "Signal({sig:?})"),
46            #[cfg(windows)]
47            Self::Decode(ref err) => err.fmt(f),
48            #[cfg(windows)]
49            Self::SystemError(ref err) => err.fmt(f),
50            #[cfg(feature = "with-sqlite-history")]
51            Self::SQLiteError(ref err) => err.fmt(f),
52        }
53    }
54}
55
56impl Error for ReadlineError {
57    fn source(&self) -> Option<&(dyn Error + 'static)> {
58        match *self {
59            Self::Io(ref err) => Some(err),
60            Self::Eof => None,
61            Self::Interrupted => None,
62            #[cfg(unix)]
63            Self::Errno(ref err) => Some(err),
64            Self::Signal(_) => None,
65            #[cfg(windows)]
66            Self::Decode(ref err) => Some(err),
67            #[cfg(windows)]
68            Self::SystemError(_) => None,
69            #[cfg(feature = "with-sqlite-history")]
70            Self::SQLiteError(ref err) => Some(err),
71        }
72    }
73}
74
75/// Signal received from terminal
76#[derive(Copy, Clone, Debug, Eq, PartialEq)]
77#[repr(u8)]
78pub enum Signal {
79    /// SIGINT
80    #[cfg(unix)]
81    Interrupt,
82    /// SIGWINCH / WINDOW_BUFFER_SIZE_EVENT
83    Resize,
84}
85
86#[cfg(unix)]
87impl Signal {
88    #[cfg(not(feature = "signal-hook"))]
89    pub(crate) fn from(b: u8) -> Self {
90        match b {
91            b'I' => Self::Interrupt,
92            b'W' => Self::Resize,
93            _ => unreachable!(),
94        }
95    }
96
97    #[cfg(feature = "signal-hook")]
98    pub(crate) fn from(_: u8) -> Self {
99        Self::Resize
100    }
101
102    #[cfg(not(feature = "signal-hook"))]
103    pub(crate) fn to_byte(sig: libc::c_int) -> u8 {
104        match sig {
105            libc::SIGINT => b'I',
106            libc::SIGWINCH => b'W',
107            _ => unreachable!(),
108        }
109    }
110}
111
112#[cfg(unix)]
113#[derive(Debug)]
114pub(crate) struct SignalError(pub Signal);
115#[cfg(unix)]
116impl fmt::Display for SignalError {
117    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118        write!(f, "Signal({:?})", self.0)
119    }
120}
121#[cfg(unix)]
122impl Error for SignalError {}
123
124impl From<io::Error> for ReadlineError {
125    fn from(err: io::Error) -> Self {
126        #[cfg(unix)]
127        if err.kind() == io::ErrorKind::Interrupted {
128            if let Some(e) = err.get_ref() {
129                if let Some(se) = e.downcast_ref::<SignalError>() {
130                    return Self::Signal(se.0);
131                }
132            }
133        }
134        Self::Io(err)
135    }
136}
137
138impl From<io::ErrorKind> for ReadlineError {
139    fn from(kind: io::ErrorKind) -> Self {
140        Self::Io(io::Error::from(kind))
141    }
142}
143
144#[cfg(unix)]
145impl From<nix::Error> for ReadlineError {
146    fn from(err: nix::Error) -> Self {
147        Self::Errno(err)
148    }
149}
150
151#[cfg(windows)]
152impl From<char::DecodeUtf16Error> for ReadlineError {
153    fn from(err: char::DecodeUtf16Error) -> Self {
154        Self::Io(io::Error::new(io::ErrorKind::InvalidData, err))
155    }
156}
157
158#[cfg(windows)]
159impl From<std::string::FromUtf8Error> for ReadlineError {
160    fn from(err: std::string::FromUtf8Error) -> Self {
161        Self::Io(io::Error::new(io::ErrorKind::InvalidData, err))
162    }
163}
164
165#[cfg(unix)]
166impl From<fmt::Error> for ReadlineError {
167    fn from(err: fmt::Error) -> Self {
168        Self::Io(io::Error::other(err))
169    }
170}
171
172#[cfg(windows)]
173impl From<clipboard_win::ErrorCode> for ReadlineError {
174    fn from(err: clipboard_win::ErrorCode) -> Self {
175        Self::SystemError(err)
176    }
177}
178
179#[cfg(feature = "with-sqlite-history")]
180impl From<rusqlite::Error> for ReadlineError {
181    fn from(err: rusqlite::Error) -> Self {
182        Self::SQLiteError(err)
183    }
184}