11a0216d1Sopenharmony_ci<div align="center">
21a0216d1Sopenharmony_ci  <h1><code>io-lifetimes</code></h1>
31a0216d1Sopenharmony_ci
41a0216d1Sopenharmony_ci  <p>
51a0216d1Sopenharmony_ci    <strong>A low-level I/O ownership and borrowing library</strong>
61a0216d1Sopenharmony_ci  </p>
71a0216d1Sopenharmony_ci
81a0216d1Sopenharmony_ci  <p>
91a0216d1Sopenharmony_ci    <a href="https://github.com/sunfishcode/io-lifetimes/actions?query=workflow%3ACI"><img src="https://github.com/sunfishcode/io-lifetimes/workflows/CI/badge.svg" alt="Github Actions CI Status" /></a>
101a0216d1Sopenharmony_ci    <a href="https://crates.io/crates/io-lifetimes"><img src="https://img.shields.io/crates/v/io-lifetimes.svg" alt="crates.io page" /></a>
111a0216d1Sopenharmony_ci    <a href="https://docs.rs/io-lifetimes"><img src="https://docs.rs/io-lifetimes/badge.svg" alt="docs.rs docs" /></a>
121a0216d1Sopenharmony_ci  </p>
131a0216d1Sopenharmony_ci</div>
141a0216d1Sopenharmony_ci
151a0216d1Sopenharmony_ciThis library introduces `OwnedFd`, `BorrowedFd`, and supporting types and
161a0216d1Sopenharmony_citraits, and corresponding features for Windows, which implement safe owning
171a0216d1Sopenharmony_ciand borrowing I/O lifetime patterns.
181a0216d1Sopenharmony_ci
191a0216d1Sopenharmony_ciThis is associated with [RFC 3128], the I/O Safety RFC, which is now merged.
201a0216d1Sopenharmony_ciWork is now underway to move the `OwnedFd` and `BorrowedFd` types and `AsFd`
211a0216d1Sopenharmony_citrait developed here into `std`.
221a0216d1Sopenharmony_ci
231a0216d1Sopenharmony_ciFor a quick taste, check out the code examples:
241a0216d1Sopenharmony_ci
251a0216d1Sopenharmony_ci - [hello], a basic demo of this API, doing low-level I/O manually, using the
261a0216d1Sopenharmony_ci   [provided example FFI bindings]
271a0216d1Sopenharmony_ci - [easy-conversions], demonstrating the `from_into` convenience feature for
281a0216d1Sopenharmony_ci   converting from an `impl Into*` into an `impl From*`.
291a0216d1Sopenharmony_ci - [portable-views], demonstrating the convenience feature which allows one
301a0216d1Sopenharmony_ci   to temporarily "view" a file descriptor as any owning type such as `File`
311a0216d1Sopenharmony_ci - [flexible-apis], demonstrating how to write library APIs that accept
321a0216d1Sopenharmony_ci   untyped I/O resources.
331a0216d1Sopenharmony_ci - [owning-wrapper], demonstrating how to implement a type which wraps an
341a0216d1Sopenharmony_ci   `Owned*` type.
351a0216d1Sopenharmony_ci
361a0216d1Sopenharmony_ci[hello]: https://github.com/sunfishcode/io-lifetimes/blob/main/examples/hello.rs
371a0216d1Sopenharmony_ci[easy-conversions]: https://github.com/sunfishcode/io-lifetimes/blob/main/examples/easy-conversions.rs
381a0216d1Sopenharmony_ci[portable-views]: https://github.com/sunfishcode/io-lifetimes/blob/main/examples/portable-views.rs
391a0216d1Sopenharmony_ci[flexible-apis]: https://github.com/sunfishcode/io-lifetimes/blob/main/examples/flexible-apis.rs
401a0216d1Sopenharmony_ci[owning-wrapper]: https://github.com/sunfishcode/io-lifetimes/blob/main/examples/owning-wrapper.rs
411a0216d1Sopenharmony_ci[provided example FFI bindings]: https://github.com/sunfishcode/io-lifetimes/blob/main/src/example_ffi.rs
421a0216d1Sopenharmony_ci
431a0216d1Sopenharmony_ciThe core of the API is very simple, and consists of two main types and three
441a0216d1Sopenharmony_cimain traits:
451a0216d1Sopenharmony_ci
461a0216d1Sopenharmony_ci```rust
471a0216d1Sopenharmony_cipub struct BorrowedFd<'fd> { ... }
481a0216d1Sopenharmony_cipub struct OwnedFd { ... }
491a0216d1Sopenharmony_ci
501a0216d1Sopenharmony_cipub trait AsFd { ... }
511a0216d1Sopenharmony_cipub trait IntoFd { ... }
521a0216d1Sopenharmony_cipub trait FromFd { ... }
531a0216d1Sopenharmony_ci
541a0216d1Sopenharmony_ciimpl AsRawFd for BorrowedFd<'_> { ... }
551a0216d1Sopenharmony_ciimpl AsRawFd for OwnedFd { ... }
561a0216d1Sopenharmony_ciimpl IntoRawFd for OwnedFd { ... }
571a0216d1Sopenharmony_ciimpl FromRawFd for OwnedFd { ... }
581a0216d1Sopenharmony_ci
591a0216d1Sopenharmony_ciimpl Drop for OwnedFd { ... }
601a0216d1Sopenharmony_ci
611a0216d1Sopenharmony_ciimpl AsFd for BorrowedFd<'_> { ... }
621a0216d1Sopenharmony_ciimpl AsFd for OwnedFd { ... }
631a0216d1Sopenharmony_ciimpl IntoFd for OwnedFd { ... }
641a0216d1Sopenharmony_ciimpl FromFd for OwnedFd { ... }
651a0216d1Sopenharmony_ci```
661a0216d1Sopenharmony_ci
671a0216d1Sopenharmony_ciOn Windows, there are `Handle` and `Socket` versions of every `Fd` thing, and
681a0216d1Sopenharmony_cia special `HandleOrInvalid` type to cope with inconsistent error reporting
691a0216d1Sopenharmony_ciin the Windows API.
701a0216d1Sopenharmony_ci
711a0216d1Sopenharmony_ci## The magic of transparency
721a0216d1Sopenharmony_ci
731a0216d1Sopenharmony_ciHere's the fun part. `BorrowedFd` and `OwnedFd` are `repr(transparent)` and
741a0216d1Sopenharmony_cihold `RawFd` values, and `Option<BorrowedFd>` and `Option<OwnedFd>` are
751a0216d1Sopenharmony_ciFFI-safe (on Rust >= 1.63), so they can all be used in FFI [directly]:
761a0216d1Sopenharmony_ci
771a0216d1Sopenharmony_ci[directly]: https://github.com/sunfishcode/io-lifetimes/blob/main/src/example_ffi.rs
781a0216d1Sopenharmony_ci
791a0216d1Sopenharmony_ci```rust
801a0216d1Sopenharmony_ciextern "C" {
811a0216d1Sopenharmony_ci    pub fn open(pathname: *const c_char, flags: c_int, ...) -> Option<OwnedFd>;
821a0216d1Sopenharmony_ci    pub fn read(fd: BorrowedFd<'_>, ptr: *mut c_void, size: size_t) -> ssize_t;
831a0216d1Sopenharmony_ci    pub fn write(fd: BorrowedFd<'_>, ptr: *const c_void, size: size_t) -> ssize_t;
841a0216d1Sopenharmony_ci    pub fn close(fd: OwnedFd) -> c_int;
851a0216d1Sopenharmony_ci}
861a0216d1Sopenharmony_ci```
871a0216d1Sopenharmony_ci
881a0216d1Sopenharmony_ciWith bindings like this, users never have to touch `RawFd` values. Of course,
891a0216d1Sopenharmony_cinot all code will do this, but it is a fun feature for code that can. This
901a0216d1Sopenharmony_ciis what motivates having `BorrowedFd` instead of just using `&OwnedFd`.
911a0216d1Sopenharmony_ci
921a0216d1Sopenharmony_ciNote the use of `Option<OwnedFd>` as the return value of `open`, representing
931a0216d1Sopenharmony_cithe fact that it can either succeed or fail.
941a0216d1Sopenharmony_ci
951a0216d1Sopenharmony_ci## I/O Safety in Rust
961a0216d1Sopenharmony_ci
971a0216d1Sopenharmony_ciI/O Safety feature is stablized in Rust 1.63. With this version or later,
981a0216d1Sopenharmony_ciio-lifetimes will use and re-export the standard-library types and traits. With
991a0216d1Sopenharmony_ciolder versions, io-lifetimes defines its own copy of these types and traits.
1001a0216d1Sopenharmony_ci
1011a0216d1Sopenharmony_ciio-lifetimes also includes several features which are not (yet?) in std,
1021a0216d1Sopenharmony_ciincluding the portability traits `AsFilelike`/`AsSocketlike`/etc., the
1031a0216d1Sopenharmony_ci`from_into_*` functions in the `From*` traits, and [views].
1041a0216d1Sopenharmony_ci
1051a0216d1Sopenharmony_ci[views]: https://docs.rs/io-lifetimes/*/io_lifetimes/views/index.html
1061a0216d1Sopenharmony_ci
1071a0216d1Sopenharmony_ci## Prior Art
1081a0216d1Sopenharmony_ci
1091a0216d1Sopenharmony_ciThere are several similar crates: [fd](https://crates.io/crates/fd),
1101a0216d1Sopenharmony_ci[filedesc](https://crates.io/crates/filedesc),
1111a0216d1Sopenharmony_ci[filedescriptor](https://crates.io/crates/filedescriptor),
1121a0216d1Sopenharmony_ci[owned-fd](https://crates.io/crates/owned-fd), and
1131a0216d1Sopenharmony_ci[unsafe-io](https://crates.io/crates/unsafe-io).
1141a0216d1Sopenharmony_ci
1151a0216d1Sopenharmony_ciSome of these provide additional features such as the ability to create pipes
1161a0216d1Sopenharmony_cior sockets, to get and set flags, and to do read and write operations.
1171a0216d1Sopenharmony_ciio-lifetimes omits these features, leaving them to to be provided as separate
1181a0216d1Sopenharmony_cilayers on top.
1191a0216d1Sopenharmony_ci
1201a0216d1Sopenharmony_ciMost of these crates provide ways to duplicate a file descriptor. io-lifetimes
1211a0216d1Sopenharmony_cicurrently treats this as another feature that can be provided by a layer on
1221a0216d1Sopenharmony_citop, though if there are use cases where this is a common operation, it could
1231a0216d1Sopenharmony_cibe added.
1241a0216d1Sopenharmony_ci
1251a0216d1Sopenharmony_ciio-lifetimes's distinguishing features are its use of `repr(transparent)`
1261a0216d1Sopenharmony_cito support direct FFI usage, niche optimizations so `Option` can support direct
1271a0216d1Sopenharmony_ciFFI usafe as well (on Rust >= 1.63), lifetime-aware `As*`/`Into*`/`From*`
1281a0216d1Sopenharmony_citraits which leverage Rust's lifetime system and allow safe and checked
1291a0216d1Sopenharmony_ci`from_*` and `as_*`/`into_*` functions, and powerful convenience features
1301a0216d1Sopenharmony_cienabled by its underlying safety.
1311a0216d1Sopenharmony_ci
1321a0216d1Sopenharmony_ciio-lifetimes also has full Windows support, as well as Unix/Windows
1331a0216d1Sopenharmony_ciportability abstractions, covering both file-like and socket-like types.
1341a0216d1Sopenharmony_ci
1351a0216d1Sopenharmony_ciio-lifetimes's [`OwnedFd`] type is similar to
1361a0216d1Sopenharmony_ci[fd](https://crates.io/crates/fd)'s
1371a0216d1Sopenharmony_ci[`FileDesc`](https://docs.rs/fd/0.2.3/fd/struct.FileDesc.html). io-lifetimes
1381a0216d1Sopenharmony_cidoesn't have a `close_on_drop` parameter, and instead uses [`OwnedFd`] and
1391a0216d1Sopenharmony_ci[`BorrowedFd`] to represent dropping and non-dropping handles, respectively, in
1401a0216d1Sopenharmony_cia way that is checked at compile time rather than runtime.
1411a0216d1Sopenharmony_ci
1421a0216d1Sopenharmony_ciio-lifetimes's [`OwnedFd`] type is also similar to
1431a0216d1Sopenharmony_ci[filedesc](https://crates.io/crates/filedesc)'s
1441a0216d1Sopenharmony_ci[`FileDesc`](https://docs.rs/filedesc/0.3.0/filedesc/struct.FileDesc.html)
1451a0216d1Sopenharmony_ciio-lifetimes's `OwnedFd` reserves the value -1, so it doesn't need to test for
1461a0216d1Sopenharmony_ci`-1` in its `Drop`, and `Option<OwnedFd>` (on Rust >= 1.63) is the same size
1471a0216d1Sopenharmony_cias `FileDesc`.
1481a0216d1Sopenharmony_ci
1491a0216d1Sopenharmony_ciio-lifetimes's [`OwnedFd`] type is also similar to
1501a0216d1Sopenharmony_ci[owned-fd](https://crates.io/crates/owned-fd)'s
1511a0216d1Sopenharmony_ci[`OwnedFd`](https://docs.rs/owned-fd/0.1.0/owned_fd/struct.OwnedFd.html).
1521a0216d1Sopenharmony_ciio-lifetimes doesn't implement `Clone`, because duplicating a file descriptor
1531a0216d1Sopenharmony_cican fail due to OS process limits, while `Clone` is an infallible interface.
1541a0216d1Sopenharmony_ci
1551a0216d1Sopenharmony_ciio-lifetimes's [`BorrowedFd`] is similar to
1561a0216d1Sopenharmony_ci[owned-fd](https://crates.io/crates/owned-fd)'s
1571a0216d1Sopenharmony_ci[`FdRef`](https://docs.rs/owned-fd/0.1.0/owned_fd/struct.FdRef.html), except it
1581a0216d1Sopenharmony_ciuses a lifetime parameter and `PhantomData` rather than transmuting a raw file
1591a0216d1Sopenharmony_cidescriptor value into a reference value.
1601a0216d1Sopenharmony_ci
1611a0216d1Sopenharmony_ciio-lifetimes's convenience features are similar to those of
1621a0216d1Sopenharmony_ci[unsafe-io](https://crates.io/crates/unsafe-io), but io-lifetimes is built on
1631a0216d1Sopenharmony_ciits own `As*`/`Into*`/`From*` traits, rather than extending
1641a0216d1Sopenharmony_ci`AsRaw*`/`IntoRaw*`/`FromRaw*` with
1651a0216d1Sopenharmony_ci[`OwnsRaw`](https://docs.rs/unsafe-io/0.6.9/unsafe_io/trait.OwnsRaw.html), so
1661a0216d1Sopenharmony_cithey're simpler and safer to use. io-lifetimes doesn't include unsafe-io's
1671a0216d1Sopenharmony_ci`*ReadWrite*` or `*HandleOrSocket*` abstractions, and leaves these as features
1681a0216d1Sopenharmony_cito be provided by separate layers on top.
1691a0216d1Sopenharmony_ci
1701a0216d1Sopenharmony_ci## Minimum Supported Rust Version (MSRV)
1711a0216d1Sopenharmony_ci
1721a0216d1Sopenharmony_ciThis crate currently works on the version of [Rust on Debian stable], which is
1731a0216d1Sopenharmony_cicurrently Rust 1.48. This policy may change in the future, in minor version
1741a0216d1Sopenharmony_cireleases, so users using a fixed version of Rust should pin to a specific
1751a0216d1Sopenharmony_civersion of this crate.
1761a0216d1Sopenharmony_ci
1771a0216d1Sopenharmony_ci[`OwnedFd`]: https://doc.rust-lang.org/stable/std/os/unix/io/struct.OwnedFd.html
1781a0216d1Sopenharmony_ci[`BorrowedFd`]: https://doc.rust-lang.org/stable/std/os/unix/io/struct.BorrowedFd.html
1791a0216d1Sopenharmony_ci[RFC 3128]: https://github.com/rust-lang/rfcs/blob/master/text/3128-io-safety.md
180