-
Notifications
You must be signed in to change notification settings - Fork 14k
Description
On Windows, the standard library's function for getting a stdio handle looks like this:
pub fn get_handle(handle_id: c::DWORD) -> io::Result<c::HANDLE> {
let handle = unsafe { c::GetStdHandle(handle_id) };
if handle == c::INVALID_HANDLE_VALUE {
Err(io::Error::last_os_error())
} else if handle.is_null() {
Err(io::Error::from_raw_os_error(c::ERROR_INVALID_HANDLE as i32))
} else {
Ok(handle)
}
}Note that it only returns a handle if one is set, otherwise it returns an error.
In contrast, the public AsRawHandle stdio implementation ignores errors returned by GetStdHandle and just uses the returned value, whatever that may be.
impl AsRawHandle for io::Stdin {
fn as_raw_handle(&self) -> RawHandle {
unsafe { c::GetStdHandle(c::STD_INPUT_HANDLE) as RawHandle }
}
}
// ...and similar for `Stdout` and `Stdin`.The Safe I/O RFC introduced new types for managing handles. The AsHandle trait is intended to be a drop in replacement for the old AsRawHandle trait but returns a BorrowedHandle instead of a RawHandle.
I personally don't think AsHandle should be implemented for stdio types. Instead a function with a signature similar to this should be implemented:
fn try_as_handle(&self) -> io::Result<BorrowedHandle<'_>>;It would work similarly to the internal get_handle function in that it will return an error if there is no handle to return.
Reasons for a try_as_handle() function instead of implementing AsHandle on stdio types:
- The error is surfaced at its origin.
- It gives users the correct mental model when thinking about Windows' stdio (especially since it differs from Unix).
- A
BorrowedHandleshould be what the name implies: a borrow of a handle. It should not be an error sentinel value (which may overlap with an actual handle value).
Reasons not to do this:
- Using a null or
INVALID_HANDLE_VALUEwill probably lead to an error in any case so it's unclear how much of an issue this is in practice. - It makes it harder to update code if
AsRawHandleandAsHandlearen't implemented for all the same types. - Given the above, is changing this really worth the trade-off?
See also: I/O Safety Tracking Issue (#87074) and a previous discussion on internals.