• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! io-lifetimes provides two different options for library authors
2 //! writing APIs which accept untyped I/O resources.
3 //!
4 //! The following uses the POSIX-ish `Fd` types; similar considerations
5 //! apply to the Windows and portable types.
6 
7 #[cfg(all(feature = "close", not(windows)))]
8 use io_lifetimes::{AsFd, BorrowedFd, OwnedFd};
9 
10 /// The simplest way to accept a borrowed I/O resource is to simply use a
11 /// `BorrwedFd` as an argument. This doesn't require the function to have any
12 /// type parameters. It also works in FFI signatures, as `BorrowedFd` and (on
13 /// Rust >= 1.63) `Option<BorrowedFd>` are guaranteed to have the same layout
14 /// as `RawFd`.
15 ///
16 /// Callers with an `AsFd`-implementing type would call `.as_fd()` and pass
17 /// the result.
18 #[cfg(all(feature = "close", not(windows)))]
use_fd_a(fd: BorrowedFd<'_>)19 fn use_fd_a(fd: BorrowedFd<'_>) {
20     let _ = fd;
21 }
22 
23 /// Another way to do this is to use an `AsFd` type parameter. This is more
24 /// verbose at the function definition site, and entails monomorphization, but
25 /// it has the advantage of allowing users to pass in any type implementing
26 /// `AsFd` directly, without having to call `.as_fd()` themselves.
27 #[cfg(all(feature = "close", not(windows)))]
use_fd_b<Fd: AsFd>(fd: Fd)28 fn use_fd_b<Fd: AsFd>(fd: Fd) {
29     let _ = fd.as_fd();
30 }
31 
32 /// Another way to do this is to use an `impl AsFd` parameter.
33 #[cfg(all(feature = "close", not(windows)))]
use_fd_c(fd: impl AsFd)34 fn use_fd_c(fd: impl AsFd) {
35     let _ = fd.as_fd();
36 }
37 
38 /// The simplest way to accept a consumed I/O resource is to simply use an
39 /// `OwnedFd` as an argument. Similar to `use_fd_a`, this doesn't require the
40 /// function to have any type parameters, and also works in FFI signatures.
41 ///
42 /// Callers with an `IntoFd`-implementing type would call `.into_fd()` and pass
43 /// the result.
44 #[cfg(all(feature = "close", not(windows)))]
consume_fd_a(fd: OwnedFd)45 fn consume_fd_a(fd: OwnedFd) {
46     let _ = fd;
47 }
48 
49 /// Another way to do this is to use an `IntoFd` type parameter. Similar to
50 /// `use_fd_b`, this is more verbose here and entails monomorphization, but it
51 /// has the advantage of allowing users to pass in any type implementing
52 /// `IntoFd` directly.
53 #[cfg(all(feature = "close", not(windows)))]
consume_fd_b<Fd: Into<OwnedFd>>(fd: Fd)54 fn consume_fd_b<Fd: Into<OwnedFd>>(fd: Fd) {
55     let _: OwnedFd = fd.into();
56 }
57 
58 /// Another way to do this is to use an `impl IntoFd` parameter.
59 #[cfg(all(feature = "close", not(windows)))]
consume_fd_c(fd: impl Into<OwnedFd>)60 fn consume_fd_c(fd: impl Into<OwnedFd>) {
61     let _: OwnedFd = fd.into();
62 }
63 
64 /// Now let's see how the APIs look for users.
65 #[cfg(all(feature = "close", not(windows)))]
main()66 fn main() {
67     let f = std::fs::File::open("Cargo.toml").unwrap();
68 
69     // The simple option requires an `.as_fd()` at the callsite.
70     use_fd_a(f.as_fd());
71 
72     // Another option can take a reference to any owning type directly.
73     use_fd_b(&f);
74 
75     // Of course, users can still pass in `BorrowedFd` values if they want to.
76     use_fd_b(f.as_fd());
77 
78     // The other option is `impl AsFd`.
79     use_fd_c(&f);
80 
81     // Users can still pass in `BorrowedFd` values if they want to here too.
82     use_fd_c(f.as_fd());
83 
84     let a = std::fs::File::open("Cargo.toml").unwrap();
85     let b = std::fs::File::open("Cargo.toml").unwrap();
86     let c = std::fs::File::open("Cargo.toml").unwrap();
87 
88     // The simple option requires an `.into()` at the callsite.
89     consume_fd_a(a.into());
90 
91     // Another option can take any `Into<OwnedFd>` type directly.
92     consume_fd_b(b);
93 
94     // The other option can take any `Into<OwnedFd>` type directly.
95     consume_fd_c(c);
96 }
97 
98 #[cfg(windows)]
main()99 fn main() {
100     println!("This example uses non-Windows APIs.");
101 }
102 
103 #[cfg(all(not(feature = "close"), not(windows)))]
main()104 fn main() {
105     println!("This example requires the \"close\" feature.");
106 }
107