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