This library introduces
BorrowedFd, and supporting types and
traits, and corresponding features for Windows, which implement safe owning
and borrowing I/O lifetime patterns.
This is associated with RFC 3128, the I/O Safety RFC, which is now merged.
Work is now underway to move the
BorrowedFd types and
trait developed here into
Some features currently require nightly Rust, as they depend on
to perform niche optimizations needed for FFI use cases.
For a quick taste, check out the code examples:
- hello, a basic demo of this API, doing low-level I/O manually, using the provided example FFI bindings
- easy-conversions, demonstrating the
from_intoconvenience feature for converting from an
impl Into*into an
- portable-views, demonstrating the convenience feature which allows one
to temporarily "view" a file descriptor as any owning type such as
- flexible-apis, demonstrating how to write library APIs that accept untyped I/O resources.
- owning-wrapper, demonstrating how to implement a type which wraps an
The core of the API is very simple, and consists of two main types and three main traits:
On Windows, there are
Socket versions of every
Fd thing, and
HandleOrInvalid type to cope with inconsistent error reporting
in the Windows API.
The magic of transparency
Here's the fun part.
RawFd values, and
FFI-safe (on nightly Rust), so they can all be used in FFI directly:
With bindings like this, users never have to touch
RawFd values. Of course,
not all code will do this, but it is a fun feature for code that can. This
is what motivates having
BorrowedFd instead of just using
Note the use of
Option<OwnedFd> as the return value of
the fact that it can either succeed or fail.
I/O Safety in Rust Nightly
The I/O Safety
implementation PR has now
landed and is available on Rust Nightly. It can be used directly, or through
io_lifetimes_use_std mode is enabled, io-lifetimes uses
AsFd instead of defining its own.
- Set the environment variable
#![cfg_attr(io_lifetimes_use_std, feature(io_safety))]to your lib.rs or main.rs.
Note that, unfortunately,
io_lifetimes_use_std mode doesn't support the
optional impls for third-party crates.
The code in
Into<OwnedFd> instead of
IntoFd. io-lifetimes is unable to provide impls for these for third-party
types, so it continues to provide
IntoFd for now, with default
impls that forward to
io-lifetimes also includes several features which are not (yet?) in std,
including the portability traits
from_into_* functions in the
From* traits, and views.
If you test a crate with the std I/O safety types and traits, or io-lifetimes
io_lifetimes_use_std mode, please post a note about it in the
I/O safety tracking issue as an example of usage.
Some of these provide additional features such as the ability to create pipes or sockets, to get and set flags, and to do read and write operations. io-lifetimes omits these features, leaving them to to be provided as separate layers on top.
Most of these crates provide ways to duplicate a file descriptor. io-lifetimes currently treats this as another feature that can be provided by a layer on top, though if there are use cases where this is a common operation, it could be added.
io-lifetimes's distinguishing features are its use of
to support direct FFI usage, niche optimizations so
Option can support direct
FFI usafe as well (on nightly Rust), lifetime-aware
traits which leverage Rust's lifetime system and allow safe and checked
into_* functions, and powerful convenience features
enabled by its underlying safety.
io-lifetimes also has full Windows support, as well as Unix/Windows portability abstractions, covering both file-like and socket-like types.
OwnedFd type is similar to
doesn't have a
close_on_drop parameter, and instead uses
BorrowedFd to represent dropping and non-dropping handles, respectively, in
a way that is checked at compile time rather than runtime.
OwnedFd type is also similar to
OwnedFd reserves the value -1, so it doesn't need to test for
-1 in its
Option<OwnedFd> (on nightly Rust) is the same size
OwnedFd type is also similar to
io-lifetimes doesn't implement
Clone, because duplicating a file descriptor
can fail due to OS process limits, while
Clone is an infallible interface.
io-lifetimes's convenience features are similar to those of
unsafe-io, but io-lifetimes is built on
From* traits, rather than extending
they're simpler and safer to use. io-lifetimes doesn't include unsafe-io's
*HandleOrSocket* abstractions, and leaves these as features
to be provided by separate layers on top.