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 `OnceCell`. 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::OnceCell;
17        thread_local!(static CACHE: OnceCell<&'static str> = OnceCell::new());
18        CACHE.with(|cell| *cell.get_or_init(|| {
19            let result = $expr;
20            Box::leak(result.into_boxed_str())
21        }))
22    }};
23}
24
25/// Get the name of the given local variable or constant as a string literal.
26/// 
27/// This macro checks that the identifier is valid in the current scope. If the identifier
28/// is renamed via refactoring tools, the macro call will be updated accordingly.
29/// 
30/// # Examples
31/// ```rust
32/// let my_variable = 42;
33/// const MY_CONSTANT: u32 = 42;
34/// assert_eq!(pretty_name::of_var!(my_variable), "my_variable");
35/// assert_eq!(pretty_name::of_var!(MY_CONSTANT), "MY_CONSTANT");
36/// ```
37#[macro_export]
38macro_rules! of_var {
39    ($ident:ident) => {{
40        let _ = &$ident;
41        stringify!($ident)
42    }};
43}
44
45/// Get the name of the given function as a `&'static str`.
46///
47/// Use a `::<..>` placeholder to exclude generic parameters in the output, see examples.
48/// 
49/// # Examples
50/// ```rust
51/// fn my_function() {}
52/// fn my_generic_function<T>() {}
53/// fn my_generic_function_2args<T, U>() {}
54/// assert_eq!(pretty_name::of_function!(my_function), "my_function");
55/// assert_eq!(pretty_name::of_function!(my_generic_function::<..>), "my_generic_function");
56/// assert_eq!(pretty_name::of_function!(my_generic_function::<u32>), "my_generic_function::<u32>");
57/// assert_eq!(pretty_name::of_function!(my_generic_function_2args::<..>), "my_generic_function_2args");
58/// assert_eq!(pretty_name::of_function!(my_generic_function_2args::<u32, String>), "my_generic_function_2args::<u32, String>");
59/// ```
60#[macro_export]
61macro_rules! of_function {
62    // IMPLEMENTATION NOTE:
63    //   - The $ident arm magically handles auto-completion for the other arms,
64    //     especially for the $ident::<..> arm.
65    //   - The $ident::<..> arm adopts an unusual approach for identifier validation
66    //     by using `use $ident;`. This works because functions can be imported, but
67    //     lacks auto-completion support in VSCode and other editors. This means that
68    //     currently we cannot use this approach for the general case.
69    ($ident:ident) => {{
70        let _ = &$ident;
71        stringify!($ident)
72    }};
73    ($ident:ident ::<..>) => {{
74        #[allow(unused)] use $ident;
75        stringify!($ident)
76    }};
77    ($ident:ident ::<$($arg:ty),*>) => {{
78        let _ = &$ident::<$($arg),*>;
79        $crate::__with_cache!(
80            format!(
81                "{}::<{}>",
82                stringify!($ident),
83                vec![$($crate::type_name::<$arg>()),*].join(", ")))
84    }};
85}
86
87/// Get the name of the given type as a `&'static str`.
88/// 
89/// This macro resolves `Self` to the appropriate type when used inside an `impl` block.
90/// 
91/// If the given type is a single identifier and is not `Self`, the macro expands to a
92/// string literal at compile time. For more complex types, the macro uses runtime type
93/// name retrieval with caching.
94/// 
95/// # Examples
96/// ```rust
97/// struct MyStruct;
98/// struct MyGenericStruct<T>(std::marker::PhantomData<T>);
99/// assert_eq!(pretty_name::of_type!(MyStruct), "MyStruct");
100/// assert_eq!(pretty_name::of_type!(MyGenericStruct<u32>), "MyGenericStruct<u32>");
101/// ```
102#[macro_export]
103macro_rules! of_type {
104    (Self) => {{
105        $crate::type_name::<Self>()
106    }};
107    ($ty:ident) => {{
108        stringify!($ty)
109    }};
110    ($ty:ty) => {{
111        $crate::type_name::<$ty>()
112    }};
113}
114
115/// Get the name of the given struct field like `Type::field` as a `&'static str`.
116///
117/// This macro resolves `Self` to the appropriate type when used inside an `impl` block.
118///
119/// By default, this macro expects a simple type identifier like `Type::field`. To use
120/// types with qualified path or generic parameters, wrap the type in angle brackets
121/// like `<Type<T>>::field` or `<module::Type>::field`.
122/// 
123/// If the *Type* part is a single identifier and is not `Self`, the macro expands to a
124/// string literal at compile time. For more complex types, the macro uses runtime type
125/// name retrieval with caching.
126/// 
127/// # Examples
128/// ```rust
129/// struct MyStruct {
130///     my_field: u32,
131/// }
132/// struct MyGenericStruct<T> {
133///     my_field: T,
134/// }
135/// assert_eq!(pretty_name::of_field!(MyStruct::my_field), "MyStruct::my_field");
136/// assert_eq!(pretty_name::of_field!(<MyGenericStruct<u32>>::my_field), "<MyGenericStruct<u32>>::my_field");
137/// ```
138#[macro_export]
139macro_rules! of_field {
140    (Self:: $field:ident) => {{
141        let _ = |obj: Self| { let _ = &obj.$field; };
142        $crate::__with_cache!(
143            format!("{}::{}", $crate::type_name::<Self>(), stringify!($field)))
144    }};
145    ($ty:ident :: $field:ident) => {{
146        let _ = |obj: $ty| { let _ = &obj.$field; };
147        concat!(stringify!($ty), "::", stringify!($field))
148    }};
149    (<$ty:ty> :: $field:ident) => {{
150        let _ = |obj: $ty| { let _ = &obj.$field; };
151        $crate::__with_cache!(
152            format!("<{}>::{}", $crate::type_name::<$ty>(), stringify!($field)))
153    }};
154}
155
156/// Get the name of the given method like `Type::method` as a `&'static str`.
157///
158/// This macro resolves `Self` to the appropriate type when used inside an `impl` block.
159///
160/// By default, this macro expects a simple type identifier like `Type::field`. To use
161/// types with qualified path or generic parameters, wrap the type in angle brackets
162/// like `<Type<T>>::field` or `<module::Type>::field`.
163/// 
164/// If both the *Type* and *method* parts are single identifiers and the *Type* part is
165/// not `Self`, the macro expands to a string literal at compile time. For more complex
166/// types, the macro uses runtime type name retrieval with caching.
167///
168/// Due to implementation limitations, you cannot use the `::<..>` placeholder to exclude
169/// generic parameters. Use explicit type arguments instead.
170/// 
171/// # Examples
172/// ```rust
173/// struct MyStruct;
174/// impl MyStruct {
175///     fn my_method(&self) {}
176///     fn my_generic_method<T>(&self) {}
177/// }
178/// struct MyGenericStruct<T>(std::marker::PhantomData<T>);
179/// impl<T> MyGenericStruct<T> {
180///     fn my_method(&self) {}
181///     fn my_generic_method<U>(&self) {}
182/// }
183/// assert_eq!(pretty_name::of_method!(MyStruct::my_method), "MyStruct::my_method");
184/// assert_eq!(pretty_name::of_method!(MyStruct::my_generic_method::<u32>), "MyStruct::my_generic_method::<u32>");
185/// assert_eq!(pretty_name::of_method!(<MyGenericStruct<u32>>::my_method), "<MyGenericStruct<u32>>::my_method");
186/// assert_eq!(pretty_name::of_method!(<MyGenericStruct<u32>>::my_generic_method::<String>), "<MyGenericStruct<u32>>::my_generic_method::<String>");
187/// ```
188#[macro_export]
189macro_rules! of_method {
190    (Self:: $method:ident) => {{
191        let _ = &Self::$method;
192        $crate::__with_cache!(
193            format!("{}::{}", $crate::type_name::<Self>(), stringify!($method)))
194    }};
195    ($ty:ident :: $method:ident) => {{
196        let _ = &$ty::$method;
197        concat!(stringify!($ty), "::", stringify!($method))
198    }};
199    ($ty:ident :: $method:ident ::<$($arg:ty),*>) => {{
200        let _ = &$ty::$method::<$($arg),*>;
201        $crate::__with_cache!(
202            format!(
203                "{}::{}::<{}>",
204                $crate::type_name::<$ty>(),
205                stringify!($method),
206                vec![$($crate::type_name::<$arg>()),*].join(", ")))
207    }};
208
209    (<$ty:ty> :: $method:ident) => {{
210        let _ = &<$ty>::$method;
211        $crate::__with_cache!(
212            format!("<{}>::{}", $crate::type_name::<$ty>(), stringify!($method)))
213    }};
214    (<$ty:ty> :: $method:ident ::<$($arg:ty),*>) => {{
215        let _ = &<$ty>::$method::<$($arg),*>;
216        $crate::__with_cache!(
217            format!(
218                "<{}>::{}::<{}>",
219                $crate::type_name::<$ty>(),
220                stringify!($method),
221                vec![$($crate::type_name::<$arg>()),*].join(", ")))
222    }};
223}
224
225/// Get the name of the given enum variant as a `&'static str`.
226///
227/// This macro resolves `Self` to the appropriate type when used inside an `impl` block.
228///
229/// This macros supports both unit variants, tuple variants and struct variants. See
230/// examples for syntax for each variant type.
231/// 
232/// If the *Type* part is a single identifier and is not `Self`, the macro expands to a
233/// string literal at compile time. For more complex types, the macro uses runtime type
234/// name retrieval with caching.
235///
236/// This macro currently expects only simple type identifiers.
237/// Support for more complex types requires the experimental feature `more_qualified_paths`
238/// (issue #86935 <https://github.com/rust-lang/rust/issues/86935>) to be stabilized (or
239/// enabled via `#![feature(more_qualified_paths)]` if using a nightly compiler).
240/// 
241/// # Examples
242/// ```rust
243/// enum MyEnum {
244///     UnitVariant,
245///     TupleVariant(u32, String),
246///     StructVariant { field: u32 },
247/// }
248/// assert_eq!(pretty_name::of_variant!(MyEnum::UnitVariant), "MyEnum::UnitVariant");
249/// assert_eq!(pretty_name::of_variant!(MyEnum::TupleVariant(..)), "MyEnum::TupleVariant");
250/// assert_eq!(pretty_name::of_variant!(MyEnum::StructVariant {..}), "MyEnum::StructVariant");
251/// ```
252#[macro_export]
253macro_rules! of_variant {
254    (Self:: $variant:ident) => {{
255        let _ = |obj: Self| match obj { Self::$variant => {}, _ => {} };
256        $crate::__with_cache!(
257            format!("{}::{}", $crate::type_name::<Self>(), stringify!($variant)))
258    }};
259    (Self:: $variant:ident (..)) => {{
260        let _ = |obj: Self| match obj { Self::$variant(..) => {}, _ => {} };
261        $crate::__with_cache!(
262            format!("{}::{}", $crate::type_name::<Self>(), stringify!($variant)))
263    }};
264    (Self:: $variant:ident {..}) => {{
265        let _ = |obj: Self| match obj { Self::$variant { .. } => {}, _ => {} };
266        $crate::__with_cache!(
267            format!("{}::{}", $crate::type_name::<Self>(), stringify!($variant)))
268    }};
269
270    ($ty:ident :: $variant:ident) => {{
271        let _ = |obj: $ty| match obj { $ty::$variant => {}, _ => {} };
272        concat!(stringify!($ty), "::", stringify!($variant))
273    }};
274    ($ty:ident :: $variant:ident (..)) => {{
275        let _ = |obj: $ty| match obj { $ty::$variant(..) => {}, _ => {} };
276        concat!(stringify!($ty), "::", stringify!($variant))
277    }};
278    ($ty:ident :: $variant:ident {..}) => {{
279        let _ = |obj: $ty| match obj { $ty::$variant { .. } => {}, _ => {} };
280        concat!(stringify!($ty), "::", stringify!($variant))
281    }};
282
283    (<$ty:ty> :: $variant:ident) => {{
284        let _ = |obj: $ty| match obj { <$ty>::$variant => {}, _ => {} };
285        $crate::__with_cache!(
286            format!("<{}>::{}", $crate::type_name::<$ty>(), stringify!($variant)))
287    }};
288    (<$ty:ty> :: $variant:ident (..)) => {{
289        let _ = |obj: $ty| match obj { <$ty>::$variant(..) => {}, _ => {} };
290        $crate::__with_cache!(
291            format!("<{}>::{}", $crate::type_name::<$ty>(), stringify!($variant)))
292    }};
293    (<$ty:ty> :: $variant:ident {..}) => {{
294        let _ = |obj: $ty| match obj { <$ty>::$variant { .. } => {}, _ => {} };
295        $crate::__with_cache!(
296            format!("<{}>::{}", $crate::type_name::<$ty>(), stringify!($variant)))
297    }};
298}
299
300#[test] fn test_self() {
301    struct MyStruct {
302        my_field: u32,
303    }
304    impl MyStruct {
305        fn my_method<T>(&self) {}
306        fn test(&self) {
307            assert_eq!(of_type!(Self), "MyStruct");
308            assert_eq!(of_field!(Self::my_field), "MyStruct::my_field");
309            assert_eq!(of_method!(Self::my_method::<u32>), "MyStruct::my_method::<u32>");
310        }
311    }
312
313    let my_struct = MyStruct { my_field: 42 };
314    my_struct.test();
315}