eztrace/
eztrace.rs

1//! Zero-fuss debug tracing macro.
2//!
3//! Cargo.toml:
4//! ```text
5//! [dependencies]
6//! eztrace = "*"
7//! ```
8//!
9//! Usage:
10//! ```
11//! #[allow(unused_imports)] #[macro_use] extern crate eztrace;
12//! # fn main() {
13//! # let (my_variable, other_variable) = (42, 237);
14//! trace!(my_variable, other_variable);
15//! # }
16//! ```
17//!
18//! Prints this:
19//! ```text
20//! my_variable, other_variable: 42 237
21//! ```
22
23/// Prints out variables and their debug representation.
24///
25/// Non-`Copy` types do what you would hope.
26///
27/// # Examples
28///
29/// Basic usage:
30///
31/// ```
32/// # #[macro_use] extern crate eztrace;
33/// let a = 3;
34/// let b = 4;
35/// let c = 5;
36/// trace!(a, b, c);
37/// // a, b, c: 3 4 5
38/// trace!(a * a + b * b, c * c);
39/// // a * a + b * b, c * c: 25 25
40/// ```
41///
42/// To print just the file & line:
43///
44/// ```
45/// # #[macro_use] extern crate eztrace;
46/// trace!();
47/// // eztrace.rs:1
48/// ```
49///
50/// To print a label:
51///
52/// ```
53/// # #[macro_use] extern crate eztrace;
54/// trace!("searching haystack for needles");
55/// // searching haystack for needles
56/// ```
57///
58/// You can also prefix with a `#` to get `{:#?}`-style format codes (tho you might just use
59/// `dbg!()` instead…)
60///
61/// ```
62/// # #[macro_use] extern crate eztrace;
63/// trace!(#);
64/// // eztrace.rs:1
65/// trace!(#"hello");
66/// // "hello"
67/// #[derive(Debug, Default)]
68/// struct Coords {
69///     x: f32,
70///     y: f32,
71/// }
72/// let zero = Coords::default();
73/// trace!(#zero);
74/// // zero: Coords {
75/// //     x: 0.0,
76/// //     y: 0.0,
77/// // }
78/// ```
79#[macro_export]
80macro_rules! trace {
81    () => { println!(trace!(@line)); };
82    (#) => { println!(trace!(@line)); };
83    (#$label:literal) => {
84        println!("{:?}", $label);
85    };
86    ($label:literal) => {
87        println!("{}", $label);
88    };
89    (#$($IT:expr),* $(,)?) => {
90        println!(
91            trace!(@#fmt $($IT),*),
92            $(&$IT),*
93        );
94    };
95    ($($IT:expr),* $(,)?) => {
96        println!(
97            trace!(@fmt $($IT),*),
98            $(&$IT),*
99        );
100    };
101    (@line) => {
102        concat!(
103            file!(), ":", line!(),
104        )
105    };
106    (@#fmt $($IT:expr),*) => {
107        concat!(
108            trace!(@stringify $($IT,)*),
109            ":",
110            $(trace!(@#fmtcode $IT)),*
111        )
112    };
113    (@fmt $($IT:expr),*) => {
114        concat!(
115            trace!(@stringify $($IT,)*),
116            ":",
117            $(trace!(@fmtcode $IT)),*
118        )
119    };
120    (@#fmtcode $_:expr) => {
121        " {:#?}"
122    };
123    (@fmtcode $_:expr) => {
124        " {:?}"
125    };
126    (@stringify $HEAD:expr, $($IT:expr,)*) => {
127        concat!(
128            stringify!($HEAD),
129            $(
130                ", ",
131                stringify!($IT),
132            )*
133        )
134    };
135}
136
137
138#[cfg(test)]
139mod tests {
140    #[test]
141    fn no_move() {
142        let string = format!("hey");
143        trace!(string, 9);
144        trace!(string, string);
145        trace!(
146            string,
147            string,
148            string,
149        );
150    }
151
152    #[test]
153    fn single_eval_per_arg() {
154        let mut n = 0;
155        fn incr(i: &mut usize) { *i += 1; }
156        trace!(
157            "check that each argument",
158            "is only evaluated",
159            "once",
160            incr(&mut n),
161        );
162        trace!(n);
163        assert_eq!(n, 1);
164    }
165
166    #[test]
167    fn empty() {
168        trace!();
169    }
170
171    #[test]
172    fn single() {
173        let hello = "hello";
174        trace!(hello);
175    }
176
177    #[test]
178    fn literal() {
179        trace!("hi");
180        trace!(0xED);
181    }
182
183    #[test]
184    fn multi() {
185        trace!("hello", "world!");
186    }
187
188    #[test]
189    fn the_docs() {
190        let a = 3;
191        let b = 4;
192        let c = 5;
193        trace!(a, b, c);
194        // a, b, c: 3 4 5
195        trace!(a * a + b * b, c * c);
196        // a * a + b * b, c * c: 25 25
197        trace!();
198
199
200        #[derive(Debug, Default)]
201        struct Coords {
202            x: f32,
203            y: f32,
204        }
205        trace!(#);
206        // eztrace.rs:7
207        trace!(#"hello");
208        // "hello"
209        let zero = Coords::default();
210        trace!(#zero);
211        // zero: Coords {
212        //     x: 0.0,
213        //     y: 0.0,
214        // }
215    }
216}
217
218// FIXME: Maybe the macro should emit a warning?
219// FIXME: Feature to always fail.