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
113
114
115
/// Prints and returns the value of a given expression for quick and dirty debugging
/// with the specified write macro, writer, format and error-handling policy.
///
/// The implementation of the `dbgwrite` macro is based on [`std::dbg`] macro implementation,
/// but the exact output printed by [`std::dbg`]
/// should not be relied upon and is subject to future changes.
///
/// If the `try` policy is used, it propagates write error and
/// returns values wrapper into `Result`.
///
/// # Panics
///
/// The macro panics if writing fails and the `expect` policy is used.
///
/// [`std::dbg`]: https://doc.rust-lang.org/std/macro.dbg.html
///
/// # Examples
///
/// ```rust
/// use core::fmt::Write;
/// let mut string = String::new();
///
/// assert_eq!(custom_print::dbgwrite!(writeln, &mut string, expect, ":?", "first"), ("first"));
/// assert!(string.contains("\"first\""));
/// assert_eq!(custom_print::dbgwrite!(writeln, &mut string, try, ":?", "second"), Ok(("second")));
/// assert!(string.contains("\"second\""));
/// ```
#[macro_export]
macro_rules! dbgwrite {
    ( $macro:path, $writer:expr, expect, $format:literal $(, $($args:tt)+)? ) => {
        $crate::_dbgwrite_impl!( $macro, $writer, $format $(, $($args)+)? )
    };
    ( $macro:path, $writer:expr, try, $format:literal $(, $($args:tt)+)? ) => {
        $crate::_try_dbgwrite_impl!( $macro, $writer, $format $(, $($args)+)? )
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! _dbgwrite_impl {
    ( $macro:path, $writer:expr, $format:literal ) => {
        $crate::write!(
            $macro, $writer, expect, "[{}:{}]", ::core::file!(), ::core::line!()
        );
    };
    ( $macro:path, $writer:expr, $format:literal, $val:expr $(,)? ) => {
        // Use of `match` here is intentional because it affects the lifetimes
        // of temporaries - https://stackoverflow.com/a/48732525/1063961
        match $val {
            tmp => {
                $crate::write!(
                    $macro, $writer, expect,
                    ::core::concat!("[{}:{}] {} = {", $format, "}"),
                    ::core::file!(), ::core::line!(), ::core::stringify!($val), &tmp
                );
                (tmp)
            }
        }
    };
    ( $macro:path, $writer:expr, $format:literal, $($val:expr),+ $(,)? ) => {
        ($(
            match $val {
                tmp => {
                    $crate::write!(
                        $macro, $writer, expect,
                        ::core::concat!("[{}:{}] {} = {", $format, "}"),
                        ::core::file!(), ::core::line!(), ::core::stringify!($val), &tmp
                    );
                    tmp
                }
            }
        ),+,)
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! _try_dbgwrite_impl {
    ( $macro:path, $writer:expr, $format:literal ) => {
        $crate::write!(
            $macro, $writer, try, "[{}:{}]", ::core::file!(), ::core::line!()
        ).map(|_| ());
    };
    ( $macro:path, $writer:expr, $format:literal, $val:expr $(,)? ) => {
        // Use of `match` here is intentional because it affects the lifetimes
        // of temporaries - https://stackoverflow.com/a/48732525/1063961
        match $val {
            tmp => {
                $crate::write!(
                    $macro, $writer, try,
                    ::core::concat!("[{}:{}] {} = {", $format, "}"),
                    ::core::file!(), ::core::line!(), ::core::stringify!($val), &tmp
                ).map(|_| tmp)
            }
        }
    };
    ( $macro:path, $writer:expr, $format:literal, $($val:expr),+ $(,)? ) => {
        (|| {
            Ok(($(
                match $val {
                    tmp => {
                        match $crate::write!(
                            $macro, $writer, try,
                            ::core::concat!("[{}:{}] {} = {", $format, "}"),
                            ::core::file!(), ::core::line!(), ::core::stringify!($val), &tmp
                        ) {
                            Ok(_) => tmp,
                            Err(err) => return Err(err),
                        }
                    }
                }
            ),+,))
        })()
    };
}