11a0216d1Sopenharmony_ci//! io-lifetimes provides two different options for library authors
21a0216d1Sopenharmony_ci//! writing APIs which accept untyped I/O resources.
31a0216d1Sopenharmony_ci//!
41a0216d1Sopenharmony_ci//! The following uses the POSIX-ish `Fd` types; similar considerations
51a0216d1Sopenharmony_ci//! apply to the Windows and portable types.
61a0216d1Sopenharmony_ci
71a0216d1Sopenharmony_ci#[cfg(all(feature = "close", not(windows)))]
81a0216d1Sopenharmony_ciuse io_lifetimes::{AsFd, BorrowedFd, OwnedFd};
91a0216d1Sopenharmony_ci
101a0216d1Sopenharmony_ci/// The simplest way to accept a borrowed I/O resource is to simply use a
111a0216d1Sopenharmony_ci/// `BorrwedFd` as an argument. This doesn't require the function to have any
121a0216d1Sopenharmony_ci/// type parameters. It also works in FFI signatures, as `BorrowedFd` and (on
131a0216d1Sopenharmony_ci/// Rust >= 1.63) `Option<BorrowedFd>` are guaranteed to have the same layout
141a0216d1Sopenharmony_ci/// as `RawFd`.
151a0216d1Sopenharmony_ci///
161a0216d1Sopenharmony_ci/// Callers with an `AsFd`-implementing type would call `.as_fd()` and pass
171a0216d1Sopenharmony_ci/// the result.
181a0216d1Sopenharmony_ci#[cfg(all(feature = "close", not(windows)))]
191a0216d1Sopenharmony_cifn use_fd_a(fd: BorrowedFd<'_>) {
201a0216d1Sopenharmony_ci    let _ = fd;
211a0216d1Sopenharmony_ci}
221a0216d1Sopenharmony_ci
231a0216d1Sopenharmony_ci/// Another way to do this is to use an `AsFd` type parameter. This is more
241a0216d1Sopenharmony_ci/// verbose at the function definition site, and entails monomorphization, but
251a0216d1Sopenharmony_ci/// it has the advantage of allowing users to pass in any type implementing
261a0216d1Sopenharmony_ci/// `AsFd` directly, without having to call `.as_fd()` themselves.
271a0216d1Sopenharmony_ci#[cfg(all(feature = "close", not(windows)))]
281a0216d1Sopenharmony_cifn use_fd_b<Fd: AsFd>(fd: Fd) {
291a0216d1Sopenharmony_ci    let _ = fd.as_fd();
301a0216d1Sopenharmony_ci}
311a0216d1Sopenharmony_ci
321a0216d1Sopenharmony_ci/// Another way to do this is to use an `impl AsFd` parameter.
331a0216d1Sopenharmony_ci#[cfg(all(feature = "close", not(windows)))]
341a0216d1Sopenharmony_cifn use_fd_c(fd: impl AsFd) {
351a0216d1Sopenharmony_ci    let _ = fd.as_fd();
361a0216d1Sopenharmony_ci}
371a0216d1Sopenharmony_ci
381a0216d1Sopenharmony_ci/// The simplest way to accept a consumed I/O resource is to simply use an
391a0216d1Sopenharmony_ci/// `OwnedFd` as an argument. Similar to `use_fd_a`, this doesn't require the
401a0216d1Sopenharmony_ci/// function to have any type parameters, and also works in FFI signatures.
411a0216d1Sopenharmony_ci///
421a0216d1Sopenharmony_ci/// Callers with an `IntoFd`-implementing type would call `.into_fd()` and pass
431a0216d1Sopenharmony_ci/// the result.
441a0216d1Sopenharmony_ci#[cfg(all(feature = "close", not(windows)))]
451a0216d1Sopenharmony_cifn consume_fd_a(fd: OwnedFd) {
461a0216d1Sopenharmony_ci    let _ = fd;
471a0216d1Sopenharmony_ci}
481a0216d1Sopenharmony_ci
491a0216d1Sopenharmony_ci/// Another way to do this is to use an `IntoFd` type parameter. Similar to
501a0216d1Sopenharmony_ci/// `use_fd_b`, this is more verbose here and entails monomorphization, but it
511a0216d1Sopenharmony_ci/// has the advantage of allowing users to pass in any type implementing
521a0216d1Sopenharmony_ci/// `IntoFd` directly.
531a0216d1Sopenharmony_ci#[cfg(all(feature = "close", not(windows)))]
541a0216d1Sopenharmony_cifn consume_fd_b<Fd: Into<OwnedFd>>(fd: Fd) {
551a0216d1Sopenharmony_ci    let _: OwnedFd = fd.into();
561a0216d1Sopenharmony_ci}
571a0216d1Sopenharmony_ci
581a0216d1Sopenharmony_ci/// Another way to do this is to use an `impl IntoFd` parameter.
591a0216d1Sopenharmony_ci#[cfg(all(feature = "close", not(windows)))]
601a0216d1Sopenharmony_cifn consume_fd_c(fd: impl Into<OwnedFd>) {
611a0216d1Sopenharmony_ci    let _: OwnedFd = fd.into();
621a0216d1Sopenharmony_ci}
631a0216d1Sopenharmony_ci
641a0216d1Sopenharmony_ci/// Now let's see how the APIs look for users.
651a0216d1Sopenharmony_ci#[cfg(all(feature = "close", not(windows)))]
661a0216d1Sopenharmony_cifn main() {
671a0216d1Sopenharmony_ci    let f = std::fs::File::open("Cargo.toml").unwrap();
681a0216d1Sopenharmony_ci
691a0216d1Sopenharmony_ci    // The simple option requires an `.as_fd()` at the callsite.
701a0216d1Sopenharmony_ci    use_fd_a(f.as_fd());
711a0216d1Sopenharmony_ci
721a0216d1Sopenharmony_ci    // Another option can take a reference to any owning type directly.
731a0216d1Sopenharmony_ci    use_fd_b(&f);
741a0216d1Sopenharmony_ci
751a0216d1Sopenharmony_ci    // Of course, users can still pass in `BorrowedFd` values if they want to.
761a0216d1Sopenharmony_ci    use_fd_b(f.as_fd());
771a0216d1Sopenharmony_ci
781a0216d1Sopenharmony_ci    // The other option is `impl AsFd`.
791a0216d1Sopenharmony_ci    use_fd_c(&f);
801a0216d1Sopenharmony_ci
811a0216d1Sopenharmony_ci    // Users can still pass in `BorrowedFd` values if they want to here too.
821a0216d1Sopenharmony_ci    use_fd_c(f.as_fd());
831a0216d1Sopenharmony_ci
841a0216d1Sopenharmony_ci    let a = std::fs::File::open("Cargo.toml").unwrap();
851a0216d1Sopenharmony_ci    let b = std::fs::File::open("Cargo.toml").unwrap();
861a0216d1Sopenharmony_ci    let c = std::fs::File::open("Cargo.toml").unwrap();
871a0216d1Sopenharmony_ci
881a0216d1Sopenharmony_ci    // The simple option requires an `.into()` at the callsite.
891a0216d1Sopenharmony_ci    consume_fd_a(a.into());
901a0216d1Sopenharmony_ci
911a0216d1Sopenharmony_ci    // Another option can take any `Into<OwnedFd>` type directly.
921a0216d1Sopenharmony_ci    consume_fd_b(b);
931a0216d1Sopenharmony_ci
941a0216d1Sopenharmony_ci    // The other option can take any `Into<OwnedFd>` type directly.
951a0216d1Sopenharmony_ci    consume_fd_c(c);
961a0216d1Sopenharmony_ci}
971a0216d1Sopenharmony_ci
981a0216d1Sopenharmony_ci#[cfg(windows)]
991a0216d1Sopenharmony_cifn main() {
1001a0216d1Sopenharmony_ci    println!("This example uses non-Windows APIs.");
1011a0216d1Sopenharmony_ci}
1021a0216d1Sopenharmony_ci
1031a0216d1Sopenharmony_ci#[cfg(all(not(feature = "close"), not(windows)))]
1041a0216d1Sopenharmony_cifn main() {
1051a0216d1Sopenharmony_ci    println!("This example requires the \"close\" feature.");
1061a0216d1Sopenharmony_ci}
107