1#[cfg(windows)]
3use std::char;
4use std::error::Error;
5use std::fmt;
6use std::io;
7
8#[expect(clippy::module_name_repetitions)]
12#[derive(Debug)]
13#[non_exhaustive]
14pub enum ReadlineError {
15 Io(io::Error),
17 Eof,
19 Interrupted,
21 #[cfg(unix)]
23 Errno(nix::Error),
24 Signal(Signal),
26 #[cfg(windows)]
28 Decode(char::DecodeUtf16Error),
29 #[cfg(windows)]
31 SystemError(clipboard_win::ErrorCode),
32 #[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#[derive(Copy, Clone, Debug, Eq, PartialEq)]
77#[repr(u8)]
78pub enum Signal {
79 #[cfg(unix)]
81 Interrupt,
82 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}