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 struct field like `Type::field` as a `&'static str`.
91///
92/// This macro resolves `Self` to the appropriate type when used inside an `impl` block.
93///
94/// By default, this macro expects a simple type identifier like `Type::field`. To use
95/// types with qualified path or generic parameters, wrap the type in angle brackets
96/// like `<Type<T>>::field` or `<module::Type>::field`.
97///
98/// # Examples
99/// ```rust
100/// struct MyStruct {
101/// my_field: u32,
102/// }
103/// struct MyGenericStruct<T> {
104/// my_field: T,
105/// }
106/// assert_eq!(pretty_name::of_field!(MyStruct::my_field), "MyStruct::my_field");
107/// assert_eq!(pretty_name::of_field!(<MyGenericStruct<u32>>::my_field), "<MyGenericStruct<u32>>::my_field");
108/// ```
109#[macro_export]
110macro_rules! of_field {
111 (Self:: $field:ident) => {{
112 let _ = |obj: $ty| { let _ = &obj.$field; };
113 $crate::__with_cache!(
114 format!("{}::{}", $crate::type_name::<Self>(), stringify!($field)))
115 }};
116 ($ty:ident :: $field:ident) => {{
117 let _ = |obj: $ty| { let _ = &obj.$field; };
118 concat!(stringify!($ty), "::", stringify!($field))
119 }};
120 (<$ty:ty> :: $field:ident) => {{
121 let _ = |obj: $ty| { let _ = &obj.$field; };
122 $crate::__with_cache!(
123 format!("<{}>::{}", $crate::type_name::<$ty>(), stringify!($field)))
124 }};
125}
126
127/// Get the name of the given method as a `&'static str`.
128///
129/// This macro resolves `Self` to the appropriate type when used inside an `impl` block.
130///
131/// By default, this macro expects a simple type identifier like `Type::field`. To use
132/// types with qualified path or generic parameters, wrap the type in angle brackets
133/// like `<Type<T>>::field` or `<module::Type>::field`.
134///
135/// Due to implementation limitations, you cannot use the `::<..>` placeholder to exclude
136/// generic parameters. Use explicit type arguments instead.
137///
138/// # Examples
139/// ```rust
140/// struct MyStruct;
141/// impl MyStruct {
142/// fn my_method(&self) {}
143/// fn my_generic_method<T>(&self) {}
144/// }
145/// struct MyGenericStruct<T>(std::marker::PhantomData<T>);
146/// impl<T> MyGenericStruct<T> {
147/// fn my_method(&self) {}
148/// fn my_generic_method<U>(&self) {}
149/// }
150/// assert_eq!(pretty_name::of_method!(MyStruct::my_method), "MyStruct::my_method");
151/// assert_eq!(pretty_name::of_method!(MyStruct::my_generic_method::<u32>), "MyStruct::my_generic_method::<u32>");
152/// assert_eq!(pretty_name::of_method!(<MyGenericStruct<u32>>::my_method), "<MyGenericStruct<u32>>::my_method");
153/// assert_eq!(pretty_name::of_method!(<MyGenericStruct<u32>>::my_generic_method::<String>), "<MyGenericStruct<u32>>::my_generic_method::<String>");
154/// ```
155#[macro_export]
156macro_rules! of_method {
157 (Self:: $method:ident) => {{
158 let _ = &$ty::$method;
159 $crate::__with_cache!(
160 format!("{}::{}", $crate::type_name::<Self>(), stringify!($method)))
161 }};
162 ($ty:ident :: $method:ident) => {{
163 let _ = &$ty::$method;
164 concat!(stringify!($ty), "::", stringify!($method))
165 }};
166 ($ty:ident :: $method:ident ::<$($arg:ty),*>) => {{
167 let _ = &$ty::$method::<$($arg),*>;
168 $crate::__with_cache!(
169 format!(
170 "{}::{}::<{}>",
171 $crate::type_name::<$ty>(),
172 stringify!($method),
173 vec![$($crate::type_name::<$arg>()),*].join(", ")))
174 }};
175
176 (<$ty:ty> :: $method:ident) => {{
177 let _ = &<$ty>::$method;
178 $crate::__with_cache!(
179 format!("<{}>::{}", $crate::type_name::<$ty>(), stringify!($method)))
180 }};
181 (<$ty:ty> :: $method:ident ::<$($arg:ty),*>) => {{
182 let _ = &<$ty>::$method::<$($arg),*>;
183 $crate::__with_cache!(
184 format!(
185 "<{}>::{}::<{}>",
186 $crate::type_name::<$ty>(),
187 stringify!($method),
188 vec![$($crate::type_name::<$arg>()),*].join(", ")))
189 }};
190}
191
192/// Get the name of the given enum variant as a `&'static str`.
193///
194/// This macro resolves `Self` to the appropriate type when used inside an `impl` block.
195///
196/// This macros supports both unit variants, tuple variants and struct variants. See
197/// examples for syntax for each variant type.
198///
199/// This macro currently expects only simple type identifiers like `Type::field`.
200/// Support for more complex types requires the experimental feature `more_qualified_paths`
201/// (issue #86935 <https://github.com/rust-lang/rust/issues/86935>) to be stabilized (or
202/// enabled via `#![feature(more_qualified_paths)]` if using a nightly compiler).
203///
204/// # Examples
205/// ```rust
206/// enum MyEnum {
207/// UnitVariant,
208/// TupleVariant(u32, String),
209/// StructVariant { field: u32 },
210/// }
211/// assert_eq!(pretty_name::of_variant!(MyEnum::UnitVariant), "MyEnum::UnitVariant");
212/// assert_eq!(pretty_name::of_variant!(MyEnum::TupleVariant(..)), "MyEnum::TupleVariant");
213/// assert_eq!(pretty_name::of_variant!(MyEnum::StructVariant {..}), "MyEnum::StructVariant");
214/// ```
215#[macro_export]
216macro_rules! of_variant {
217 (Self:: $variant:ident) => {{
218 let _ = |obj| match obj { Self::$variant => {}, _ => {} };
219 $crate::__with_cache!(
220 format!("{}::{}", $crate::type_name::<Self>(), stringify!($variant)))
221 }};
222 (Self:: $variant:ident (..)) => {{
223 let _ = |obj| match obj { Self::$variant(..) => {}, _ => {} };
224 $crate::__with_cache!(
225 format!("{}::{}", $crate::type_name::<Self>(), stringify!($variant)))
226 }};
227 (Self:: $variant:ident {..}) => {{
228 let _ = |obj| match obj { Self::$variant { .. } => {}, _ => {} };
229 $crate::__with_cache!(
230 format!("{}::{}", $crate::type_name::<Self>(), stringify!($variant)))
231 }};
232
233 ($ty:ident :: $variant:ident) => {{
234 let _ = |obj| match obj { $ty::$variant => {}, _ => {} };
235 concat!(stringify!($ty), "::", stringify!($variant))
236 }};
237 ($ty:ident :: $variant:ident (..)) => {{
238 let _ = |obj| match obj { $ty::$variant(..) => {}, _ => {} };
239 concat!(stringify!($ty), "::", stringify!($variant))
240 }};
241 ($ty:ident :: $variant:ident {..}) => {{
242 let _ = |obj| match obj { $ty::$variant { .. } => {}, _ => {} };
243 concat!(stringify!($ty), "::", stringify!($variant))
244 }};
245
246 (<$ty:ty> :: $variant:ident) => {{
247 let _ = |obj| match obj { <$ty>::$variant => {}, _ => {} };
248 $crate::__with_cache!(
249 format!("<{}>::{}", $crate::type_name::<$ty>(), stringify!($variant)))
250 }};
251 (<$ty:ty> :: $variant:ident (..)) => {{
252 let _ = |obj| match obj { <$ty>::$variant(..) => {}, _ => {} };
253 $crate::__with_cache!(
254 format!("<{}>::{}", $crate::type_name::<$ty>(), stringify!($variant)))
255 }};
256 (<$ty:ty> :: $variant:ident {..}) => {{
257 let _ = |obj| match obj { <$ty>::$variant { .. } => {}, _ => {} };
258 $crate::__with_cache!(
259 format!("<{}>::{}", $crate::type_name::<$ty>(), stringify!($variant)))
260 }};
261}