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.