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