ident_util/lib.rs
1//!
2//! Rust name_of! Macro
3//!
4//! MIT License
5//! Copyright (c) 2018 SilentByte <https://silentbyte.com/>
6//!
7
8#![crate_name = "ident_util"]
9
10/// Takes a binding, type, const, or function as an argument and returns its
11/// unqualified string representation. If the identifier does not exist
12/// in the current context, the macro will cause a compilation error.
13/// This macro is mainly intended for debugging purposes and to improve
14/// the refactoring experience compared to plain `stringify!()`.
15///
16/// The syntax depends on the type of the identifier:
17///
18/// 1. Bindings to variables and functions require no annotation,
19/// e.g. `name_of!(some_binding)`.
20///
21/// 2. Types and structs require the keyword `type`, e.g. `name_of!(type SomeType)`.
22/// Alternatively, the macro `name_of_type!(SomeType)` may be used.
23///
24/// 3. Fields within structs are referred to with the `in` keyword,
25/// e.g. `name_of!(some_field in SomeType)`.
26///
27///
28/// # Examples
29///
30/// ```
31/// # #[macro_use] extern crate ident_util;
32/// # fn main() {
33/// struct TestStruct {
34/// test_field: i32,
35/// }
36///
37/// impl TestStruct {
38/// const TEST_CONST: i32 = 1;
39/// }
40///
41/// struct GenericStruct<T> {
42/// test_field_t: T,
43/// }
44///
45/// fn greet() -> &'static str {
46/// "Hi, World"
47/// }
48///
49/// let text = "Hello, World!";
50///
51/// println!("Binding `{}` holds `{}`.", name_of!(text), text);
52///
53/// println!("Function `{}` says `{}`.", name_of!(greet), greet());
54///
55/// println!(
56/// "Struct `{}` has a field `{}`.",
57/// name_of!(type TestStruct),
58/// name_of!(test_field in TestStruct)
59/// );
60///
61/// println!(
62/// "Generic Struct `{}` has a field `{}`.",
63/// name_of!(type GenericStruct<String>),
64/// name_of!(test_field_t in GenericStruct<String>)
65/// );
66///
67/// println!(
68/// "Struct `{}` has an associated constant `{}`.",
69/// name_of!(type TestStruct),
70/// name_of!(const TEST_CONST in TestStruct)
71/// );
72///
73/// println!(
74/// "Standard types such as `{}` and `{}` also work.",
75/// name_of!(type i32),
76/// name_of!(type f64)
77/// );
78///
79/// # }
80/// ```
81#[macro_export]
82macro_rules! name_of {
83 // Covers Bindings
84 ($n: ident) => {{
85 let _ = || {
86 &$n;
87 };
88 stringify!($n)
89 }};
90
91 // Covers Types
92 (type $t: ty) => {{
93 $crate::name_of_type!($t)
94 }};
95
96 // Covers Struct Fields
97 ($n: ident in $t: ty) => {{
98 let _ = |f: $t| {
99 let _ = &f.$n;
100 };
101 stringify!($n)
102 }};
103
104 // Covers Struct Constants
105 (const $n: ident in $t: ty) => {{
106 let _ = || {
107 let _ = &<$t>::$n;
108 };
109 stringify!($n)
110 }};
111}
112
113/// Takes the name of a type as its sole parameter,
114/// e.g. `name_of_type!(SomeStruct)` or `name_of_type!(f64)`.
115///
116/// It is an alternative to the `name_of!(type T)` macro, specifically for types.
117///
118/// # Examples
119///
120/// ```
121/// # #[macro_use] extern crate ident_util;
122/// # fn main() {
123/// struct TestStruct {
124/// test_field: i32
125/// }
126///
127/// println!("Struct is called `{}`.", name_of_type!(TestStruct));
128/// println!("Type is called `{}`.", name_of_type!(i32));
129///
130/// # }
131/// ```
132#[macro_export]
133macro_rules! name_of_type {
134 // Covers Types
135 ($t: ty) => {{
136 let _ = || {
137 let _: $t;
138 };
139 stringify!($t)
140 }};
141}
142
143/// Takes the path of a type/mod/const.. as its path &str,
144/// e.g. `path_of!(web::info::Foo)`.
145///
146/// # Examples
147///
148/// ```
149/// # #[macro_use] extern crate ident_util;
150/// use web::info::Foo;
151///
152/// # fn main() {
153///
154/// println!("struct path `{}`.", path_of!(web::info::Foo));
155///
156/// # }
157/// ```
158#[macro_export]
159macro_rules! path_of {
160 ($p: path) => {
161 stringify!($p)
162 };
163}
164
165#[cfg(test)]
166mod tests {
167 fn test_fn() {
168 //
169 }
170
171 struct TestStruct {
172 test_field: i32,
173 }
174
175 impl TestStruct {
176 const TEST_CONST: i32 = 1;
177 }
178
179 struct TestGenericStruct<T> {
180 test_field: T,
181 }
182
183 struct TestGenericStructMultiType<T, U> {
184 test_field_t: T,
185 test_field_u: U,
186 }
187
188 #[test]
189 fn name_of_binding() {
190 let test_variable = 123;
191 assert_eq!(name_of!(test_variable), "test_variable");
192 }
193
194 #[test]
195 fn name_of_fn() {
196 assert_eq!(name_of!(test_fn), "test_fn");
197 }
198
199 #[test]
200 fn name_of_type() {
201 assert_eq!(name_of!(type i32), "i32");
202 assert_eq!(name_of_type!(i32), "i32");
203 }
204
205 #[test]
206 fn path_of() {
207 assert_eq!(path_of!(test_fn), "test_fn");
208 }
209
210 #[test]
211 fn name_of_struct() {
212 assert_eq!(name_of!(type TestStruct), "TestStruct");
213 assert_eq!(name_of_type!(TestStruct), "TestStruct");
214 }
215
216 #[test]
217 fn name_of_generic_struct() {
218 assert_eq!(
219 name_of!(type TestGenericStruct<i32>),
220 "TestGenericStruct<i32>"
221 );
222
223 assert_eq!(
224 name_of_type!(TestGenericStruct<i32>),
225 "TestGenericStruct<i32>"
226 );
227 }
228
229 #[test]
230 fn name_of_generic_multi_type_struct() {
231 assert_eq!(
232 name_of!(type TestGenericStructMultiType<i32, TestGenericStruct<String>>),
233 "TestGenericStructMultiType<i32, TestGenericStruct<String>>"
234 );
235
236 assert_eq!(
237 name_of_type!( TestGenericStructMultiType<i32, TestGenericStruct<String>>),
238 "TestGenericStructMultiType<i32, TestGenericStruct<String>>"
239 );
240 }
241
242 #[test]
243 fn name_of_struct_field() {
244 assert_eq!(name_of!(test_field in TestStruct), "test_field");
245 }
246
247 #[test]
248 fn name_of_generic_struct_field() {
249 assert_eq!(name_of!(test_field in TestGenericStruct<i32>), "test_field");
250 }
251
252 #[test]
253 fn name_of_generic_multi_type_struct_field() {
254 assert_eq!(
255 name_of!(test_field_t in TestGenericStructMultiType<i32, TestGenericStruct<String>>),
256 "test_field_t"
257 );
258
259 assert_eq!(
260 name_of!(test_field_u in TestGenericStructMultiType<i32, TestGenericStruct<String>>),
261 "test_field_u"
262 );
263 }
264
265 #[test]
266 fn name_of_struct_constant() {
267 assert_eq!(name_of!(const TEST_CONST in TestStruct), "TEST_CONST");
268 }
269}