|
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