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}