eztrace 0.2.0

Zero-fuss debug tracing macro
Documentation
//! Zero-fuss debug tracing macro.
//!
//! Cargo.toml:
//! ```text
//! [dependencies]
//! eztrace = "*"
//! ```
//!
//! Usage:
//! ```
//! #[allow(unused_imports)] #[macro_use] extern crate eztrace;
//! # fn main() {
//! # let (my_variable, other_variable) = (42, 237);
//! trace!(my_variable, other_variable);
//! # }
//! ```
//!
//! Prints this:
//! ```text
//! my_variable, other_variable: 42 237
//! ```

/// Prints out variables and their debug representation.
///
/// Non-`Copy` types do what you would hope.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// # #[macro_use] extern crate eztrace;
/// let a = 3;
/// let b = 4;
/// let c = 5;
/// trace!(a, b, c);
/// // a, b, c: 3 4 5
/// trace!(a * a + b * b, c * c);
/// // a * a + b * b, c * c: 25 25
/// ```
///
/// To print just the file & line:
///
/// ```
/// # #[macro_use] extern crate eztrace;
/// trace!();
/// // eztrace.rs:1
/// ```
///
/// To print a label:
///
/// ```
/// # #[macro_use] extern crate eztrace;
/// trace!("searching haystack for needles");
/// // searching haystack for needles
/// ```
///
/// You can also prefix with a `#` to get `{:#?}`-style format codes (tho you might just use
/// `dbg!()` instead…)
///
/// ```
/// # #[macro_use] extern crate eztrace;
/// trace!(#);
/// // eztrace.rs:1
/// trace!(#"hello");
/// // "hello"
/// #[derive(Debug, Default)]
/// struct Coords {
///     x: f32,
///     y: f32,
/// }
/// let zero = Coords::default();
/// trace!(#zero);
/// // zero: Coords {
/// //     x: 0.0,
/// //     y: 0.0,
/// // }
/// ```
#[macro_export]
macro_rules! trace {
    () => { println!(trace!(@line)); };
    (#) => { println!(trace!(@line)); };
    (#$label:literal) => {
        println!("{:?}", $label);
    };
    ($label:literal) => {
        println!("{}", $label);
    };
    (#$($IT:expr),* $(,)?) => {
        println!(
            trace!(@#fmt $($IT),*),
            $(&$IT),*
        );
    };
    ($($IT:expr),* $(,)?) => {
        println!(
            trace!(@fmt $($IT),*),
            $(&$IT),*
        );
    };
    (@line) => {
        concat!(
            file!(), ":", line!(),
        )
    };
    (@#fmt $($IT:expr),*) => {
        concat!(
            trace!(@stringify $($IT,)*),
            ":",
            $(trace!(@#fmtcode $IT)),*
        )
    };
    (@fmt $($IT:expr),*) => {
        concat!(
            trace!(@stringify $($IT,)*),
            ":",
            $(trace!(@fmtcode $IT)),*
        )
    };
    (@#fmtcode $_:expr) => {
        " {:#?}"
    };
    (@fmtcode $_:expr) => {
        " {:?}"
    };
    (@stringify $HEAD:expr, $($IT:expr,)*) => {
        concat!(
            stringify!($HEAD),
            $(
                ", ",
                stringify!($IT),
            )*
        )
    };
}


#[cfg(test)]
mod tests {
    #[test]
    fn no_move() {
        let string = format!("hey");
        trace!(string, 9);
        trace!(string, string);
        trace!(
            string,
            string,
            string,
        );
    }

    #[test]
    fn single_eval_per_arg() {
        let mut n = 0;
        fn incr(i: &mut usize) { *i += 1; }
        trace!(
            "check that each argument",
            "is only evaluated",
            "once",
            incr(&mut n),
        );
        trace!(n);
        assert_eq!(n, 1);
    }

    #[test]
    fn empty() {
        trace!();
    }

    #[test]
    fn single() {
        let hello = "hello";
        trace!(hello);
    }

    #[test]
    fn literal() {
        trace!("hi");
        trace!(0xED);
    }

    #[test]
    fn multi() {
        trace!("hello", "world!");
    }

    #[test]
    fn the_docs() {
        let a = 3;
        let b = 4;
        let c = 5;
        trace!(a, b, c);
        // a, b, c: 3 4 5
        trace!(a * a + b * b, c * c);
        // a * a + b * b, c * c: 25 25
        trace!();


        #[derive(Debug, Default)]
        struct Coords {
            x: f32,
            y: f32,
        }
        trace!(#);
        // eztrace.rs:7
        trace!(#"hello");
        // "hello"
        let zero = Coords::default();
        trace!(#zero);
        // zero: Coords {
        //     x: 0.0,
        //     y: 0.0,
        // }
    }
}

// FIXME: Maybe the macro should emit a warning?
// FIXME: Feature to always fail.