1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/*! Calm, non-panicking I/O operations.
A fun fact about Rust is that `println!` and friends induce a panic when they
try to write to a standard stream that has closed.
A fun fact about UNIX pipelines is that, if the standard streams are a pipe, the
kernel fires a `SIGPIPE` at the process connected to the other end, before
returning `-EPIPE` from the system call. The C runtime `crt0` usually responds
to this signal by terminating. The Rust runtime masks that signal, and does not
terminate.
This means that Rust programs which use `println!` for emitting text, when
placed in a pipeline, can suddenly begin panicking as `stdout` is suddenly
finite.
This crate provides patches to these problems: fallible macros which write to
`stdout` and `stderr` just like `print` and `eprint` do, but return `io::Result`
instead of panicking.
In addition, this crate provides attributes you can place on functions which
return `io::Result` to suppress specific failures, such as pipes breaking. These
macros should only be used on terminal functions, such as `main`, as they
currently throw away the success value.
## Writing to Standand Streams
```sh
println!(...)` becomes `stdoutln!(...)?
print!(...)` becomes `stdout!(...)?
eprintln!(...)` becomes `stderrln!(...)?
eprint!(...)` becomes `stderr!(...)?
```
That’s it. Change your functions that write to those streams to return an error
variant compatible with `io::Result`, and add `?` to taste.
## Suppressing Pipe Failure
Take your function that returns `io::Result`:
```rust,ignore
fn main() -> io::Result<()> {
stdoutln!("Hello!")?;
}
```
and add one attribute to it:
```rust,ignore
#[calm_io::pipefail] // <- this attribute
fn main() -> io::Result<()> {
stdoutln!("Hello, but calmly!")?;
}
```
You can observe this by running these three shell commands:
```sh
yes | head
cargo run --example bad_yes | head
cargo run --example good_yes | head
```
and observing that `bad_yes` panics, `yes` exits quietly (unless you inspect
`PIPESTATUS` or use `set -o pipefail`), and `good_yes` always exits quietly.
!*/
pub use *;
/// Like `print!`, except it returns a `Result` rather than `panic!`king.
/// Like `println!`, except it returns a `Result` rather than `panic!`king.
/// Like `eprint!`, except it returns a `Result` rather than `panic!`king.
/// Like `eprintln!`, except it returns a `Result` rather than `panic!`king.