Skip to content

windows-result: unwrap FACILITY_WIN32 HRESULTs when converting to std::io::Error#4448

Draft
Copilot wants to merge 3 commits into
masterfrom
copilot/review-issue-4433
Draft

windows-result: unwrap FACILITY_WIN32 HRESULTs when converting to std::io::Error#4448
Copilot wants to merge 3 commits into
masterfrom
copilot/review-issue-4433

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 20, 2026

The From<Error> for std::io::Error impl in windows-result previously stored the full HRESULT into from_raw_os_error. Because Rust's std::io::Error::kind() on Windows decodes raw OS errors as Win32 error codes (small values), passing a full HRESULT meant ErrorKind for every Win32-origin error fell through to Uncategorized, defeating pattern matching.

This change unwraps HRESULTs whose facility is FACILITY_WIN32 into their underlying Win32 code via the existing WIN32_ERROR::from_error helper, while preserving the full HRESULT unchanged for HRESULTs from other facilities (E_FAIL, E_NOTIMPL, RPC/COM/custom facilities). This mirrors the conventions used by .NET's Marshal.GetExceptionForHR and Rust's own internal Win32 error decoding (option 2 from the issue discussion).

Tests

Updated crates/tests/misc/error/tests/std.rs to cover:

  • ERROR_FILE_NOT_FOUNDErrorKind::NotFound
  • E_INVALIDARG (which is HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)) unwraps to 87 → ErrorKind::InvalidInput
  • ERROR_INVALID_DATA unwraps to its Win32 code (13) and formats with the expected message (no ErrorKind assertion, since Rust's std maps code 13 to Uncategorized)
  • E_NOTIMPL, E_FAIL (non-FACILITY_WIN32) preserve the full HRESULT
  • Round-trip ERROR_INVALID_DATAstd::io::Errorwindows::core::Error is information-preserving

Note on behavior change

This is a behavioral change to a public From impl: HRESULTs with FACILITY_WIN32 now surface as their underlying Win32 code in std::io::Error::raw_os_error() rather than the full HRESULT. This is the explicit goal — to make ErrorKind matching work — but it affects existing users that read raw_os_error() expecting the full HRESULT. Non-FACILITY_WIN32 HRESULTs are unaffected.

@kennykerr
Copy link
Copy Markdown
Collaborator

@copilot fix test failure

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 20, 2026

@copilot fix test failure

Fixed in cb52490. The arm64 Windows test was failing on assert_eq!(std_error.kind(), ErrorKind::InvalidData) for ERROR_INVALID_DATA (13) — Rust's std doesn't map that code to InvalidData (it falls through to Uncategorized). Removed that assertion; the NotFound and InvalidInput checks remain since those codes are decoded by Rust's std.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adjusts windows-result’s From<windows::core::Error> for std::io::Error conversion so Win32-origin HRESULTs map to Win32 error codes in raw_os_error(), enabling meaningful std::io::Error::kind() matching on Windows.

Changes:

  • Unwrap FACILITY_WIN32 HRESULTs to the underlying Win32 error code when converting Error -> std::io::Error.
  • Extend tests to validate ErrorKind mapping for common Win32 codes and preserve non-Win32 HRESULT behavior.
  • Add a round-trip test to ensure Win32 HRESULT information remains recoverable via std::io::Error -> windows::core::Error.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
crates/libs/result/src/error.rs Updates From<Error> for std::io::Error to unwrap FACILITY_WIN32 HRESULTs to Win32 codes.
crates/tests/misc/error/tests/std.rs Updates and expands conversion tests to cover ErrorKind decoding and round-trips.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +163 to +172
// If the HRESULT wraps a Win32 error (FACILITY_WIN32), unwrap it to the
// underlying Win32 error code so that `std::io::Error::kind` can decode
// it into a meaningful `ErrorKind`. For HRESULTs from other facilities
// (such as COM `E_*` codes or custom facilities), preserve the full
// HRESULT value to avoid losing information. This mirrors the behavior
// of .NET's `Marshal.GetExceptionForHR` and the conventions used by
// Rust's own Win32 error decoding.
if let Some(win32) = WIN32_ERROR::from_error(&from) {
Self::from_raw_os_error(win32.0 as i32)
} else {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants