custom_print/macros/dbgwrite.rs
1/// Prints and returns the value of a given expression for quick and dirty debugging
2/// with the specified write macro, writer, format and error-handling policy.
3///
4/// The implementation of the `dbgwrite` macro is based on [`std::dbg`] macro implementation,
5/// but the exact output printed by [`std::dbg`]
6/// should not be relied upon and is subject to future changes.
7///
8/// If the `try` policy is used, it propagates write error and
9/// returns values wrapper into `Result`.
10///
11/// # Panics
12///
13/// The macro panics if writing fails and the `expect` policy is used.
14///
15/// [`std::dbg`]: https://doc.rust-lang.org/std/macro.dbg.html
16///
17/// # Examples
18///
19/// ```rust
20/// use core::fmt::Write;
21/// let mut string = String::new();
22///
23/// assert_eq!(custom_print::dbgwrite!(writeln, &mut string, expect, ":?", "first"), ("first"));
24/// assert!(string.contains("\"first\""));
25/// assert_eq!(custom_print::dbgwrite!(writeln, &mut string, try, ":?", "second"), Ok(("second")));
26/// assert!(string.contains("\"second\""));
27/// ```
28#[macro_export]
29macro_rules! dbgwrite {
30 ( $macro:path, $writer:expr, expect, $format:literal $(, $($args:tt)+)? ) => {
31 $crate::_dbgwrite_impl!( $macro, $writer, $format $(, $($args)+)? )
32 };
33 ( $macro:path, $writer:expr, try, $format:literal $(, $($args:tt)+)? ) => {
34 $crate::_try_dbgwrite_impl!( $macro, $writer, $format $(, $($args)+)? )
35 };
36}
37
38#[doc(hidden)]
39#[macro_export]
40macro_rules! _dbgwrite_impl {
41 ( $macro:path, $writer:expr, $format:literal ) => {
42 $crate::write!(
43 $macro, $writer, expect, "[{}:{}]", ::core::file!(), ::core::line!()
44 );
45 };
46 ( $macro:path, $writer:expr, $format:literal, $val:expr $(,)? ) => {
47 // Use of `match` here is intentional because it affects the lifetimes
48 // of temporaries - https://stackoverflow.com/a/48732525/1063961
49 match $val {
50 tmp => {
51 $crate::write!(
52 $macro, $writer, expect,
53 ::core::concat!("[{}:{}] {} = {", $format, "}"),
54 ::core::file!(), ::core::line!(), ::core::stringify!($val), &tmp
55 );
56 (tmp)
57 }
58 }
59 };
60 ( $macro:path, $writer:expr, $format:literal, $($val:expr),+ $(,)? ) => {
61 ($(
62 match $val {
63 tmp => {
64 $crate::write!(
65 $macro, $writer, expect,
66 ::core::concat!("[{}:{}] {} = {", $format, "}"),
67 ::core::file!(), ::core::line!(), ::core::stringify!($val), &tmp
68 );
69 tmp
70 }
71 }
72 ),+,)
73 };
74}
75
76#[doc(hidden)]
77#[macro_export]
78macro_rules! _try_dbgwrite_impl {
79 ( $macro:path, $writer:expr, $format:literal ) => {
80 $crate::write!(
81 $macro, $writer, try, "[{}:{}]", ::core::file!(), ::core::line!()
82 ).map(|_| ());
83 };
84 ( $macro:path, $writer:expr, $format:literal, $val:expr $(,)? ) => {
85 // Use of `match` here is intentional because it affects the lifetimes
86 // of temporaries - https://stackoverflow.com/a/48732525/1063961
87 match $val {
88 tmp => {
89 $crate::write!(
90 $macro, $writer, try,
91 ::core::concat!("[{}:{}] {} = {", $format, "}"),
92 ::core::file!(), ::core::line!(), ::core::stringify!($val), &tmp
93 ).map(|_| tmp)
94 }
95 }
96 };
97 ( $macro:path, $writer:expr, $format:literal, $($val:expr),+ $(,)? ) => {
98 (|| {
99 Ok(($(
100 match $val {
101 tmp => {
102 match $crate::write!(
103 $macro, $writer, try,
104 ::core::concat!("[{}:{}] {} = {", $format, "}"),
105 ::core::file!(), ::core::line!(), ::core::stringify!($val), &tmp
106 ) {
107 Ok(_) => tmp,
108 Err(err) => return Err(err),
109 }
110 }
111 }
112 ),+,))
113 })()
114 };
115}