1#![doc = include_str!("../README.md")]
2use std::fmt;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub struct CodePath {
7 context: &'static str,
8 location: &'static str,
9 scope: &'static str,
10}
11
12impl CodePath {
13 #[must_use]
15 pub const fn new(context: &'static str, location: &'static str, scope: &'static str) -> Self {
16 Self {
17 context,
18 location,
19 scope,
20 }
21 }
22}
23
24impl fmt::Display for CodePath {
25 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26 if !self.context.is_empty() {
27 write!(f, "{} in ", self.context)?;
28 }
29 write!(f, "{} at {}", self.scope, self.location)
30 }
31}
32
33impl From<CodePath> for String {
34 fn from(val: CodePath) -> Self {
35 val.to_string()
36 }
37}
38
39#[macro_export]
45macro_rules! code_path {
46 ($($context:expr_2021),* $(,)?) => {
47 $crate::CodePath::new(
48 concat!($($context),*),
49 $crate::code_loc!(),
50 $crate::code_scope!(),
51 )
52 };
53}
54
55#[macro_export]
57macro_rules! code_scope {
58 () => {{
59 const fn f() {}
60 fn type_name_of<T>(_: T) -> &'static str {
61 ::std::any::type_name::<T>()
62 }
63 type_name_of(f)
64 .strip_suffix("::f")
65 .unwrap_or_default()
66 .trim_end_matches("::{{closure}}")
67 }};
68}
69
70#[macro_export]
72macro_rules! code_loc {
73 () => {
74 concat!(file!(), ":", line!())
75 };
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 #[test]
83 fn nesting() {
84 fn foo() -> &'static str {
85 fn bar() -> &'static str {
86 code_scope!()
87 }
88 bar()
89 }
90
91 assert_eq!(foo(), "code_path::tests::nesting::foo::bar");
92 }
93
94 #[test]
95 fn ending_cloures() {
96 fn foo() -> &'static str {
97 #[allow(clippy::redundant_closure_call)]
98 (|| (|| code_scope!())())()
99 }
100 assert_eq!(foo(), "code_path::tests::ending_cloures::foo");
101 }
102
103 #[test]
104 fn literal_context() {
105 let CodePath { context, .. } = code_path!(42);
106
107 assert_eq!(context, "42");
108
109 let CodePath {
110 context: multi_context,
111 ..
112 } = code_path!("answer: ", 42);
113 assert_eq!(multi_context, "answer: 42");
114 }
115}