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}