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