unwind_context/func_name.rs
1#[doc(hidden)]
2/// Strips module path from a function name.
3///
4/// This is an auxiliary function and is used in [`func_name!`] macro.
5///
6/// # Examples
7///
8/// ```rust
9/// assert_eq!(
10/// unwind_context::func_name_from_item_type_name(
11/// "unwind_context",
12/// "unwind_context::func1::Item",
13/// ),
14/// "func1"
15/// );
16/// ```
17///
18/// [`func_name!`]: macro@crate::func_name
19#[must_use]
20pub fn func_name_from_item_type_name(
21 module_path: &'static str,
22 subitem: &'static str,
23) -> &'static str {
24 let name = str::strip_suffix(subitem, "::Item").unwrap_or(subitem);
25 let name = str::strip_suffix(name, "::{{closure}}").unwrap_or(name);
26 let name = str::strip_prefix(name, module_path).unwrap_or(name);
27 let name = str::strip_prefix(name, "::").unwrap_or(name);
28 name
29}
30
31/// Returns the name of the function where the macro is invoked. Returns a
32/// `&'static str`.
33///
34/// # Note
35///
36/// This is intended for diagnostic use and the exact output is not guaranteed.
37/// It provides a best-effort description, but the output may change between
38/// versions of the compiler.
39///
40/// In short: use this for debugging, avoid using the output to affect program
41/// behavior.
42///
43/// # Examples
44///
45/// ```
46/// let current_function_name = unwind_context::func_name!();
47/// println!("defined in function: {current_function_name}");
48/// ```
49#[macro_export]
50macro_rules! func_name {
51 () => {{
52 struct Item;
53 let module_path = ::core::module_path!();
54 let item_type_name = ::core::any::type_name::<Item>();
55
56 $crate::func_name_from_item_type_name(module_path, item_type_name)
57 }};
58}
59
60#[cfg(test)]
61mod tests {
62 #[test]
63 fn test_func_name() {
64 fn foo() -> &'static str {
65 func_name!()
66 }
67 fn bar() -> &'static str {
68 func_name!()
69 }
70 fn baz() -> &'static str {
71 func_name!()
72 }
73
74 assert!(foo().contains("foo"));
75 assert!(bar().contains("bar"));
76 assert!(baz().contains("baz"));
77 }
78}