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}