1#![warn(rust_2018_idioms, unreachable_pub)]
2#![deny(elided_lifetimes_in_paths)]
3#![forbid(unsafe_code)]
4
5#[doc(hidden)]
13pub mod private {
14 pub use proc_macro2::{Ident, Span};
15 pub use std::{
16 boxed::Box,
17 option::Option::{None, Some},
18 stringify
19 };
20 pub use syn::{punctuated::Punctuated, Path, PathSegment, QSelf, Type, TypePath};
21
22 #[inline]
23 pub fn default<T: Default>() -> T {
24 T::default()
25 }
26
27 #[inline]
28 pub const fn len<T, const LEN: usize>(_: &[T; LEN]) -> usize {
29 LEN
30 }
31}
32
33#[macro_export]
37macro_rules! ty {
38 (:: $($segment:ident)::*) => {
39 $crate::private::Type::Path($crate::type_path!(:: $($segment)::*))
40 };
41 ($($segment:ident)::*) => {
42 $crate::private::Type::Path($crate::type_path!($($segment)::*))
43 };
44
45 (< $($ty_segment:ident)::* > :: $($segment:ident)::*) => {
46 $crate::private::Type::Path($crate::type_path!(<$($ty_segment)::*>::$($segment)::*))
47 };
48 (< :: $($ty_segment:ident)::* > :: $($segment:ident)::*) => {
49 $crate::private::Type::Path($crate::type_path!(<:: $($ty_segment)::*>::$($segment)::*))
50 };
51
52 (< $($ty_segment:ident)::* as $($as_segment:ident)::* > :: $($segment:ident)::*) => {
53 $crate::private::Type::Path(
54 $crate::type_path!(<$($ty_segment)::* as $($as_segment)::*>::$($segment)::*)
55 )
56 };
57 (< :: $($ty_segment:ident)::* as $($as_segment:ident)::* > :: $($segment:ident)::*) => {
58 $crate::private::Type::Path(
59 $crate::type_path!(<:: $($ty_segment)::* as $($as_segment)::*>::$($segment)::*)
60 )
61 };
62 (< $($ty_segment:ident)::* as :: $($as_segment:ident)::* > :: $($segment:ident)::*) => {
63 $crate::private::Type::Path(
64 $crate::type_path!(<$($ty_segment)::* as :: $($as_segment)::*>::$($segment)::*)
65 )
66 };
67 (< :: $($ty_segment:ident)::* as :: $($as_segment:ident)::* > :: $($segment:ident)::*) => {
68 $crate::private::Type::Path(
69 $crate::type_path!(<:: $($ty_segment)::* as :: $($as_segment)::*>::$($segment)::*)
70 )
71 };
72}
73
74#[macro_export]
78macro_rules! type_path {
79 (:: $($segment:ident)::*) => {
80 $crate::type_path_impl!($crate::private::None, $crate::path!(:: $($segment)::*))
81 };
82 ($($segment:ident)::*) => {
83 $crate::type_path_impl!($crate::private::None, $crate::path!($($segment)::*))
84 };
85
86 (< $($ty_segment:ident)::* > :: $($segment:ident)::*) => {
87 $crate::type_path_impl!(
88 $crate::private::Some($crate::private::QSelf {
89 lt_token: $crate::private::default(),
90 ty: Box::new($crate::ty!($($ty_segment)::*)),
91 position: 0,
92 as_token: $crate::private::None,
93 gt_token: $crate::private::default()
94 }),
95 $crate::path!(:: $($segment)::*)
96 )
97 };
98 (< :: $($ty_segment:ident)::* > :: $($segment:ident)::*) => {
99 $crate::type_path_impl!(
100 $crate::private::Some($crate::private::QSelf {
101 lt_token: $crate::private::default(),
102 ty: Box::new($crate::ty!(:: $($ty_segment)::*)),
103 position: 0,
104 as_token: $crate::private::None,
105 gt_token: $crate::private::default()
106 }),
107 $crate::path!(:: $($segment)::*)
108 )
109 };
110
111 (< $($ty_segment:ident)::* as $($as_segment:ident)::* > :: $($segment:ident)::*) => {
112 $crate::type_path_impl!(
113 $crate::private::Some($crate::private::QSelf {
114 lt_token: $crate::private::default(),
115 ty: Box::new($crate::ty!($($ty_segment)::*)),
116 position: $crate::private::len(&[$($crate::private::stringify!($as_segment)),*]),
117 as_token: $crate::private::Some($crate::private::default()),
118 gt_token: $crate::private::default()
119 }),
120 $crate::path!($($as_segment)::* :: $($segment)::*)
121 )
122 };
123 (< :: $($ty_segment:ident)::* as $($as_segment:ident)::* > :: $($segment:ident)::*) => {
124 $crate::type_path_impl!(
125 $crate::private::Some($crate::private::QSelf {
126 lt_token: $crate::private::default(),
127 ty: Box::new($crate::ty!(:: $($ty_segment)::*)),
128 position: $crate::private::len(&[$($crate::private::stringify!($as_segment)),*]),
129 as_token: $crate::private::Some($crate::private::default()),
130 gt_token: $crate::private::default()
131 }),
132 $crate::path!($($as_segment)::* :: $($segment)::*)
133 )
134 };
135 (< $($ty_segment:ident)::* as :: $($as_segment:ident)::* > :: $($segment:ident)::*) => {
136 $crate::type_path_impl!(
137 $crate::private::Some($crate::private::QSelf {
138 lt_token: $crate::private::default(),
139 ty: Box::new($crate::ty!($($ty_segment)::*)),
140 position: $crate::private::len(&[$($crate::private::stringify!($as_segment)),*]),
141 as_token: $crate::private::Some($crate::private::default()),
142 gt_token: $crate::private::default()
143 }),
144 $crate::path!(:: $($as_segment)::* :: $($segment)::*)
145 )
146 };
147 (< :: $($ty_segment:ident)::* as :: $($as_segment:ident)::* > :: $($segment:ident)::*) => {
148 $crate::type_path_impl!(
149 $crate::private::Some($crate::private::QSelf {
150 lt_token: $crate::private::default(),
151 ty: Box::new($crate::ty!(:: $($ty_segment)::*)),
152 position: $crate::private::len(&[$($crate::private::stringify!($as_segment)),*]),
153 as_token: $crate::private::Some($crate::private::default()),
154 gt_token: $crate::private::default()
155 }),
156 $crate::path!(:: $($as_segment)::* :: $($segment)::*)
157 )
158 };
159}
160
161#[macro_export]
162#[doc(hidden)]
163macro_rules! type_path_impl {
164 ($qself:expr, $path:expr) => {
165 $crate::private::TypePath {
166 qself: $qself,
167 path: $path
168 }
169 };
170}
171
172#[macro_export]
175macro_rules! path {
176 (:: $($segment:ident)::*) => {
177 $crate::path_impl!($crate::private::Some($crate::private::default()), $($segment),*)
178 };
179 ($($segment:ident)::*) => {
180 $crate::path_impl!($crate::private::None, $($segment),*)
181 };
182}
183
184#[macro_export]
185#[doc(hidden)]
186macro_rules! path_impl {
187 ($leading_colon:expr, $($segment:ident),*) => {
188 {
189 #[allow(unused_mut)]
190 let mut segments: $crate::private::Punctuated<$crate::private::PathSegment, _> = $crate::private::default();
191 $(
192 segments.push($crate::private::PathSegment {
193 ident: $crate::private::Ident::new(
194 $crate::private::stringify!($segment),
195 $crate::private::Span::call_site()
196 ),
197 arguments: $crate::private::default()
198 });
199 )*
200 $crate::private::Path {
201 leading_colon: $leading_colon,
202 segments
203 }
204 }
205 };
206}
207
208#[cfg(test)]
209mod tests {
210 use std::fmt::Debug;
211 use syn::parse::Parse;
212
213 #[track_caller]
214 fn assert_eq<T>(t: T, s: &str)
215 where
216 T: Debug + Eq + Parse
217 {
218 let expected: T = syn::parse_str(s).unwrap();
219 assert_eq!(expected, t);
220 }
221
222 #[test]
225 fn type_with_leading_colon() {
226 assert_eq(
227 ty!(::my_crate::my_mod::FooBar),
228 "::my_crate::my_mod::FooBar"
229 );
230 }
231
232 #[test]
233 fn type_without_leading_colon() {
234 assert_eq(ty!(my_crate::my_mod::FooBar), "my_crate::my_mod::FooBar");
235 }
236
237 #[test]
238 fn type_with_qself_with_leading_colon() {
239 assert_eq(
240 ty!(<::my_crate::my_mod::FooBar>::MyType),
241 "<::my_crate::my_mod::FooBar>::MyType"
242 );
243 }
244
245 #[test]
246 fn type_with_qself_without_leading_colon() {
247 assert_eq(
248 ty!(<my_crate::my_mod::FooBar>::MyType),
249 "<my_crate::my_mod::FooBar>::MyType"
250 );
251 }
252
253 #[test]
254 fn type_with_qself_with_leading_colon_with_as_with_leading_colon() {
255 assert_eq(
256 ty!(<::my_crate::my_mod::FooBar as ::my_crate::my_mod::MyTrait>::MyType),
257 "<::my_crate::my_mod::FooBar as ::my_crate::my_mod::MyTrait>::MyType"
258 );
259 }
260
261 #[test]
262 fn type_with_qself_with_leading_colon_with_as_without_leading_colon() {
263 assert_eq(
264 ty!(<::my_crate::my_mod::FooBar as my_crate::my_mod::MyTrait>::MyType),
265 "<::my_crate::my_mod::FooBar as my_crate::my_mod::MyTrait>::MyType"
266 );
267 }
268
269 #[test]
270 fn type_with_qself_without_leading_colon_with_as_with_leading_colon() {
271 assert_eq(
272 ty!(<my_crate::my_mod::FooBar as ::my_crate::my_mod::MyTrait>::MyType),
273 "<my_crate::my_mod::FooBar as ::my_crate::my_mod::MyTrait>::MyType"
274 );
275 }
276
277 #[test]
278 fn type_with_qself_without_leading_colon_with_as_without_leading_colon() {
279 assert_eq(
280 ty!(<my_crate::my_mod::FooBar as my_crate::my_mod::MyTrait>::MyType),
281 "<my_crate::my_mod::FooBar as my_crate::my_mod::MyTrait>::MyType"
282 );
283 }
284
285 #[test]
288 fn type_path_with_leading_colon() {
289 assert_eq(
290 type_path!(::my_crate::my_mod::FooBar),
291 "::my_crate::my_mod::FooBar"
292 );
293 }
294
295 #[test]
296 fn type_path_without_leading_colon() {
297 assert_eq(
298 type_path!(my_crate::my_mod::FooBar),
299 "my_crate::my_mod::FooBar"
300 );
301 }
302
303 #[test]
304 fn type_path_with_qself_with_leading_colon() {
305 assert_eq(
306 type_path!(<::my_crate::my_mod::FooBar>::MyType),
307 "<::my_crate::my_mod::FooBar>::MyType"
308 );
309 }
310
311 #[test]
312 fn type_path_with_qself_without_leading_colon() {
313 assert_eq(
314 type_path!(<my_crate::my_mod::FooBar>::MyType),
315 "<my_crate::my_mod::FooBar>::MyType"
316 );
317 }
318
319 #[test]
320 fn type_path_with_qself_with_leading_colon_with_as_with_leading_colon() {
321 assert_eq(
322 type_path!(
323 <::my_crate::my_mod::FooBar as ::my_crate::my_mod::MyTrait>::MyType
324 ),
325 "<::my_crate::my_mod::FooBar as ::my_crate::my_mod::MyTrait>::MyType"
326 );
327 }
328
329 #[test]
330 fn type_path_with_qself_with_leading_colon_with_as_without_leading_colon() {
331 assert_eq(
332 type_path!(<::my_crate::my_mod::FooBar as my_crate::my_mod::MyTrait>::MyType),
333 "<::my_crate::my_mod::FooBar as my_crate::my_mod::MyTrait>::MyType"
334 );
335 }
336
337 #[test]
338 fn type_path_with_qself_without_leading_colon_with_as_with_leading_colon() {
339 assert_eq(
340 type_path!(<my_crate::my_mod::FooBar as ::my_crate::my_mod::MyTrait>::MyType),
341 "<my_crate::my_mod::FooBar as ::my_crate::my_mod::MyTrait>::MyType"
342 );
343 }
344
345 #[test]
346 fn type_path_with_qself_without_leading_colon_with_as_without_leading_colon() {
347 assert_eq(
348 type_path!(<my_crate::my_mod::FooBar as my_crate::my_mod::MyTrait>::MyType),
349 "<my_crate::my_mod::FooBar as my_crate::my_mod::MyTrait>::MyType"
350 );
351 }
352
353 #[test]
356 fn path_with_leading_colon() {
357 assert_eq(
358 path!(::my_crate::my_mod::FooBar),
359 "::my_crate::my_mod::FooBar"
360 );
361 }
362
363 #[test]
364 fn path_without_leading_colon() {
365 assert_eq(path!(my_crate::my_mod::FooBar), "my_crate::my_mod::FooBar");
366 }
367}