• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! A simple testcase that prints a few messages to the console, demonstrating
2 //! the io-lifetimes API.
3 
4 #![cfg_attr(not(io_safety_is_in_std), allow(unused_imports))]
5 
6 #[cfg(feature = "close")]
7 use io_lifetimes::example_ffi::*;
8 #[cfg(feature = "close")]
9 use std::{
10     fs::File,
11     io::{self, Write},
12 };
13 
14 #[cfg(all(unix, feature = "close"))]
15 use io_lifetimes::{AsFd, OwnedFd};
16 
17 #[cfg(all(windows, feature = "close"))]
18 use io_lifetimes::{AsHandle, OwnedHandle};
19 #[cfg(all(windows, feature = "close"))]
20 use std::{convert::TryInto, os::windows::io::RawHandle, ptr::null_mut};
21 
22 #[cfg(all(io_safety_is_in_std, unix, feature = "close"))]
main() -> io::Result<()>23 fn main() -> io::Result<()> {
24     let fd = unsafe {
25         // Open a file, which returns an `Option<OwnedFd>`, which we can
26         // maybe convert into an `OwnedFile`.
27         let fd: OwnedFd = open("/dev/stdout\0".as_ptr() as *const _, O_WRONLY | O_CLOEXEC)
28             .ok_or_else(io::Error::last_os_error)?;
29 
30         // Borrow the fd to write to it.
31         let result = write(fd.as_fd(), "hello, world\n".as_ptr() as *const _, 13);
32         match result {
33             -1 => return Err(io::Error::last_os_error()),
34             13 => (),
35             _ => return Err(io::Error::new(io::ErrorKind::Other, "short write")),
36         }
37 
38         fd
39     };
40 
41     // Convert into a `File`. No `unsafe` here!
42     let mut file = File::from(fd);
43     writeln!(&mut file, "greetings, y'all")?;
44 
45     // We can borrow a `BorrowedFd` from a `File`.
46     unsafe {
47         let result = write(file.as_fd(), "sup?\n".as_ptr() as *const _, 5);
48         match result {
49             -1 => return Err(io::Error::last_os_error()),
50             5 => (),
51             _ => return Err(io::Error::new(io::ErrorKind::Other, "short write")),
52         }
53     }
54 
55     // `OwnedFd` closes the fd in its `Drop` implementation.
56 
57     Ok(())
58 }
59 
60 /// The Windows analog of the above.
61 #[cfg(all(windows, feature = "close"))]
main() -> io::Result<()>62 fn main() -> io::Result<()> {
63     let handle = unsafe {
64         // Open a file, which returns an `HandleOrInvalid`, which we can fallibly
65         // convert into an `OwnedFile`.
66         let handle: OwnedHandle = CreateFileW(
67             ['C' as u16, 'O' as _, 'N' as _, 0].as_ptr(),
68             FILE_GENERIC_WRITE,
69             0,
70             null_mut(),
71             OPEN_EXISTING,
72             FILE_ATTRIBUTE_NORMAL,
73             null_mut() as RawHandle as HANDLE,
74         )
75         .try_into()
76         .map_err(|_err| io::Error::last_os_error())?;
77 
78         // Borrow the handle to write to it.
79         let mut number_of_bytes_written = 0;
80         let result = WriteFile(
81             handle.as_handle(),
82             "hello, world\n".as_ptr() as *const _,
83             13,
84             &mut number_of_bytes_written,
85             null_mut(),
86         );
87         match (result, number_of_bytes_written) {
88             (0, _) => return Err(io::Error::last_os_error()),
89             (_, 13) => (),
90             (_, _) => return Err(io::Error::new(io::ErrorKind::Other, "short write")),
91         }
92 
93         handle
94     };
95 
96     // Convert into a `File`. No `unsafe` here!
97     let mut file = File::from(handle);
98     writeln!(&mut file, "greetings, y'all")?;
99 
100     // We can borrow a `BorrowedHandle` from a `File`.
101     unsafe {
102         let mut number_of_bytes_written = 0;
103         let result = WriteFile(
104             file.as_handle(),
105             "sup?\n".as_ptr() as *const _,
106             5,
107             &mut number_of_bytes_written,
108             null_mut(),
109         );
110         match (result, number_of_bytes_written) {
111             (0, _) => return Err(io::Error::last_os_error()),
112             (_, 5) => (),
113             (_, _) => return Err(io::Error::new(io::ErrorKind::Other, "short write")),
114         }
115     }
116 
117     // `OwnedHandle` closes the handle in its `Drop` implementation.
118 
119     Ok(())
120 }
121 
122 #[cfg(all(
123     not(all(io_safety_is_in_std, unix, feature = "close")),
124     not(all(windows, feature = "close"))
125 ))]
main()126 fn main() {
127     println!("On Unix, this example requires Rust >= 1.63 and the \"close\" feature.");
128 }
129