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 { details: Default::default(), cause: None, source: Some(source) }
44 }
45 pub fn from_cause(cause: io::Error) -> Self {
48 Self { details: Default::default(), cause: Some(cause), source: None }
49 }
50 pub fn from_source_and_cause(source: S, cause: io::Error) -> Self {
53 Self { details: Default::default(), cause: Some(cause), source: Some(source) }
54 }
55}
56impl<S, E> ConversionError<S, E> {
57 pub fn from_source_and_details(source: S, details: E) -> Self {
59 Self { details, cause: None, source: Some(source) }
60 }
61 pub fn from_cause_and_details(cause: io::Error, details: E) -> Self {
63 Self { details, cause: Some(cause), source: None }
64 }
65 pub fn map_source<Sb>(self, f: impl FnOnce(S) -> Sb) -> ConversionError<Sb, E> {
69 ConversionError { details: self.details, cause: self.cause, source: self.source.map(f) }
70 }
71 pub fn try_map_source<Sb>(self, f: impl FnOnce(S) -> Option<Sb>) -> ConversionError<Sb, E> {
76 ConversionError {
77 details: self.details,
78 cause: self.cause,
79 source: self.source.and_then(f),
80 }
81 }
82}
83impl<S, E: Display> ConversionError<S, E> {
84 pub fn to_io_error(&self) -> io::Error { io::Error::other(self.to_string()) }
86}
87impl<S, E: Display> From<ConversionError<S, E>> for io::Error {
89 fn from(e: ConversionError<S, E>) -> Self { e.to_io_error() }
90}
91impl<S, E: Default> Default for ConversionError<S, E> {
92 fn default() -> Self { Self { details: Default::default(), cause: None, source: None } }
93}
94impl<S, E: Display> Display for ConversionError<S, E> {
95 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
96 let mut snp = FormatSnooper::new(f);
97 write!(snp, "{}", &self.details)?;
98 if let Some(e) = &self.cause {
99 if snp.anything_written() {
100 f.write_str(": ")?;
101 }
102 Display::fmt(e, f)?;
103 }
104 Ok(())
105 }
106}
107impl<S: Debug, E: Error + 'static> Error for ConversionError<S, E> {
108 #[inline]
109 #[allow(clippy::as_conversions)]
110 fn source(&self) -> Option<&(dyn Error + 'static)> { self.cause.as_ref().map(|r| r as &_) }
111}
112
113struct FormatSnooper<'a, 'b> {
116 formatter: &'b mut Formatter<'a>,
117 anything_written: bool,
118}
119impl<'a, 'b> FormatSnooper<'a, 'b> {
120 fn new(formatter: &'b mut Formatter<'a>) -> Self {
121 Self { formatter, anything_written: false }
122 }
123 fn anything_written(&self) -> bool { self.anything_written }
124}
125impl Write for FormatSnooper<'_, '_> {
126 fn write_str(&mut self, s: &str) -> fmt::Result {
127 if !s.is_empty() {
128 self.anything_written = true;
129 self.formatter.write_str(s)
130 } else {
131 Ok(())
132 }
133 }
134}
135
136#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
139pub struct NoDetails;
140impl Display for NoDetails {
141 fn fmt(&self, _f: &mut Formatter<'_>) -> fmt::Result {
142 Ok(()) }
144}
145
146#[cfg(windows)]
148#[cfg_attr(feature = "doc_cfg", doc(cfg(windows)))]
149pub type FromHandleError<E = NoDetails> = ConversionError<std::os::windows::io::OwnedHandle, E>;
150
151#[cfg(unix)]
153#[cfg_attr(feature = "doc_cfg", doc(cfg(unix)))]
154pub type FromFdError<E = NoDetails> = ConversionError<std::os::unix::io::OwnedFd, E>;
155
156#[derive(Debug)]
159pub struct ReuniteError<R, S> {
160 pub rh: R,
162 pub sh: S,
164}
165impl<R, S> ReuniteError<R, S> {
166 #[inline]
168 pub fn map_halves<NR: From<R>, NS: From<S>>(
169 self,
170 fr: impl FnOnce(R) -> NR,
171 fs: impl FnOnce(S) -> NS,
172 ) -> ReuniteError<NR, NS> {
173 let Self { rh, sh } = self;
174 ReuniteError { rh: fr(rh), sh: fs(sh) }
175 }
176 #[inline]
180 pub fn convert_halves<NR: From<R>, NS: From<S>>(self) -> ReuniteError<NR, NS> {
181 self.map_halves(From::from, From::from)
182 }
183}
184impl<R, S> Display for ReuniteError<R, S> {
185 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
186 f.write_str("attempt to reunite stream halves that come from different streams")
187 }
188}
189impl<R: Debug, S: Debug> Error for ReuniteError<R, S> {}
190
191pub type ReuniteResult<T, R, S> = Result<T, ReuniteError<R, S>>;