mirror of https://github.com/smol-rs/polling
feat(windows): AFD failure now sources underlying I/O error
Previously, if AFD failed to initialize `polling` would return a custom I/O error with a string error, containing the formatted version of the underlying system error. However, this means that information about the underlying system error is lost to the user. This commit makes it so the returned `io::Error` wraps a user inaccessible type: `AfdError`. This `AfdError`, when stringified, returns a similar error message as what was previously returned. In addition when `.source()` is used it returns the underlying system error. Closes #174 Signed-off-by: John Nunley <dev@notgull.net>
This commit is contained in:
parent
1f13664bbb
commit
ea5a38a500
|
@ -121,17 +121,19 @@ impl Poller {
|
|||
pub(super) fn new() -> io::Result<Self> {
|
||||
// Make sure AFD is able to be used.
|
||||
if let Err(e) = afd::NtdllImports::force_load() {
|
||||
return Err(crate::unsupported_error(format!(
|
||||
"Failed to initialize unstable Windows functions: {}\nThis usually only happens for old Windows or Wine.",
|
||||
e
|
||||
)));
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Unsupported,
|
||||
AfdError::new("failed to initialize unstable Windows functions", e),
|
||||
));
|
||||
}
|
||||
|
||||
// Create and destroy a single AFD to test if we support it.
|
||||
Afd::<Packet>::new().map_err(|e| crate::unsupported_error(format!(
|
||||
"Failed to initialize \\Device\\Afd: {}\nThis usually only happens for old Windows or Wine.",
|
||||
e,
|
||||
)))?;
|
||||
Afd::<Packet>::new().map_err(|e| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Unsupported,
|
||||
AfdError::new("failed to initialize \\Device\\Afd", e),
|
||||
)
|
||||
})?;
|
||||
|
||||
let port = IoCompletionPort::new(0)?;
|
||||
tracing::trace!(handle = ?port, "new");
|
||||
|
@ -1326,6 +1328,54 @@ fn dur2timeout(dur: Duration) -> u32 {
|
|||
.unwrap_or(INFINITE)
|
||||
}
|
||||
|
||||
/// An error type that wraps around failing to open AFD.
|
||||
struct AfdError {
|
||||
/// String description of what happened.
|
||||
description: &'static str,
|
||||
|
||||
/// The underlying system error.
|
||||
system: io::Error,
|
||||
}
|
||||
|
||||
impl AfdError {
|
||||
#[inline]
|
||||
fn new(description: &'static str, system: io::Error) -> Self {
|
||||
Self {
|
||||
description,
|
||||
system,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for AfdError {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("AfdError")
|
||||
.field("description", &self.description)
|
||||
.field("system", &self.system)
|
||||
.field("note", &"probably caused by old Windows or Wine")
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for AfdError {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}: {}\nThis error is usually caused by running on old Windows or Wine",
|
||||
self.description, &self.system
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for AfdError {
|
||||
#[inline]
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
Some(&self.system)
|
||||
}
|
||||
}
|
||||
|
||||
struct CallOnDrop<F: FnMut()>(F);
|
||||
|
||||
impl<F: FnMut()> Drop for CallOnDrop<F> {
|
||||
|
|
Loading…
Reference in New Issue