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")]
7use io_lifetimes::example_ffi::*;
8#[cfg(feature = "close")]
9use std::{
10    fs::File,
11    io::{self, Write},
12};
13
14#[cfg(all(unix, feature = "close"))]
15use io_lifetimes::{AsFd, OwnedFd};
16
17#[cfg(all(windows, feature = "close"))]
18use io_lifetimes::{AsHandle, OwnedHandle};
19#[cfg(all(windows, feature = "close"))]
20use std::{convert::TryInto, os::windows::io::RawHandle, ptr::null_mut};
21
22#[cfg(all(io_safety_is_in_std, unix, feature = "close"))]
23fn 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"))]
62fn 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))]
126fn main() {
127    println!("On Unix, this example requires Rust >= 1.63 and the \"close\" feature.");
128}
129