dbg!
in the loop without terminal woes.
The macro [dbg_once!
] only prints its value the first time.
use dbg_if::dbg_once;
for i in 0..10 {
dbg_once!(i); // Outputs: [src/lib.rs:9:9] x = 0
}
The macro [dbg_if_ne!
] only prints changed values.
use dbg_if::dbg_if_ne;
fn f(x: u8) -> u8 {
dbg_if_ne!(x, u8)
}
f(1); // Outputs: [src/lib.rs:58:9] x = 1
f(1); // No output.
f(2); // Outputs: [src/lib.rs:58:9] x = 2
The macro [dbg_if_hash_ne!
] only prints on changed hash values.
use dbg_if::dbg_if_hash_ne;
let mut s: String = "hello".into();
fn f(x: &str) -> &str {
dbg_if_hash_ne!(x)
}
f(&s); // Outputs: [src/lib.rs:37:9] x = "hello"
f(&s); // No output.
s.push('!');
f(&s); // Outputs: [src/lib.rs:37:9] x = "hello!"
The sister macros [once!
], [was_ne!
], and [was_hash_ne!
] return true instead
of printing.
Finally the macro [dbg_if
] provides a kind of drop-in replacment for
dbg
if that is your preference.
use dbg_if::dbg_if as dbg;
let mut x: u8 = 0;
fn f(x: u8) -> u8 {
dbg!(x + 1);
dbg!(x + 2, Once);
dbg!(x + 3, IfNe, u8);
dbg!(x + 4, IfHashNe)
}
x = f(x);
// Outputs:
// [src/lib.rs:10:9] x + 1 = 1
// [src/lib.rs:11:9] x + 2 = 2
// [src/lib.rs:12:9] x + 3 = 3
// [src/lib.rs:13:9] x + 4 = 4
x = f(x);
// Outputs:
// [src/lib.rs:10:9] x + 1 = 1
If the feature "float" is enabled, these macros are available:
- [
abs_diff_ne_args!
] acceptsepsilon
argument, - [
relative_ne_args!
] acceptsepsilon
andrelative_max
arguments, - and [
ulps_ne_args!
] acceptsepsilon
andulps_max
arguments.
These can be given as the third argument to [was_ne!
] or [dbg_if_ne!
]. See
the [approx
] crate for more details.
#[cfg(feature = "float")]
{
use dbg_if::{dbg_if_ne, abs_diff_ne_args};
fn f(x: f32) -> f32 {
dbg_if_ne!(x, f32, abs_diff_ne_args!(epsilon = 1.0))
}
f(1.0); // Outputs: [src/lib.rs:42:9] x = 1.0
f(1.5); // No output.
f(2.0); // No output.
f(2.1); // Outputs: [src/lib.rs:42:9] x = 2.1
}
- Ease debugging inspection without resorting to a debugger.
fn f(x: u8) -> u8 {
dbg!(x) + 1
}
assert_eq!(f(1), 2);
The dbg!
macro is great. It's like being able to add a probe right into your
code without disturbing everything since it works on expressions and lets them
"pass thru." For straight shot code, it is perfect.
fn f(x: u8) -> u8 {
let mut accum = 0;
for i in 0..100 {
accum += dbg!(x);
}
accum
}
[src/main.rs:59:18] x = 1
[src/main.rs:59:18] x = 1
[src/main.rs:59:18] x = 1
...^C
For code in tight loops, however, dbg!
leaves something to be desired. The
terminal screams, "x = 1" again and again. There has got to be a better way.
Yes! Let's take note of the value at the call site—with a static atomic
variable—and instead of spamming the terminal with the same information, let's
only emit information when it has changed with [dbg_if_ne!
].
use dbg_if::dbg_if_ne;
fn f(x: u8) -> u8 {
let mut accum = 0;
for i in 0..5 {
accum += dbg_if_ne!(x, u8);
}
accum
}
f(1); // Outputs: [src/main.rs:59:18] x = 1
That's fine. Can they be hashed? Because hashes can be stored in an AtomicU64
at the call site. Just use [dbg_if_hash_ne!
].
Some tests require a particular setup in order to run successfully. A couple of
aliases have been placed in .cargo/config.toml
to run these tests.
cargo test
runs thewas*
tests.cargo test-output
runs above and thedbg*
tests which verify its output on stdout.cargo test-all
runs above and the float features.
If you see errors that say, "Redirect already exists," that's because some tests
check the stdout and cannot be run multi-threaded. Use cargo test-output
to
run them with the right arguments.
This crate is licensed, at your option, under either
- the Apache License, Version 2.0 or
- the MIT license.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Thank you to Philipp Oppermann for his crate
once
. I initially thought I'd only
write dbg_once!
and submit a PR. But once I got going I realized dbg_if_ne!
would be useful too and these are all require std
; once
is a no_std
crate.
So dbg_if
is inspired and informed by once
but it actually doesn't share
any code with once
.