diff --git a/src/iocp/mod.rs b/src/iocp/mod.rs index 3800a2c..5168e76 100644 --- a/src/iocp/mod.rs +++ b/src/iocp/mod.rs @@ -121,17 +121,19 @@ impl Poller { pub(super) fn new() -> io::Result { // 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::::new().map_err(|e| crate::unsupported_error(format!( - "Failed to initialize \\Device\\Afd: {}\nThis usually only happens for old Windows or Wine.", - e, - )))?; + Afd::::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); impl Drop for CallOnDrop {