1use super::cmd::{Format, ResetStyle, SetForeground8};
8
9#[derive(Clone, Copy, Debug, PartialEq, Eq)]
11pub enum ErrorKind {
12 NoData,
14 InFlight,
16 MalformedUtf8,
18 MalformedSequence,
20 PathologicalSequence,
22 BadControl,
24 BadSequence,
26 NotASequence,
28 OutOfMemory,
30 TooFewCoordinates,
32 TooManyCoordinates,
34 EmptyCoordinate,
36 OversizedCoordinate,
38 MalformedCoordinate,
40 Unreadable,
42}
43
44impl ErrorKind {
45 pub fn as_str(&self) -> &'static str {
47 match *self {
48 Self::NoData => "reading terminal input timed out without returning data",
49 Self::InFlight => "token is in-flight, hence access to raw bytes is not safe",
50 Self::MalformedUtf8 => "malformed UTF-8",
51 Self::MalformedSequence => "malformed ANSI escape sequence",
52 Self::PathologicalSequence => "pathologically long ANSI escape sequence",
53 Self::BadControl => "unexpected control for ANSI escape sequence",
54 Self::BadSequence => "unexpected ANSI escape sequence",
55 Self::NotASequence => "token not an ANSI escape sequence",
56 Self::OutOfMemory => "ANSI escape sequence too long for internal buffer",
57 Self::Unreadable => "error reading terminal",
58 Self::TooFewCoordinates => "too few color coordinates",
59 Self::TooManyCoordinates => "too many color coordinates",
60 Self::EmptyCoordinate => "empty color coordinate",
61 Self::OversizedCoordinate => "oversized color coordinate",
62 Self::MalformedCoordinate => "malformed color coordinate",
63 }
64 }
65}
66
67impl From<ErrorKind> for std::io::Error {
68 fn from(value: ErrorKind) -> Self {
69 Error::from(value).into()
70 }
71}
72
73impl From<ErrorKind> for Error {
74 fn from(kind: ErrorKind) -> Self {
75 Self { kind, source: None }
76 }
77}
78
79#[derive(Debug)]
81pub struct Error {
82 kind: ErrorKind,
83 source: Option<std::io::Error>,
84}
85
86impl Error {
87 #[must_use = "the only reason to invoke method is to access the returned value"]
89 pub fn unreadable(source: std::io::Error) -> Self {
90 Self {
91 kind: ErrorKind::Unreadable,
92 source: Some(source),
93 }
94 }
95
96 pub fn kind(&self) -> ErrorKind {
98 self.kind
99 }
100}
101
102impl core::fmt::Display for Error {
103 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
104 f.write_str(self.kind.as_str())
105 }
106}
107
108impl core::error::Error for Error {
109 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
110 if let &Self {
111 kind: ErrorKind::Unreadable,
112 source: Some(ref error),
113 } = self
114 {
115 Some(error)
116 } else {
117 None
118 }
119 }
120}
121
122impl From<std::io::Error> for Error {
123 fn from(value: std::io::Error) -> Self {
124 Self::unreadable(value)
125 }
126}
127
128impl From<Error> for std::io::Error {
129 fn from(value: Error) -> Self {
130 use self::ErrorKind::*;
131
132 match value.kind {
133 MalformedUtf8 | MalformedSequence | PathologicalSequence | BadControl | BadSequence
134 | NotASequence | TooFewCoordinates | TooManyCoordinates | EmptyCoordinate
135 | OversizedCoordinate | MalformedCoordinate => {
136 Self::new(std::io::ErrorKind::InvalidData, value)
137 }
138 NoData => std::io::ErrorKind::TimedOut.into(),
139 InFlight => std::io::ErrorKind::ResourceBusy.into(),
140 OutOfMemory => std::io::ErrorKind::OutOfMemory.into(),
141 Unreadable =>
142 {
143 #[allow(clippy::option_if_let_else)]
144 if let Some(error) = value.source {
145 error
146 } else {
147 Self::new(std::io::ErrorKind::Other, value)
148 }
149 }
150 }
151 }
152}
153
154pub fn should_retry<T, E>(result: core::result::Result<T, E>) -> bool
158where
159 E: Into<std::io::Error>,
160{
161 if let Err(err) = result {
162 let kind = err.into().kind();
163 kind == std::io::ErrorKind::Interrupted || kind == std::io::ErrorKind::TimedOut
164 } else {
165 false
166 }
167}
168
169#[allow(clippy::print_stdout)]
171pub fn report<E: core::error::Error>(error: &E) {
172 println!(
173 "{}{}ERROR: {}{}",
174 Format::Bold,
175 SetForeground8::<1>,
176 error,
177 ResetStyle
178 );
179
180 let mut error: &dyn core::error::Error = error;
181 while let Some(inner) = error.source() {
182 println!(" {}", inner);
183 error = inner;
184 }
185}