pretty_name/
lib.rs

1#![doc = include_str!("../README.md")]
2
3mod type_name;
4pub use type_name::type_name;
5pub use type_name::type_name_of_val;
6
7/// Internal helper macro for caching string results in thread-local storage.
8///
9/// This macro wraps an expression that produces a `String` and caches it as a
10/// `&'static str` using thread-local `LazyCell`. Each unique macro invocation
11/// gets its own cache entry, ensuring zero runtime overhead after first use.
12#[doc(hidden)]
13#[macro_export]
14macro_rules! __with_cache {
15    ($expr:expr) => {{
16        use std::cell::LazyCell;
17        thread_local! {
18            static CACHE: LazyCell<&'static str> =
19                LazyCell::new(|| {
20                    let result = $expr;
21                    Box::leak(result.into_boxed_str())
22                });
23        }
24        CACHE.with(|cell| *LazyCell::force(cell))
25    }};
26}
27
28/// Get the name of the given local variable or constant as a string literal.
29/// 
30/// This macro checks that the identifier is valid in the current scope. If the identifier
31/// is renamed via refactoring tools, the macro call will be updated accordingly.
32/// 
33/// # Examples
34/// ```rust
35/// let my_variable = 42;
36/// const MY_CONSTANT: u32 = 42;
37/// assert_eq!(pretty_name::of_var!(my_variable), "my_variable");
38/// assert_eq!(pretty_name::of_var!(MY_CONSTANT), "MY_CONSTANT");
39/// ```
40#[macro_export]
41macro_rules! of_var {
42    ($ident:ident) => {{
43        let _ = &$ident;
44        stringify!($ident)
45    }};
46}
47
48/// Get the name of the given function.
49///
50/// Use `::<..>` syntax to exclude generic parameters in the output, see examples.
51///
52/// This macro returns `&'static str`. It caches the result and subsequent calls have
53/// zero runtime overhead.
54///
55/// This macro checks that the identifier is valid in the current scope. If the identifier
56/// is renamed via refactoring tools, the macro call will be updated accordingly.
57/// 
58/// # Examples
59/// ```rust
60/// fn my_function() {}
61/// fn my_generic_function<T>() {}
62/// fn my_generic_function_2args<T, U>() {}
63/// assert_eq!(pretty_name::of_function!(my_function), "my_function");
64/// assert_eq!(pretty_name::of_function!(my_generic_function::<..>), "my_generic_function");
65/// assert_eq!(pretty_name::of_function!(my_generic_function::<u32>), "my_generic_function::<u32>");
66/// assert_eq!(pretty_name::of_function!(my_generic_function_2args::<..>), "my_generic_function_2args");
67/// assert_eq!(pretty_name::of_function!(my_generic_function_2args::<u32, String>), "my_generic_function_2args::<u32, String>");
68/// ```
69#[macro_export]
70macro_rules! of_function {
71    // IMPLEMENTATION NOTE:
72    //   - The $ident arm magically handles auto-completion for the other arms,
73    //     especially for the $ident::<..> arm.
74    //   - The $ident::<..> arm adopts an unusual approach for identifier validation
75    //     by using `use $ident;`. This works because functions can be imported, but
76    //     lacks auto-completion support in VSCode and other editors. This means that
77    //     currently we cannot use this approach for the general case.
78    ($ident:ident) => {{
79        let _ = &$ident;
80        stringify!($ident)
81    }};
82    ($ident:ident ::<..>) => {{
83        #[allow(unused)] use $ident;
84        stringify!($ident)
85    }};
86    ($ident:ident ::<$($arg:ty),*>) => {{
87        let _ = &$ident::<$($arg),*>;
88        $crate::__with_cache!(
89            format!(
90                "{}::<{}>",
91                stringify!($ident),
92                vec![$($crate::type_name::<$arg>()),*].join(", ")))
93    }};
94}
95
96/// Get the name of the given struct field like `Type::field` as `&'static str`.
97///
98/// This macro returns `&'static str`. It caches the result and subsequent calls have
99/// zero runtime overhead.
100///
101/// This macro resolves `Self` to the appropriate type when used inside an `impl` block.
102///
103/// By default, this macro expects a simple type identifier like `Type::field`. To use
104/// types with qualified path or generic parameters, wrap the type in angle brackets
105/// like `<Type<T>>::field` or `<module::Type>::field`.
106///
107/// This macro checks that the field exists on the given type. If either the type or field
108/// is renamed via refactoring tools, the macro call will be updated accordingly.
109/// 
110/// # Examples
111/// ```rust
112/// struct MyStruct {
113///     my_field: u32,
114/// }
115/// struct MyGenericStruct<T> {
116///     my_field: T,
117/// }
118/// assert_eq!(pretty_name::of_field!(MyStruct::my_field), "MyStruct::my_field");
119/// assert_eq!(pretty_name::of_field!(<MyGenericStruct<u32>>::my_field), "<MyGenericStruct<u32>>::my_field");
120/// ```
121#[macro_export]
122macro_rules! of_field {
123    ($ty:ident :: $field:ident) => {{
124        let _ = |obj: $ty| { let _ = &obj.$field; };
125        $crate::__with_cache!(
126            format!("{}::{}", $crate::type_name::<$ty>(), stringify!($field)))
127    }};
128    (<$ty:ty> :: $field:ident) => {{
129        let _ = |obj: $ty| { let _ = &obj.$field; };
130        $crate::__with_cache!(
131            format!("<{}>::{}", $crate::type_name::<$ty>(), stringify!($field)))
132    }};
133}
134
135/// Get the name of the given method as `&'static str`.
136///
137/// This macro returns `&'static str`. It caches the result and subsequent calls have
138/// zero runtime overhead.
139///
140/// This macro resolves `Self` to the appropriate type when used inside an `impl` block.
141///
142/// By default, this macro expects a simple type identifier like `Type::field`. To use
143/// types with qualified path or generic parameters, wrap the type in angle brackets
144/// like `<Type<T>>::field` or `<module::Type>::field`.
145///
146/// This macro checks that the method exists on the given type. If either the type or method
147/// is renamed via refactoring tools, the macro call will be updated accordingly.
148///
149/// Due to implementation limitations, you cannot use `::<..>` syntax to exclude generic
150/// parameters. Use explicit type arguments instead.
151/// 
152/// # Examples
153/// ```rust
154/// struct MyStruct;
155/// impl MyStruct {
156///     fn my_method(&self) {}
157///     fn my_generic_method<T>(&self) {}
158/// }
159/// struct MyGenericStruct<T>(std::marker::PhantomData<T>);
160/// impl<T> MyGenericStruct<T> {
161///     fn my_method(&self) {}
162///     fn my_generic_method<U>(&self) {}
163/// }
164/// assert_eq!(pretty_name::of_method!(MyStruct::my_method), "MyStruct::my_method");
165/// assert_eq!(pretty_name::of_method!(MyStruct::my_generic_method::<u32>), "MyStruct::my_generic_method::<u32>");
166/// assert_eq!(pretty_name::of_method!(<MyGenericStruct<u32>>::my_method), "<MyGenericStruct<u32>>::my_method");
167/// assert_eq!(pretty_name::of_method!(<MyGenericStruct<u32>>::my_generic_method::<String>), "<MyGenericStruct<u32>>::my_generic_method::<String>");
168/// ```
169#[macro_export]
170macro_rules! of_method {
171    ($ty:ident :: $method:ident) => {{
172        let _ = &$ty::$method;
173        $crate::__with_cache!(
174            format!("{}::{}", $crate::type_name::<$ty>(), stringify!($method)))
175    }};
176    ($ty:ident :: $method:ident ::<$($arg:ty),*>) => {{
177        let _ = &$ty::$method::<$($arg),*>;
178        $crate::__with_cache!(
179            format!(
180                "{}::{}::<{}>",
181                $crate::type_name::<$ty>(),
182                stringify!($method),
183                vec![$($crate::type_name::<$arg>()),*].join(", ")))
184    }};
185
186    (<$ty:ty> :: $method:ident) => {{
187        let _ = &<$ty>::$method;
188        $crate::__with_cache!(
189            format!("<{}>::{}", $crate::type_name::<$ty>(), stringify!($method)))
190    }};
191    (<$ty:ty> :: $method:ident ::<$($arg:ty),*>) => {{
192        let _ = &<$ty>::$method::<$($arg),*>;
193        $crate::__with_cache!(
194            format!(
195                "<{}>::{}::<{}>",
196                $crate::type_name::<$ty>(),
197                stringify!($method),
198                vec![$($crate::type_name::<$arg>()),*].join(", ")))
199    }};
200}
201
202/// Get the name of the given enum variant as `&'static str`.
203///
204/// This macro returns `&'static str`. It caches the result and subsequent calls have
205/// zero runtime overhead.
206///
207/// This macro resolves `Self` to the appropriate type when used inside an `impl` block.
208///
209/// This macros supports both unit variants, tuple variants and struct variants. See
210/// examples for syntax for each variant type.
211///
212/// This macro checks that the variant exists on the given enum type. If either the type or
213/// variant is renamed via refactoring tools, the macro call will be updated accordingly.
214///
215/// This macro currently expects only simple type identifiers like `Type::field`.
216/// Support for more complex types requires the experimental feature `more_qualified_paths`
217/// (issue #86935 <https://github.com/rust-lang/rust/issues/86935>) to be stabilized.
218/// 
219/// # Examples
220/// ```rust
221/// enum MyEnum {
222///     UnitVariant,
223///     TupleVariant(u32, String),
224///     StructVariant { field: u32 },
225/// }
226/// assert_eq!(pretty_name::of_variant!(MyEnum::UnitVariant), "MyEnum::UnitVariant");
227/// assert_eq!(pretty_name::of_variant!(MyEnum::TupleVariant(..)), "MyEnum::TupleVariant");
228/// assert_eq!(pretty_name::of_variant!(MyEnum::StructVariant {..}), "MyEnum::StructVariant");
229/// ```
230#[macro_export]
231macro_rules! of_variant {
232    ($ty:ident $(::<$($ty_arg:ty),*>)? :: $variant:ident) => {{
233        let _ = |obj| match obj { $ty $(::<$($ty_arg),*>)?::$variant => {}, _ => {} };
234        $crate::__with_cache!(
235            format!("{}::{}", $crate::type_name::<$ty $(::<$($ty_arg),*>)?>(), stringify!($variant)))
236    }};
237    ($ty:ident $(::<$($ty_arg:ty),*>)? :: $variant:ident (..)) => {{
238        let _ = |obj| match obj { $ty $(::<$($ty_arg),*>)?::$variant(..) => {}, _ => {} };
239        $crate::__with_cache!(
240            format!("{}::{}", $crate::type_name::<$ty $(::<$($ty_arg),*>)?>(), stringify!($variant)))
241    }};
242    ($ty:ident $(::<$($ty_arg:ty),*>)? :: $variant:ident {..}) => {{
243        let _ = |obj| match obj { $ty $(::<$($ty_arg),*>)?::$variant { .. } => {}, _ => {} };
244        $crate::__with_cache!(
245            format!("{}::{}", $crate::type_name::<$ty $(::<$($ty_arg),*>)?>(), stringify!($variant)))
246    }};
247
248    (<$ty:ty> :: $variant:ident) => {{
249        let _ = |obj| match obj { <$ty>::$variant => {}, _ => {} };
250        $crate::__with_cache!(
251            format!("<{}>::{}", $crate::type_name::<$ty>(), stringify!($variant)))
252    }};
253    (<$ty:ty> :: $variant:ident (..)) => {{
254        let _ = |obj| match obj { <$ty>::$variant(..) => {}, _ => {} };
255        $crate::__with_cache!(
256            format!("<{}>::{}", $crate::type_name::<$ty>(), stringify!($variant)))
257    }};
258    (<$ty:ty> :: $variant:ident {..}) => {{
259        let _ = |obj| match obj { <$ty>::$variant { .. } => {}, _ => {} };
260        $crate::__with_cache!(
261            format!("<{}>::{}", $crate::type_name::<$ty>(), stringify!($variant)))
262    }};
263}