1//! A simple example implementing the main traits for a type.
2
3#[cfg(not(windows))]
4#[cfg(any(feature = "close", not(io_safety_is_in_std)))]
5use io_lifetimes::FromFd;
6#[cfg(windows)]
7#[cfg(any(feature = "close", not(io_safety_is_in_std)))]
8use io_lifetimes::FromHandle;
9#[cfg(not(windows))]
10#[cfg(not(io_safety_is_in_std))]
11use io_lifetimes::IntoFd;
12#[cfg(windows)]
13#[cfg(not(io_safety_is_in_std))]
14use io_lifetimes::IntoHandle;
15use io_lifetimes::OwnedFilelike;
16#[cfg(not(windows))]
17use io_lifetimes::{AsFd, BorrowedFd, OwnedFd};
18#[cfg(windows)]
19use io_lifetimes::{AsHandle, BorrowedHandle, OwnedHandle};
20
21/// A wrapper around a file descriptor.
22///
23/// Implementing `AsFd`, `IntoFd`, and `FromFd` for a type that wraps an
24/// `Owned*` is straightforward. `Owned*` types also automatically close the
25/// handle in its `Drop`.
26///
27/// Should owning wrappers implement `AsRawFd`, `IntoRawFd`, and `FromRawFd`
28/// too? They can, and there's no need to remove them from a type that already
29/// implements them. But for new code, they can be omitted. Users that really
30/// need the raw value can always do `as_fd().as_raw_fd()`,
31/// `.into_fd().into_raw_fd()`, or `T::from_fd(OwnedFd::from_raw_fd(raw_fd))`.
32/// But if possible, users should use just `as_fd`, `into_fd`, and `from_fd`
33/// and avoid working with raw values altogether.
34struct Thing {
35    filelike: OwnedFilelike,
36}
37
38#[cfg(not(windows))]
39impl AsFd for Thing {
40    #[inline]
41    fn as_fd(&self) -> BorrowedFd<'_> {
42        self.filelike.as_fd()
43    }
44}
45
46#[cfg(not(io_safety_is_in_std))]
47#[cfg(not(windows))]
48impl IntoFd for Thing {
49    #[inline]
50    fn into_fd(self) -> OwnedFd {
51        self.filelike
52    }
53}
54
55#[cfg(not(windows))]
56impl From<Thing> for OwnedFd {
57    #[inline]
58    fn from(owned: Thing) -> Self {
59        owned.filelike
60    }
61}
62
63#[cfg(not(io_safety_is_in_std))]
64#[cfg(not(windows))]
65impl FromFd for Thing {
66    #[inline]
67    fn from_fd(filelike: OwnedFd) -> Self {
68        Self { filelike }
69    }
70}
71
72#[cfg(not(windows))]
73impl From<OwnedFd> for Thing {
74    #[inline]
75    fn from(filelike: OwnedFd) -> Self {
76        Self { filelike }
77    }
78}
79
80#[cfg(windows)]
81impl AsHandle for Thing {
82    #[inline]
83    fn as_handle(&self) -> BorrowedHandle<'_> {
84        self.filelike.as_handle()
85    }
86}
87
88#[cfg(not(io_safety_is_in_std))]
89#[cfg(windows)]
90impl IntoHandle for Thing {
91    #[inline]
92    fn into_handle(self) -> OwnedHandle {
93        self.filelike
94    }
95}
96
97#[cfg(windows)]
98impl From<Thing> for OwnedHandle {
99    #[inline]
100    fn from(owned: Thing) -> Self {
101        owned.filelike
102    }
103}
104
105#[cfg(not(io_safety_is_in_std))]
106#[cfg(windows)]
107impl FromHandle for Thing {
108    #[inline]
109    fn from_handle(filelike: OwnedHandle) -> Self {
110        Self { filelike }
111    }
112}
113
114#[cfg(windows)]
115impl From<OwnedHandle> for Thing {
116    #[inline]
117    fn from(filelike: OwnedHandle) -> Self {
118        Self { filelike }
119    }
120}
121
122#[cfg(feature = "close")]
123fn main() {
124    use io_lifetimes::{AsFilelike, FromFilelike, IntoFilelike};
125
126    // Minimally exercise `Thing`'s Posix-ish API.
127    #[cfg(not(windows))]
128    {
129        let file = std::fs::File::open("Cargo.toml").unwrap();
130        let thing = Thing::from_into_fd(file);
131        let _ = thing.as_fd();
132        let _: OwnedFd = thing.into();
133    }
134
135    // Minimally exercise `Thing`'s Windows API.
136    #[cfg(windows)]
137    {
138        let file = std::fs::File::open("Cargo.toml").unwrap();
139        let thing = Thing::from_into_handle(file);
140        let _ = thing.as_handle();
141        let _: OwnedHandle = thing.into();
142    }
143
144    // Implementing the above traits makes the blanket impls for the portable
145    // `Filelike` traits available too.
146    {
147        let file = std::fs::File::open("Cargo.toml").unwrap();
148        let thing = Thing::from_into_filelike(file);
149        let _ = thing.as_filelike();
150        let _ = thing.into_filelike();
151    }
152}
153
154#[cfg(not(feature = "close"))]
155fn main() {
156    println!("This example requires the \"close\" feature.");
157}
158