|
3 | 3 |
|
4 | 4 | #[cfg(not(windows))] |
5 | 5 | fn main() { |
6 | | - use io_lifetimes::AsFilelike; |
7 | 6 | use rustix::io::{dup2, pipe}; |
8 | | - use std::io::{BufRead, BufReader, Write}; |
| 7 | + use std::io::{BufRead, BufReader}; |
9 | 8 | use std::mem::forget; |
10 | 9 |
|
| 10 | + // Create some new file descriptors that we'll use to replace stdio's file |
| 11 | + // descriptors with. |
11 | 12 | let (reader, writer) = pipe().unwrap(); |
| 13 | + |
| 14 | + // Acquire `OwnedFd` instances for stdin and stdout. These APIs are `unsafe` |
| 15 | + // because in general, with low-level APIs like this, libraries can't assume |
| 16 | + // that stdin and stdout will be open or safe to use. It's ok here, because |
| 17 | + // we're directly inside `main`, so we know that stdin and stdout haven't |
| 18 | + // been closed and aren't being used for other purposes. |
12 | 19 | let (stdin, stdout) = unsafe { (rustix::io::take_stdin(), rustix::io::take_stdout()) }; |
| 20 | + |
| 21 | + // Use `dup2` to copy our new file descriptors over the stdio file descriptors. |
| 22 | + // |
| 23 | + // These take their second argument as an `&OwnedFd` rather than the usual |
| 24 | + // `impl AsFd` because they conceptually do a `close` on the original file |
| 25 | + // descriptor, which one shouldn't be able to do with just a `BorrowedFd`. |
13 | 26 | dup2(&reader, &stdin).unwrap(); |
14 | 27 | dup2(&writer, &stdout).unwrap(); |
| 28 | + |
| 29 | + // Then, forget the stdio `OwnedFd`s, because actually dropping them would |
| 30 | + // close them. Here, we want stdin and stdout to remain open for the rest |
| 31 | + // of the program. |
15 | 32 | forget(stdin); |
16 | 33 | forget(stdout); |
17 | 34 |
|
| 35 | + // We can also drop the original file descriptors now, since `dup2` creates |
| 36 | + // new file descriptors with independent lifetimes. |
18 | 37 | drop(reader); |
19 | 38 | drop(writer); |
20 | 39 |
|
21 | | - // Don't use `std::io::stdout()` because in tests it's captured. |
22 | | - unsafe { |
23 | | - writeln!( |
24 | | - rustix::io::stdout().as_filelike_view::<std::fs::File>(), |
25 | | - "hello, world!" |
26 | | - ) |
27 | | - .unwrap(); |
28 | | - |
29 | | - let mut s = String::new(); |
30 | | - BufReader::new(&*rustix::io::stdin().as_filelike_view::<std::fs::File>()) |
31 | | - .read_line(&mut s) |
32 | | - .unwrap(); |
33 | | - assert_eq!(s, "hello, world!\n"); |
34 | | - } |
| 40 | + // Now we can print to "stdout" in the usual way, and it'll go to our pipe. |
| 41 | + println!("hello, world!"); |
| 42 | + |
| 43 | + // And we can read from stdin, and it'll read from our pipe. It's a little |
| 44 | + // silly that we connected our stdout to our own stdin, but it's just an |
| 45 | + // example :-). |
| 46 | + let mut s = String::new(); |
| 47 | + BufReader::new(std::io::stdin()).read_line(&mut s).unwrap(); |
| 48 | + assert_eq!(s, "hello, world!\n"); |
35 | 49 | } |
36 | 50 |
|
37 | 51 | #[cfg(windows)] |
|
0 commit comments