#![cfg_attr(use_nightly, feature(core_intrinsics, specialization))]
#[allow(dead_code)]
#[doc(hidden)]
pub struct WrapDebug<T>(pub T);
use std::fmt::{Debug, Formatter, Result};
impl<T: Debug> Debug for WrapDebug<T> {
fn fmt(&self, f: &mut Formatter) -> Result { self.0.fmt(f) }
}
#[cfg(use_nightly)]
impl<T> Debug for WrapDebug<T> {
default fn fmt(&self, f: &mut Formatter) -> Result {
use ::std::intrinsics::type_name;
write!(f, "[<unknown> of type {} is !Debug]",
unsafe { type_name::<T>() })
}
}
#[macro_export]
macro_rules! dbg {
() => {
dbg!( () );
};
($($val: expr),+,) => {
dbg!( $($val),+ )
};
($($lab: expr => $val: expr),+,) => {
dbg!( $($lab => $val),+ )
};
($valf: expr $(, $val: expr)*) => {{
#[allow(unreachable_code, unused_must_use, unused_parens)]
let _r = {
#[cfg(not(debug_assertions))] { ($valf $(, $val)*) }
#[cfg(debug_assertions)] {
use ::std::io::Write;
let stderr = ::std::io::stderr();
let mut err = ::std::io::BufWriter::new(stderr.lock());
let detailed = option_env!("RUST_DBG_COMPACT")
.map_or(true, |s| s == "0");
(if detailed {
write!(&mut err, "[DEBUGGING, {}:{}]\n=> ", file!(), line!())
} else {
write!(&mut err, "[{}:{}] ", file!(), line!())
}).unwrap();
let _ret = (
{
write!(&mut err, "{} = ", stringify!($valf)).unwrap();
let _tmp = $crate::WrapDebug($valf);
(if detailed { write!(&mut err, "{:#?}", _tmp) }
else { write!(&mut err, "{:?}" , _tmp) }).unwrap();
_tmp.0
}
$(, {
write!(&mut err, ", ").unwrap();
write!(&mut err, "{} = ", stringify!($val)).unwrap();
let _tmp = $crate::WrapDebug($val);
(if detailed { write!(&mut err, "{:#?}", _tmp) }
else { write!(&mut err, "{:?}" , _tmp) }).unwrap();
_tmp.0
} )*
);
(if detailed { writeln!(&mut err, "\n") }
else { writeln!(&mut err, "") }).unwrap();
_ret
}
};
_r
}};
($labf: expr => $valf: expr $(, $lab: expr => $val: expr)*) => {{
#[allow(unreachable_code, unused_must_use, unused_parens)]
let _r = {
#[cfg(not(debug_assertions))] { ($valf $(, $val)*) }
#[cfg(debug_assertions)] {
use ::std::io::Write;
let stderr = ::std::io::stderr();
let mut err = ::std::io::BufWriter::new(stderr.lock());
let detailed = option_env!("RUST_DBG_COMPACT")
.map_or(true, |s| s == "0");
(if detailed {
write!(&mut err, "[DEBUGGING, {}:{}]\n=> ", file!(), line!())
} else {
write!(&mut err, "[{}:{}] ", file!(), line!())
}).unwrap();
let _ret = (
{
let _ = concat!($labf, "");
let _ : &'static str = $labf;
write!(&mut err, "{} = ", stringify!($labf)).unwrap();
let _tmp = $crate::WrapDebug($valf);
(if detailed { write!(&mut err, "{:#?}", _tmp) }
else { write!(&mut err, "{:?}" , _tmp) }).unwrap();
_tmp.0
}
$(, {
write!(&mut err, ", ").unwrap();
let _ = concat!($lab, "");
let _ : &'static str = $lab;
write!(&mut err, "{} = ", stringify!($lab)).unwrap();
let _tmp = $crate::WrapDebug($val);
(if detailed { write!(&mut err, "{:#?}", _tmp) }
else { write!(&mut err, "{:?}" , _tmp) }).unwrap();
_tmp.0
} )*
);
(if detailed { writeln!(&mut err, "\n") }
else { writeln!(&mut err, "") }).unwrap();
_ret
}
};
_r
}};
}
#[cfg(test)]
mod tests {
#[derive(Debug)] struct Point {
x: usize,
y: usize,
}
macro_rules! test {
($test: ident $block: block) => {
#[test]
fn $test() {
eprintln!();
$block
}
};
}
test!(unit_works {
dbg!();
});
test!(common_use {
dbg!(Point { x: 1, y: 2 });
let p = Point { x: 4, y: 5 };
dbg!(p);
});
test!(passthrough {
let x = dbg!(1 + 2);
let y = dbg!(x + 1) + dbg!(3);
dbg!(y);
});
test!(types {
let a = 1;
let b = 2;
let _ : u32 = dbg!(a);
let _ : (u32, u32) = dbg!(a, b);
let _ : (u32, u32, u32) = dbg!(a, b, a + b);
let p = Point { x: 4, y: 5 };
let q = Point { x: 2, y: 1 };
let _ : (&Point, &Point) = dbg!(&p, &q);
});
test!(labels {
let w = 1;
let h = 2;
dbg!("width" => w, "height" => h, "area" => w * h);
let p = Point { x: 4, y: 5 };
dbg!("first point" => &p, "same point" => &p);
});
test!(not_debug {
struct X(usize);
let a = X(1);
dbg!(&a);
});
test!(factorial_simple {
fn factorial(n: u32) -> u32 {
if dbg!(n <= 1) {
dbg!(1)
} else {
dbg!(n * factorial(n - 1))
}
}
dbg!(factorial(4));
});
test!(factorial_labels {
fn factorial(n: u32) -> u32 {
if dbg!("are we at the base case?" => n <= 1) {
dbg!("base value" => 1)
} else {
dbg!("ascending with n * factorial(n - 1)" => n * factorial(n - 1))
}
}
dbg!(factorial(4));
});
test!(factorial_multiarg {
fn factorial(n: u32) -> u32 {
if dbg!(n, n <= 1).1 {
dbg!(n, 1).1
} else {
dbg!(n, n * factorial(n - 1)).1
}
}
dbg!(factorial(4));
});
#[should_panic]
#[test]
fn panics() {
eprintln!();
let (a, _b) = (1, 2);
dbg!(a, panic!(), _b);
}
}