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