anstream/
macros.rs

1/// Prints to [`stdout`][crate::stdout].
2///
3/// Equivalent to the [`println!`] macro except that a newline is not printed at
4/// the end of the message.
5///
6/// Note that stdout is frequently line-buffered by default so it may be
7/// necessary to use [`std::io::Write::flush()`] to ensure the output is emitted
8/// immediately.
9///
10/// **NOTE:** The `print!` macro will lock the standard output on each call. If you call
11/// `print!` within a hot loop, this behavior may be the bottleneck of the loop.
12/// To avoid this, lock stdout with [`AutoStream::lock`][crate::AutoStream::lock]:
13/// ```
14/// #  #[cfg(feature = "auto")] {
15/// use std::io::Write as _;
16///
17/// let mut lock = anstream::stdout().lock();
18/// write!(lock, "hello world").unwrap();
19/// # }
20/// ```
21///
22/// Use `print!` only for the primary output of your program. Use
23/// [`eprint!`] instead to print error and progress messages.
24///
25/// **NOTE:** Not all `print!` calls will be captured in tests like [`std::print!`]
26/// - Capturing will automatically be activated in test binaries
27/// - Otherwise, only when the `test` feature is enabled
28///
29/// # Panics
30///
31/// Panics if writing to `stdout` fails for any reason **except** broken pipe.
32///
33/// Writing to non-blocking stdout can cause an error, which will lead
34/// this macro to panic.
35///
36/// # Examples
37///
38/// ```
39/// #  #[cfg(feature = "auto")] {
40/// use std::io::Write as _;
41/// use anstream::print;
42/// use anstream::stdout;
43///
44/// print!("this ");
45/// print!("will ");
46/// print!("be ");
47/// print!("on ");
48/// print!("the ");
49/// print!("same ");
50/// print!("line ");
51///
52/// stdout().flush().unwrap();
53///
54/// print!("this string has a newline, why not choose println! instead?\n");
55///
56/// stdout().flush().unwrap();
57/// # }
58/// ```
59#[cfg(feature = "auto")]
60#[macro_export]
61macro_rules! print {
62    ($($arg:tt)*) => {{
63        if cfg!(any(feature = "test", test)) {
64            use std::io::Write as _;
65
66            let stdio = std::io::stdout();
67            let choice = $crate::AutoStream::choice(&stdio);
68            let buffer = Vec::new();
69            let mut stream = $crate::AutoStream::new(buffer, choice);
70            // Ignore errors rather than panic
71            let _ = ::std::write!(&mut stream, $($arg)*);
72            let buffer = stream.into_inner();
73            // Should be UTF-8 but not wanting to panic
74            let buffer = String::from_utf8_lossy(&buffer);
75            ::std::print!("{}", buffer)
76        } else {
77            use std::io::Write as _;
78
79            let mut stream = $crate::stdout();
80            match ::std::write!(&mut stream, $($arg)*) {
81                Err(e) if e.kind() != ::std::io::ErrorKind::BrokenPipe => {
82                    ::std::panic!("failed printing to stdout: {e}");
83                }
84                Err(_) | Ok(_) => {}
85            }
86        }
87    }};
88}
89
90/// Prints to [`stdout`][crate::stdout], with a newline.
91///
92/// On all platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone
93/// (no additional CARRIAGE RETURN (`\r`/`U+000D`)).
94///
95/// This macro uses the same syntax as [`format!`], but writes to the standard output instead.
96/// See [`std::fmt`] for more information.
97///
98/// **NOTE:** The `println!` macro will lock the standard output on each call. If you call
99/// `println!` within a hot loop, this behavior may be the bottleneck of the loop.
100/// To avoid this, lock stdout with [`AutoStream::lock`][crate::AutoStream::lock]:
101/// ```
102/// #  #[cfg(feature = "auto")] {
103/// use std::io::Write as _;
104///
105/// let mut lock = anstream::stdout().lock();
106/// writeln!(lock, "hello world").unwrap();
107/// # }
108/// ```
109///
110/// Use `println!` only for the primary output of your program. Use
111/// [`eprintln!`] instead to print error and progress messages.
112///
113/// **NOTE:** Not all `println!` calls will be captured in tests like [`std::println!`]
114/// - Capturing will automatically be activated in test binaries
115/// - Otherwise, only when the `test` feature is enabled
116///
117/// # Panics
118///
119/// Panics if writing to `stdout` fails for any reason **except** broken pipe.
120///
121/// Writing to non-blocking stdout can cause an error, which will lead
122/// this macro to panic.
123///
124/// # Examples
125///
126/// ```
127/// #  #[cfg(feature = "auto")] {
128/// use anstream::println;
129///
130/// println!(); // prints just a newline
131/// println!("hello there!");
132/// println!("format {} arguments", "some");
133/// let local_variable = "some";
134/// println!("format {local_variable} arguments");
135/// # }
136/// ```
137#[cfg(feature = "auto")]
138#[macro_export]
139macro_rules! println {
140    () => {
141        $crate::print!("\n")
142    };
143    ($($arg:tt)*) => {{
144        if cfg!(any(feature = "test", test)) {
145            use std::io::Write as _;
146
147            let stdio = std::io::stdout();
148            let choice = $crate::AutoStream::choice(&stdio);
149            let buffer = Vec::new();
150            let mut stream = $crate::AutoStream::new(buffer, choice);
151            // Ignore errors rather than panic
152            let _ = ::std::write!(&mut stream, $($arg)*);
153            let buffer = stream.into_inner();
154            // Should be UTF-8 but not wanting to panic
155            let buffer = String::from_utf8_lossy(&buffer);
156            ::std::println!("{}", buffer)
157        } else {
158            use std::io::Write as _;
159
160            let mut stream = $crate::stdout();
161            match ::std::writeln!(&mut stream, $($arg)*) {
162                Err(e) if e.kind() != ::std::io::ErrorKind::BrokenPipe => {
163                    ::std::panic!("failed printing to stdout: {e}");
164                }
165                Err(_) | Ok(_) => {}
166            }
167        }
168    }};
169}
170
171/// Prints to [`stderr`][crate::stderr].
172///
173/// Equivalent to the [`print!`] macro, except that output goes to
174/// `stderr` instead of `stdout`. See [`print!`] for
175/// example usage.
176///
177/// Use `eprint!` only for error and progress messages. Use `print!`
178/// instead for the primary output of your program.
179///
180/// **NOTE:** Not all `eprint!` calls will be captured in tests like [`std::eprint!`]
181/// - Capturing will automatically be activated in test binaries
182/// - Otherwise, only when the `test` feature is enabled
183///
184/// # Panics
185///
186/// Panics if writing to `stderr` fails for any reason **except** broken pipe.
187///
188/// Writing to non-blocking stdout can cause an error, which will lead
189/// this macro to panic.
190///
191/// # Examples
192///
193/// ```
194/// #  #[cfg(feature = "auto")] {
195/// use anstream::eprint;
196///
197/// eprint!("Error: Could not complete task");
198/// # }
199/// ```
200#[cfg(feature = "auto")]
201#[macro_export]
202macro_rules! eprint {
203    ($($arg:tt)*) => {{
204        if cfg!(any(feature = "test", test)) {
205            use std::io::Write as _;
206
207            let stdio = std::io::stderr();
208            let choice = $crate::AutoStream::choice(&stdio);
209            let buffer = Vec::new();
210            let mut stream = $crate::AutoStream::new(buffer, choice);
211            // Ignore errors rather than panic
212            let _ = ::std::write!(&mut stream, $($arg)*);
213            let buffer = stream.into_inner();
214            // Should be UTF-8 but not wanting to panic
215            let buffer = String::from_utf8_lossy(&buffer);
216            ::std::eprint!("{}", buffer)
217        } else {
218            use std::io::Write as _;
219
220            let mut stream = $crate::stderr();
221            match ::std::write!(&mut stream, $($arg)*) {
222                Err(e) if e.kind() != ::std::io::ErrorKind::BrokenPipe => {
223                    ::std::panic!("failed printing to stdout: {e}");
224                }
225                Err(_) | Ok(_) => {}
226            }
227        }
228    }};
229}
230
231/// Prints to [`stderr`][crate::stderr], with a newline.
232///
233/// Equivalent to the [`println!`] macro, except that output goes to
234/// `stderr` instead of `stdout`. See [`println!`] for
235/// example usage.
236///
237/// Use `eprintln!` only for error and progress messages. Use `println!`
238/// instead for the primary output of your program.
239///
240/// **NOTE:** Not all `eprintln!` calls will be captured in tests like [`std::eprintln!`]
241/// - Capturing will automatically be activated in test binaries
242/// - Otherwise, only when the `test` feature is enabled
243///
244/// # Panics
245///
246/// Panics if writing to `stderr` fails for any reason **except** broken pipe.
247///
248/// Writing to non-blocking stdout can cause an error, which will lead
249/// this macro to panic.
250///
251/// # Examples
252///
253/// ```
254/// #  #[cfg(feature = "auto")] {
255/// use anstream::eprintln;
256///
257/// eprintln!("Error: Could not complete task");
258/// # }
259/// ```
260#[cfg(feature = "auto")]
261#[macro_export]
262macro_rules! eprintln {
263    () => {
264        $crate::eprint!("\n")
265    };
266    ($($arg:tt)*) => {{
267        if cfg!(any(feature = "test", test)) {
268            use std::io::Write as _;
269
270            let stdio = std::io::stderr();
271            let choice = $crate::AutoStream::choice(&stdio);
272            let buffer = Vec::new();
273            let mut stream = $crate::AutoStream::new(buffer, choice);
274            // Ignore errors rather than panic
275            let _ = ::std::write!(&mut stream, $($arg)*);
276            let buffer = stream.into_inner();
277            // Should be UTF-8 but not wanting to panic
278            let buffer = String::from_utf8_lossy(&buffer);
279            ::std::eprintln!("{}", buffer)
280        } else {
281            use std::io::Write as _;
282
283            let mut stream = $crate::stderr();
284            match ::std::writeln!(&mut stream, $($arg)*) {
285                Err(e) if e.kind() != ::std::io::ErrorKind::BrokenPipe => {
286                    ::std::panic!("failed printing to stdout: {e}");
287                }
288                Err(_) | Ok(_) => {}
289            }
290        }
291    }};
292}
293
294/// Panics the current thread.
295///
296/// This allows a program to terminate immediately and provide feedback
297/// to the caller of the program.
298///
299/// This macro is the perfect way to assert conditions in example code and in
300/// tests. `panic!` is closely tied with the `unwrap` method of both
301/// [`Option`][ounwrap] and [`Result`][runwrap] enums. Both implementations call
302/// `panic!` when they are set to [`None`] or [`Err`] variants.
303///
304/// When using `panic!()` you can specify a string payload, that is built using
305/// the [`format!`] syntax. That payload is used when injecting the panic into
306/// the calling Rust thread, causing the thread to panic entirely.
307///
308/// The behavior of the default `std` hook, i.e. the code that runs directly
309/// after the panic is invoked, is to print the message payload to
310/// `stderr` along with the file/line/column information of the `panic!()`
311/// call. You can override the panic hook using [`std::panic::set_hook()`].
312/// Inside the hook a panic can be accessed as a `&dyn Any + Send`,
313/// which contains either a `&str` or `String` for regular `panic!()` invocations.
314/// To panic with a value of another other type, [`panic_any`] can be used.
315///
316/// See also the macro [`compile_error!`], for raising errors during compilation.
317///
318/// # When to use `panic!` vs `Result`
319///
320/// The Rust language provides two complementary systems for constructing /
321/// representing, reporting, propagating, reacting to, and discarding errors. These
322/// responsibilities are collectively known as "error handling." `panic!` and
323/// `Result` are similar in that they are each the primary interface of their
324/// respective error handling systems; however, the meaning these interfaces attach
325/// to their errors and the responsibilities they fulfill within their respective
326/// error handling systems differ.
327///
328/// The `panic!` macro is used to construct errors that represent a bug that has
329/// been detected in your program. With `panic!` you provide a message that
330/// describes the bug and the language then constructs an error with that message,
331/// reports it, and propagates it for you.
332///
333/// `Result` on the other hand is used to wrap other types that represent either
334/// the successful result of some computation, `Ok(T)`, or error types that
335/// represent an anticipated runtime failure mode of that computation, `Err(E)`.
336/// `Result` is used alongside user defined types which represent the various
337/// anticipated runtime failure modes that the associated computation could
338/// encounter. `Result` must be propagated manually, often with the the help of the
339/// `?` operator and `Try` trait, and they must be reported manually, often with
340/// the help of the `Error` trait.
341///
342/// For more detailed information about error handling check out the [book] or the
343/// [`std::result`] module docs.
344///
345/// [ounwrap]: Option::unwrap
346/// [runwrap]: Result::unwrap
347/// [`std::panic::set_hook()`]: ../std/panic/fn.set_hook.html
348/// [`panic_any`]: ../std/panic/fn.panic_any.html
349/// [`Box`]: ../std/boxed/struct.Box.html
350/// [`Any`]: crate::any::Any
351/// [`format!`]: ../std/macro.format.html
352/// [book]: ../book/ch09-00-error-handling.html
353/// [`std::result`]: ../std/result/index.html
354///
355/// # Current implementation
356///
357/// If the main thread panics it will terminate all your threads and end your
358/// program with code `101`.
359///
360/// # Examples
361///
362/// ```should_panic
363/// # #![allow(unreachable_code)]
364/// use anstream::panic;
365/// panic!();
366/// panic!("this is a terrible mistake!");
367/// panic!("this is a {} {message}", "fancy", message = "message");
368/// ```
369#[cfg(feature = "auto")]
370#[macro_export]
371macro_rules! panic {
372    () => {
373        ::std::panic!()
374    };
375    ($($arg:tt)*) => {{
376        use std::io::Write as _;
377
378        let panic_stream = std::io::stderr();
379        let choice = $crate::AutoStream::choice(&panic_stream);
380        let buffer = Vec::new();
381        let mut stream = $crate::AutoStream::new(buffer, choice);
382        // Ignore errors rather than panic
383        let _ = ::std::write!(&mut stream, $($arg)*);
384        let buffer = stream.into_inner();
385        // Should be UTF-8 but not wanting to panic
386        let buffer = String::from_utf8_lossy(&buffer).into_owned();
387        ::std::panic!("{}", buffer)
388    }};
389}