1use std::{
4 error::Error,
5 fmt::{self, Debug, Display, Formatter, Write},
6 io,
7};
8
9#[derive(Debug)]
31pub struct ConversionError<S, E = NoDetails> {
32 pub details: E,
34 pub cause: Option<io::Error>,
36 pub source: Option<S>,
38}
39impl<S, E: Default> ConversionError<S, E> {
40 pub fn from_source(source: S) -> Self {
43 Self {
44 details: Default::default(),
45 cause: None,
46 source: Some(source),
47 }
48 }
49 pub fn from_cause(cause: io::Error) -> Self {
52 Self {
53 details: Default::default(),
54 cause: Some(cause),
55 source: None,
56 }
57 }
58 pub fn from_source_and_cause(source: S, cause: io::Error) -> Self {
61 Self {
62 details: Default::default(),
63 cause: Some(cause),
64 source: Some(source),
65 }
66 }
67}
68impl<S, E> ConversionError<S, E> {
69 pub fn from_source_and_details(source: S, details: E) -> Self {
71 Self {
72 details,
73 cause: None,
74 source: Some(source),
75 }
76 }
77 pub fn from_cause_and_details(cause: io::Error, details: E) -> Self {
79 Self {
80 details,
81 cause: Some(cause),
82 source: None,
83 }
84 }
85 pub fn map_source<Sb>(self, f: impl FnOnce(S) -> Sb) -> ConversionError<Sb, E> {
89 ConversionError {
90 details: self.details,
91 cause: self.cause,
92 source: self.source.map(f),
93 }
94 }
95 pub fn try_map_source<Sb>(self, f: impl FnOnce(S) -> Option<Sb>) -> ConversionError<Sb, E> {
100 ConversionError {
101 details: self.details,
102 cause: self.cause,
103 source: self.source.and_then(f),
104 }
105 }
106}
107impl<S, E: Display> ConversionError<S, E> {
108 pub fn to_io_error(&self) -> io::Error {
110 let msg = self.to_string();
111 io::Error::new(io::ErrorKind::Other, msg)
112 }
113}
114impl<S, E: Display> From<ConversionError<S, E>> for io::Error {
116 fn from(e: ConversionError<S, E>) -> Self {
117 e.to_io_error()
118 }
119}
120impl<S, E: Default> Default for ConversionError<S, E> {
121 fn default() -> Self {
122 Self {
123 details: Default::default(),
124 cause: None,
125 source: None,
126 }
127 }
128}
129impl<S, E: Display> Display for ConversionError<S, E> {
130 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
131 let mut snp = FormatSnooper::new(f);
132 write!(snp, "{}", &self.details)?;
133 if let Some(e) = &self.cause {
134 if snp.anything_written() {
135 f.write_str(": ")?;
136 }
137 Display::fmt(e, f)?;
138 }
139 Ok(())
140 }
141}
142impl<S: Debug, E: Error + 'static> Error for ConversionError<S, E> {
143 #[inline]
144 #[allow(clippy::as_conversions)]
145 fn source(&self) -> Option<&(dyn Error + 'static)> {
146 self.cause.as_ref().map(|r| r as &_)
147 }
148}
149
150struct FormatSnooper<'a, 'b> {
153 formatter: &'b mut Formatter<'a>,
154 anything_written: bool,
155}
156impl<'a, 'b> FormatSnooper<'a, 'b> {
157 fn new(formatter: &'b mut Formatter<'a>) -> Self {
158 Self {
159 formatter,
160 anything_written: false,
161 }
162 }
163 fn anything_written(&self) -> bool {
164 self.anything_written
165 }
166}
167impl Write for FormatSnooper<'_, '_> {
168 fn write_str(&mut self, s: &str) -> fmt::Result {
169 if !s.is_empty() {
170 self.anything_written = true;
171 self.formatter.write_str(s)
172 } else {
173 Ok(())
174 }
175 }
176}
177
178#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
181pub struct NoDetails;
182impl Display for NoDetails {
183 fn fmt(&self, _f: &mut Formatter<'_>) -> fmt::Result {
184 Ok(()) }
186}
187
188#[cfg(windows)]
190#[cfg_attr(feature = "doc_cfg", doc(cfg(windows)))]
191pub type FromHandleError<E = NoDetails> = ConversionError<std::os::windows::io::OwnedHandle, E>;
192
193#[cfg(unix)]
195#[cfg_attr(feature = "doc_cfg", doc(cfg(unix)))]
196pub type FromFdError<E = NoDetails> = ConversionError<std::os::unix::io::OwnedFd, E>;
197
198#[derive(Debug)]
201pub struct ReuniteError<R, S> {
202 pub rh: R,
204 pub sh: S,
206}
207impl<R, S> ReuniteError<R, S> {
208 #[inline]
210 pub fn map_halves<NR: From<R>, NS: From<S>>(
211 self,
212 fr: impl FnOnce(R) -> NR,
213 fs: impl FnOnce(S) -> NS,
214 ) -> ReuniteError<NR, NS> {
215 let Self { rh, sh } = self;
216 ReuniteError {
217 rh: fr(rh),
218 sh: fs(sh),
219 }
220 }
221 #[inline]
225 pub fn convert_halves<NR: From<R>, NS: From<S>>(self) -> ReuniteError<NR, NS> {
226 self.map_halves(From::from, From::from)
227 }
228}
229impl<R, S> Display for ReuniteError<R, S> {
230 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
231 f.write_str("attempt to reunite stream halves that come from different streams")
232 }
233}
234impl<R: Debug, S: Debug> Error for ReuniteError<R, S> {}
235
236pub type ReuniteResult<T, R, S> = Result<T, ReuniteError<R, S>>;