q_debug/macros.rs
1/// Expands to the path of the function within which it was invoked e.g.
2/// `"crate::module::function::"`
3#[macro_export]
4macro_rules! function {
5 () => {{
6 // This works by defining a function within the call site and using
7 // (abusing) `std::any::type_name` to retrieve it's full path.
8 //
9 // Note: it is possible that this may break as the docs for
10 // `std::any::type_name`` state:
11 //
12 // > This is intended for diagnostic use. The exact contents and
13 // > format of the string are not specified, other than being a
14 // > best-effort description of the type
15 //
16 // and
17 // > ... output may change between versions of the compiler.
18 //
19 // I'm ok with this because `q` is a low-risk crate (e.g. it's a "cool"
20 // debugging tool but if it breaks it won't be the end of the world),
21 // it works for now and I can't (currently) think of a better way to
22 // do this without more "heavy-weight" methods e.g. parsing backtraces
23 // or proc macros.
24 fn f() {}
25 fn type_name_of<T>(_: T) -> &'static str {
26 std::any::type_name::<T>()
27 }
28 let name = type_name_of(f); // `"crate::module::function::f"`
29 &name[..name.len() - 3] // `"crate::module::function::"`
30 }};
31}
32
33#[macro_export]
34macro_rules! loc {
35 () => {
36 $crate::LogLocation {
37 file_path: file!().to_string(),
38 func_path: function!().to_string(),
39 lineno: line!(),
40 thread_id: std::thread::current().id(),
41 }
42 };
43}
44
45// TODO: Variadic arguments e.g. `q!("Hello", 1, foo(2))` -> `"> \"Hello\", 1, foo(2) = 3"`
46
47#[macro_export]
48macro_rules! q {
49 // Note: `unwrap` is used when accessing the the global `Logger` mutex as
50 // trying to recover from lock poisoning is not suitable for this use case.
51 () => {
52 $crate::LOGGER.write().unwrap().q(loc!());
53 };
54
55 ($x:literal) => {{
56 let val = $x;
57 $crate::LOGGER.write().unwrap().q_literal(&val, loc!());
58 val
59 }};
60
61 ($x:expr) => {{
62 let val = $x;
63 $crate::LOGGER
64 .write()
65 .unwrap()
66 .q_expr(&val, stringify!($x), loc!());
67 val
68 }};
69}
70
71#[cfg(test)]
72mod tests {
73
74 #[test]
75 fn test_function() {
76 assert_eq!(function!(), "q_debug::macros::tests::test_function");
77
78 struct Foo {
79 bar: String,
80 }
81
82 impl Foo {
83 pub fn new() -> Self {
84 Foo {
85 bar: function!().to_string(),
86 }
87 }
88 }
89
90 assert_eq!(
91 Foo::new().bar,
92 "q_debug::macros::tests::test_function::Foo::new"
93 );
94 }
95}