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