1#![allow(clippy::tabs_in_doc_comments)]
2#![warn(rust_2018_idioms, unreachable_pub)]
3#![deny(elided_lifetimes_in_paths)]
4#![forbid(unsafe_code)]
5
6#[doc(hidden)]
133pub mod private {
134 pub use proc_macro2::{Ident, Span};
135 pub use std::{
136 boxed::Box,
137 option::Option::{None, Some},
138 stringify
139 };
140 pub use syn::{
141 punctuated::Punctuated, AngleBracketedGenericArguments, GenericArgument, Path,
142 PathArguments, PathSegment, QSelf, Type, TypePath
143 };
144
145 #[inline]
146 pub fn default<T: Default>() -> T {
147 T::default()
148 }
149
150 #[inline]
151 pub const fn len<T, const LEN: usize>(_: &[T; LEN]) -> usize {
152 LEN
153 }
154}
155
156#[macro_export]
160macro_rules! ty {
161 ($($body:tt)*) => {
162 $crate::private::Type::Path($crate::type_path!($($body)*))
163 };
164}
165
166#[macro_export]
170macro_rules! type_path {
171 (:: $($body:tt)*) => {
172 $crate::type_path_impl!($crate::private::None, $crate::path!(:: $($body)*))
173 };
174 ($segment:ident $($body:tt)*) => {
175 $crate::type_path_impl!($crate::private::None, $crate::path!($segment $($body)*))
176 };
177
178 (< $($ty_segment:ident)::* > :: $($body:tt)*) => {
179 $crate::type_path_impl!(
180 $crate::private::Some($crate::private::QSelf {
181 lt_token: $crate::private::default(),
182 ty: Box::new($crate::ty!($($ty_segment)::*)),
183 position: 0,
184 as_token: $crate::private::None,
185 gt_token: $crate::private::default()
186 }),
187 $crate::path!(:: $($body)*)
188 )
189 };
190 (< :: $($ty_segment:ident)::* > :: $($body:tt)*) => {
191 $crate::type_path_impl!(
192 $crate::private::Some($crate::private::QSelf {
193 lt_token: $crate::private::default(),
194 ty: Box::new($crate::ty!(:: $($ty_segment)::*)),
195 position: 0,
196 as_token: $crate::private::None,
197 gt_token: $crate::private::default()
198 }),
199 $crate::path!(:: $($body)*)
200 )
201 };
202
203 (< $($ty_segment:ident)::* as $($as_segment:ident)::* > :: $($body:tt)*) => {
204 $crate::type_path_impl!(
205 $crate::private::Some($crate::private::QSelf {
206 lt_token: $crate::private::default(),
207 ty: Box::new($crate::ty!($($ty_segment)::*)),
208 position: $crate::private::len(&[$($crate::private::stringify!($as_segment)),*]),
209 as_token: $crate::private::Some($crate::private::default()),
210 gt_token: $crate::private::default()
211 }),
212 $crate::path!($($as_segment)::* :: $($body)*)
213 )
214 };
215 (< :: $($ty_segment:ident)::* as $($as_segment:ident)::* > :: $($body:tt)*) => {
216 $crate::type_path_impl!(
217 $crate::private::Some($crate::private::QSelf {
218 lt_token: $crate::private::default(),
219 ty: Box::new($crate::ty!(:: $($ty_segment)::*)),
220 position: $crate::private::len(&[$($crate::private::stringify!($as_segment)),*]),
221 as_token: $crate::private::Some($crate::private::default()),
222 gt_token: $crate::private::default()
223 }),
224 $crate::path!($($as_segment)::* :: $($body)*)
225 )
226 };
227 (< $($ty_segment:ident)::* as :: $($as_segment:ident)::* > :: $($body:tt)*) => {
228 $crate::type_path_impl!(
229 $crate::private::Some($crate::private::QSelf {
230 lt_token: $crate::private::default(),
231 ty: Box::new($crate::ty!($($ty_segment)::*)),
232 position: $crate::private::len(&[$($crate::private::stringify!($as_segment)),*]),
233 as_token: $crate::private::Some($crate::private::default()),
234 gt_token: $crate::private::default()
235 }),
236 $crate::path!(:: $($as_segment)::* :: $($body)*)
237 )
238 };
239 (< :: $($ty_segment:ident)::* as :: $($as_segment:ident)::* > :: $($body:tt)*) => {
240 $crate::type_path_impl!(
241 $crate::private::Some($crate::private::QSelf {
242 lt_token: $crate::private::default(),
243 ty: Box::new($crate::ty!(:: $($ty_segment)::*)),
244 position: $crate::private::len(&[$($crate::private::stringify!($as_segment)),*]),
245 as_token: $crate::private::Some($crate::private::default()),
246 gt_token: $crate::private::default()
247 }),
248 $crate::path!(:: $($as_segment)::* :: $($body)*)
249 )
250 };
251}
252
253#[macro_export]
254#[doc(hidden)]
255macro_rules! type_path_impl {
256 ($qself:expr, $path:expr) => {
257 $crate::private::TypePath {
258 attrs: $crate::private::default(),
259 qself: $qself,
260 path: $path
261 }
262 };
263}
264
265#[macro_export]
268macro_rules! path {
269 (:: $($segment:ident)::*) => {
270 $crate::path_impl!(
271 $crate::private::Some($crate::private::default()),
272 $crate::private::PathArguments::None,
273 $($segment),*
274 )
275 };
276 ($($segment:ident)::*) => {
277 $crate::path_impl!(
278 $crate::private::None,
279 $crate::private::PathArguments::None,
280 $($segment),*
281 )
282 };
283 (:: $($segment:ident)::* < $($args:tt)*) => {
285 $crate::path_impl!(
286 $crate::private::Some($crate::private::default()),
287 $crate::path_args_impl!($crate::private::default(), $crate::private::None, $($args)*),
288 $($segment),*
289 )
290 };
291 ($($segment:ident)::* < $($args:tt)*) => {
292 $crate::path_impl!(
293 $crate::private::None,
294 $crate::path_args_impl!($crate::private::default(), $crate::private::None, $($args)*),
295 $($segment),*
296 )
297 };
298}
299
300#[macro_export]
301#[doc(hidden)]
302macro_rules! path_impl {
303 ($leading_colon:expr, $args:expr, $($segment:ident),*) => {
304 {
305 #[allow(unused_mut)]
306 let mut segments: $crate::private::Punctuated<$crate::private::PathSegment, _> = $crate::private::default();
307 $(
308 segments.push($crate::private::PathSegment {
309 ident: $crate::private::Ident::new(
310 $crate::private::stringify!($segment),
311 $crate::private::Span::call_site()
312 ),
313 arguments: $crate::private::PathArguments::None
314 });
315 )*
316 if let Some(last_segment) = segments.last_mut() {
317 last_segment.arguments = $args;
318 }
319 $crate::private::Path {
320 leading_colon: $leading_colon,
321 segments
322 }
323 }
324 };
325}
326
327#[macro_export]
328#[doc(hidden)]
329macro_rules! path_args_impl {
330 ($args:expr, $leading_colon:expr, $(>)?) => {
332 $crate::private::PathArguments::AngleBracketed(
333 $crate::private::AngleBracketedGenericArguments {
334 colon2_token: $leading_colon,
335 lt_token: $crate::private::default(),
336 args: $args,
337 gt_token: $crate::private::default()
338 }
339 )
340 };
341 ($args:expr, $leading_colon:expr, :: $($segment:ident)::* $(>)?) => {
343 $crate::path_args_impl!(
344 {
345 let mut args: $crate::private::Punctuated<$crate::private::GenericArgument, _> = $args;
346 args.push($crate::private::GenericArgument::Type($crate::ty!(:: $($segment)::*)));
347 args
348 },
349 $leading_colon,
350 )
351 };
352 ($args:expr, $leading_colon:expr, $($segment:ident)::* $(>)?) => {
353 $crate::path_args_impl!(
354 {
355 let mut args: $crate::private::Punctuated<$crate::private::GenericArgument, _> = $args;
356 args.push($crate::private::GenericArgument::Type($crate::ty!($($segment)::*)));
357 args
358 },
359 $leading_colon,
360 )
361 };
362 ($args:expr, $leading_colon:expr, :: $($segment:ident)::* $(, $($body:tt)*)?) => {
364 $crate::path_args_impl!(
365 {
366 let mut args: $crate::private::Punctuated<$crate::private::GenericArgument, _> = $args;
367 args.push($crate::private::GenericArgument::Type($crate::ty!(:: $($segment)::*)));
368 args
369 },
370 $leading_colon,
371 $($($body)*)?
372 )
373 };
374 ($args:expr, $leading_colon:expr, $($segment:ident)::* $(, $($body:tt)*)?) => {
375 $crate::path_args_impl!(
376 {
377 let mut args: $crate::private::Punctuated<$crate::private::GenericArgument, _> = $args;
378 args.push($crate::private::GenericArgument::Type($crate::ty!($($segment)::*)));
379 args
380 },
381 $leading_colon,
382 $($($body)*)?
383 )
384 };
385}
386
387#[cfg(test)]
388mod tests {
389 use std::fmt::Debug;
390 use syn::parse::Parse;
391
392 #[track_caller]
393 fn assert_eq<T>(t: T, s: &str)
394 where
395 T: Debug + Eq + Parse
396 {
397 let expected: T = syn::parse_str(s).unwrap();
398 if expected != t {
400 panic!(
401 r#"assertion `left == right` failed
402 left: {expected:#?}
403 right: {t:#?}"#
404 )
405 }
406 }
407
408 #[test]
411 fn type_with_leading_colon() {
412 assert_eq(
413 ty!(::my_crate::my_mod::FooBar),
414 "::my_crate::my_mod::FooBar"
415 );
416 }
417
418 #[test]
419 fn type_without_leading_colon() {
420 assert_eq(ty!(my_crate::my_mod::FooBar), "my_crate::my_mod::FooBar");
421 }
422
423 #[test]
424 fn type_with_qself_with_leading_colon() {
425 assert_eq(
426 ty!(<::my_crate::my_mod::FooBar>::MyType),
427 "<::my_crate::my_mod::FooBar>::MyType"
428 );
429 }
430
431 #[test]
432 fn type_with_qself_without_leading_colon() {
433 assert_eq(
434 ty!(<my_crate::my_mod::FooBar>::MyType),
435 "<my_crate::my_mod::FooBar>::MyType"
436 );
437 }
438
439 #[test]
440 fn type_with_qself_with_leading_colon_with_as_with_leading_colon() {
441 assert_eq(
442 ty!(<::my_crate::my_mod::FooBar as ::my_crate::my_mod::MyTrait>::MyType),
443 "<::my_crate::my_mod::FooBar as ::my_crate::my_mod::MyTrait>::MyType"
444 );
445 }
446
447 #[test]
448 fn type_with_qself_with_leading_colon_with_as_without_leading_colon() {
449 assert_eq(
450 ty!(<::my_crate::my_mod::FooBar as my_crate::my_mod::MyTrait>::MyType),
451 "<::my_crate::my_mod::FooBar as my_crate::my_mod::MyTrait>::MyType"
452 );
453 }
454
455 #[test]
456 fn type_with_qself_without_leading_colon_with_as_with_leading_colon() {
457 assert_eq(
458 ty!(<my_crate::my_mod::FooBar as ::my_crate::my_mod::MyTrait>::MyType),
459 "<my_crate::my_mod::FooBar as ::my_crate::my_mod::MyTrait>::MyType"
460 );
461 }
462
463 #[test]
464 fn type_with_qself_without_leading_colon_with_as_without_leading_colon() {
465 assert_eq(
466 ty!(<my_crate::my_mod::FooBar as my_crate::my_mod::MyTrait>::MyType),
467 "<my_crate::my_mod::FooBar as my_crate::my_mod::MyTrait>::MyType"
468 );
469 }
470
471 #[test]
474 fn type_path_with_leading_colon() {
475 assert_eq(
476 type_path!(::my_crate::my_mod::FooBar),
477 "::my_crate::my_mod::FooBar"
478 );
479 }
480
481 #[test]
482 fn type_path_without_leading_colon() {
483 assert_eq(
484 type_path!(my_crate::my_mod::FooBar),
485 "my_crate::my_mod::FooBar"
486 );
487 }
488
489 #[test]
490 fn type_path_with_qself_with_leading_colon() {
491 assert_eq(
492 type_path!(<::my_crate::my_mod::FooBar>::MyType),
493 "<::my_crate::my_mod::FooBar>::MyType"
494 );
495 }
496
497 #[test]
498 fn type_path_with_qself_without_leading_colon() {
499 assert_eq(
500 type_path!(<my_crate::my_mod::FooBar>::MyType),
501 "<my_crate::my_mod::FooBar>::MyType"
502 );
503 }
504
505 #[test]
506 fn type_path_with_qself_with_leading_colon_with_as_with_leading_colon() {
507 assert_eq(
508 type_path!(
509 <::my_crate::my_mod::FooBar as ::my_crate::my_mod::MyTrait>::MyType
510 ),
511 "<::my_crate::my_mod::FooBar as ::my_crate::my_mod::MyTrait>::MyType"
512 );
513 }
514
515 #[test]
516 fn type_path_with_qself_with_leading_colon_with_as_without_leading_colon() {
517 assert_eq(
518 type_path!(<::my_crate::my_mod::FooBar as my_crate::my_mod::MyTrait>::MyType),
519 "<::my_crate::my_mod::FooBar as my_crate::my_mod::MyTrait>::MyType"
520 );
521 }
522
523 #[test]
524 fn type_path_with_qself_without_leading_colon_with_as_with_leading_colon() {
525 assert_eq(
526 type_path!(<my_crate::my_mod::FooBar as ::my_crate::my_mod::MyTrait>::MyType),
527 "<my_crate::my_mod::FooBar as ::my_crate::my_mod::MyTrait>::MyType"
528 );
529 }
530
531 #[test]
532 fn type_path_with_qself_without_leading_colon_with_as_without_leading_colon() {
533 assert_eq(
534 type_path!(<my_crate::my_mod::FooBar as my_crate::my_mod::MyTrait>::MyType),
535 "<my_crate::my_mod::FooBar as my_crate::my_mod::MyTrait>::MyType"
536 );
537 }
538
539 #[test]
542 fn path_with_leading_colon() {
543 assert_eq(
544 path!(::my_crate::my_mod::FooBar),
545 "::my_crate::my_mod::FooBar"
546 );
547 }
548
549 #[test]
550 fn path_without_leading_colon() {
551 assert_eq(path!(my_crate::my_mod::FooBar), "my_crate::my_mod::FooBar");
552 }
553
554 #[test]
555 fn path_with_leading_colon_with_args() {
556 assert_eq(
557 path!(::my_crate::my_mod::FooBar<::some::Argument, AnotherArgument>),
558 "::my_crate::my_mod::FooBar<::some::Argument, AnotherArgument>"
559 )
560 }
561
562 #[test]
563 fn path_without_leading_colon_with_args() {
564 assert_eq(
565 path!(my_crate::my_mod::FooBar<::some::Argument, AnotherArgument>),
566 "my_crate::my_mod::FooBar<::some::Argument, AnotherArgument>"
567 )
568 }
569}