`dbg!` with some text?

#1

Is there a way to write:

dbg!("some header text: {}", &my_var);

I found debug_macros crate but not maintained anymore.

#2

No there is not, you can use the println macro instead. If you want file and line numbers then you can use the file, line, and column macros to get that info.

https://doc.rust-lang.org/std/macro.file.html
https://doc.rust-lang.org/std/macro.line.html
https://doc.rust-lang.org/std/macro.column.html

2 Likes
#3

Thanks!

1 Like
#4

Alternatively, you could define your own macro based on dbg!. Like so:

macro_rules! dbg_msg {
    ($val:expr) => {
        match $val {
            tmp => {
                eprintln!("[{}:{}] {} = {:#?}",
                    file!(), line!(), stringify!($val), &tmp);
                tmp
            }
        }
    };
    ($tag:expr, $val:expr $(,)?) => {
        match $val {
            tmp => {
                eprintln!("[{}:{}] ({:#?}) {} = {:#?}",
                    file!(), line!(), $tag, stringify!($val), &tmp);
                tmp
            }
        }
    }
}

The awkward match statement is part of the standard library implementation, so I just followed it.

2 Likes
#5

Silly approach that you probably don’t want to do:

dbg!({ "some header text"; &my_var });
[src/main.rs:3] { "some header text"; &my_var } = 4

It’s like that because of the lifetimes of temporaries, IIRC. match A { x => B } is Rust’s version of an ML let x = A in B.

#6

A variant on @OptimisticPeach suggestion (is more flexible regarding the positioning of different items)

macro_rules! dbgf {
    (
        $fmt:expr, $val:expr $(,)?
    ) => (
        match $val {
            | tmp => {
                eprintln!(
                    concat!("[{}:{}] ", $fmt),
                    file!(),
                    line!(),
                    format_args!(
                        "{} = {:?}",
                        stringify!($val),
                        tmp,
                    ),
                );
                tmp
            },
        }
    );

    (
        $val:expr $(,)?
    ) => (
        dbgf!("{}", $val)
    );
}
5 Likes
#7

Why this is not in std :thinking:???

#8

Probably because one of the ideas with dbg! was to have it allow multiple arguments and treat them as a tuple:

let (a, b) = dbg!(1, 2);

Personally I think passing a tuple into dbg! is easy enough and gives a decent enough output and having it support an optional format string would be a better use of extra arguments (although I’d personally design it a bit differently to the one @Yandros implemented).

#9

I agree, the implementation I suggested targeted adding contextual text, but I personally find it more useful to cutomize the formatting:

macro_rules! dbgf {
    (
        $fmt:expr, $expr:expr $(,)?
    ) => (
        match $expr {
            | tmp => {
                eprintln!(
                    concat!("[{}:{}:{}] {} = ", $fmt),
                    file!(),
                    line!(),
                    column!(),
                    stringify!($expr),
                    tmp,
                );
                tmp
            },
        }
    );

    (
        $expr:expr $(,)?
    ) => (
        dbgf!("{:#?}", $expr) // default formatting is {:#?} as with dbg!
    );
}

Now, the question is whether we can have both contextual text, and custom formatting, and the answer is yes, but it requires a helper struct:

use ::std::fmt;

// #[macro_export]
macro_rules! dbgf {
    (
        $fmt:expr, $expr:expr $(,)?
    ) => (
        match $expr {
            | tmp => {
                eprintln!(
                    concat!("[{}:{}:{}] ", $fmt),
                    file!(),
                    line!(),
                    column!(),
                    $crate::WithPrefix {
                        prefix: concat!(stringify!($expr), " = "),
                        value: &tmp,
                    },
                );
                tmp
            },
        }
    );

    (
        $expr:expr $(,)?
    ) => (
        dbgf!("{:#?}", $expr) // default formatting
    );
}

// #[doc(hidden)] pub
struct WithPrefix<'prefix, T> {
    prefix: &'prefix str,
    value: T,
}

macro_rules! impl_fmtTraits_for_WithPrefix {(
    $( $Trait:ident ),* $(,)?
) => (
    $(
        impl<T : fmt::$Trait> fmt::$Trait for WithPrefix<'_, T> {
            fn fmt (
                self: &'_ Self,
                stream: &'_ mut fmt::Formatter<'_>,
            ) -> fmt::Result
            {
                stream.write_str(self.prefix)?;
                self.value.fmt(stream)
            }
        }
    )*
)}


impl_fmtTraits_for_WithPrefix! {
    Display, Debug, Octal, LowerHex, UpperHex, Pointer, Binary, LowerExp, UpperExp,
}

EDIT: Fixed using {:?} as the default formatter instead of ::std::dbg!'s {:#?}, as @Nemo157 pointed out

#10

dbg! actually uses {:#?} which is one of the main reasons I’d like to be able to override it to {:?}.

1 Like