#![allow(clippy::tabs_in_doc_comments)]
#![warn(rust_2018_idioms, unreachable_pub)]
#![deny(elided_lifetimes_in_paths)]
#![forbid(unsafe_code)]
#[doc(hidden)]
pub mod private {
pub use proc_macro2::{Ident, Span};
pub use std::{
boxed::Box,
option::Option::{None, Some},
stringify
};
pub use syn::{
punctuated::Punctuated, AngleBracketedGenericArguments, GenericArgument, Path,
PathArguments, PathSegment, QSelf, Type, TypePath
};
#[inline]
pub fn default<T: Default>() -> T {
T::default()
}
#[inline]
pub const fn len<T, const LEN: usize>(_: &[T; LEN]) -> usize {
LEN
}
}
#[macro_export]
macro_rules! ty {
($($body:tt)*) => {
$crate::private::Type::Path($crate::type_path!($($body)*))
};
}
#[macro_export]
macro_rules! type_path {
(:: $($body:tt)*) => {
$crate::type_path_impl!($crate::private::None, $crate::path!(:: $($body)*))
};
($segment:ident $($body:tt)*) => {
$crate::type_path_impl!($crate::private::None, $crate::path!($segment $($body)*))
};
(< $($ty_segment:ident)::* > :: $($body:tt)*) => {
$crate::type_path_impl!(
$crate::private::Some($crate::private::QSelf {
lt_token: $crate::private::default(),
ty: Box::new($crate::ty!($($ty_segment)::*)),
position: 0,
as_token: $crate::private::None,
gt_token: $crate::private::default()
}),
$crate::path!(:: $($body)*)
)
};
(< :: $($ty_segment:ident)::* > :: $($body:tt)*) => {
$crate::type_path_impl!(
$crate::private::Some($crate::private::QSelf {
lt_token: $crate::private::default(),
ty: Box::new($crate::ty!(:: $($ty_segment)::*)),
position: 0,
as_token: $crate::private::None,
gt_token: $crate::private::default()
}),
$crate::path!(:: $($body)*)
)
};
(< $($ty_segment:ident)::* as $($as_segment:ident)::* > :: $($body:tt)*) => {
$crate::type_path_impl!(
$crate::private::Some($crate::private::QSelf {
lt_token: $crate::private::default(),
ty: Box::new($crate::ty!($($ty_segment)::*)),
position: $crate::private::len(&[$($crate::private::stringify!($as_segment)),*]),
as_token: $crate::private::Some($crate::private::default()),
gt_token: $crate::private::default()
}),
$crate::path!($($as_segment)::* :: $($body)*)
)
};
(< :: $($ty_segment:ident)::* as $($as_segment:ident)::* > :: $($body:tt)*) => {
$crate::type_path_impl!(
$crate::private::Some($crate::private::QSelf {
lt_token: $crate::private::default(),
ty: Box::new($crate::ty!(:: $($ty_segment)::*)),
position: $crate::private::len(&[$($crate::private::stringify!($as_segment)),*]),
as_token: $crate::private::Some($crate::private::default()),
gt_token: $crate::private::default()
}),
$crate::path!($($as_segment)::* :: $($body)*)
)
};
(< $($ty_segment:ident)::* as :: $($as_segment:ident)::* > :: $($body:tt)*) => {
$crate::type_path_impl!(
$crate::private::Some($crate::private::QSelf {
lt_token: $crate::private::default(),
ty: Box::new($crate::ty!($($ty_segment)::*)),
position: $crate::private::len(&[$($crate::private::stringify!($as_segment)),*]),
as_token: $crate::private::Some($crate::private::default()),
gt_token: $crate::private::default()
}),
$crate::path!(:: $($as_segment)::* :: $($body)*)
)
};
(< :: $($ty_segment:ident)::* as :: $($as_segment:ident)::* > :: $($body:tt)*) => {
$crate::type_path_impl!(
$crate::private::Some($crate::private::QSelf {
lt_token: $crate::private::default(),
ty: Box::new($crate::ty!(:: $($ty_segment)::*)),
position: $crate::private::len(&[$($crate::private::stringify!($as_segment)),*]),
as_token: $crate::private::Some($crate::private::default()),
gt_token: $crate::private::default()
}),
$crate::path!(:: $($as_segment)::* :: $($body)*)
)
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! type_path_impl {
($qself:expr, $path:expr) => {
$crate::private::TypePath {
attrs: $crate::private::default(),
qself: $qself,
path: $path
}
};
}
#[macro_export]
macro_rules! path {
(:: $($segment:ident)::*) => {
$crate::path_impl!(
$crate::private::Some($crate::private::default()),
$crate::private::PathArguments::None,
$($segment),*
)
};
($($segment:ident)::*) => {
$crate::path_impl!(
$crate::private::None,
$crate::private::PathArguments::None,
$($segment),*
)
};
(:: $($segment:ident)::* < $($args:tt)*) => {
$crate::path_impl!(
$crate::private::Some($crate::private::default()),
$crate::path_args_impl!($crate::private::default(), $crate::private::None, $($args)*),
$($segment),*
)
};
($($segment:ident)::* < $($args:tt)*) => {
$crate::path_impl!(
$crate::private::None,
$crate::path_args_impl!($crate::private::default(), $crate::private::None, $($args)*),
$($segment),*
)
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! path_impl {
($leading_colon:expr, $args:expr, $($segment:ident),*) => {
{
#[allow(unused_mut)]
let mut segments: $crate::private::Punctuated<$crate::private::PathSegment, _> = $crate::private::default();
$(
segments.push($crate::private::PathSegment {
ident: $crate::private::Ident::new(
$crate::private::stringify!($segment),
$crate::private::Span::call_site()
),
arguments: $crate::private::PathArguments::None
});
)*
if let Some(last_segment) = segments.last_mut() {
last_segment.arguments = $args;
}
$crate::private::Path {
leading_colon: $leading_colon,
segments
}
}
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! path_args_impl {
($args:expr, $leading_colon:expr, $(>)?) => {
$crate::private::PathArguments::AngleBracketed(
$crate::private::AngleBracketedGenericArguments {
colon2_token: $leading_colon,
lt_token: $crate::private::default(),
args: $args,
gt_token: $crate::private::default()
}
)
};
($args:expr, $leading_colon:expr, :: $($segment:ident)::* $(>)?) => {
$crate::path_args_impl!(
{
let mut args: $crate::private::Punctuated<$crate::private::GenericArgument, _> = $args;
args.push($crate::private::GenericArgument::Type($crate::ty!(:: $($segment)::*)));
args
},
$leading_colon,
)
};
($args:expr, $leading_colon:expr, $($segment:ident)::* $(>)?) => {
$crate::path_args_impl!(
{
let mut args: $crate::private::Punctuated<$crate::private::GenericArgument, _> = $args;
args.push($crate::private::GenericArgument::Type($crate::ty!($($segment)::*)));
args
},
$leading_colon,
)
};
($args:expr, $leading_colon:expr, :: $($segment:ident)::* $(, $($body:tt)*)?) => {
$crate::path_args_impl!(
{
let mut args: $crate::private::Punctuated<$crate::private::GenericArgument, _> = $args;
args.push($crate::private::GenericArgument::Type($crate::ty!(:: $($segment)::*)));
args
},
$leading_colon,
$($($body)*)?
)
};
($args:expr, $leading_colon:expr, $($segment:ident)::* $(, $($body:tt)*)?) => {
$crate::path_args_impl!(
{
let mut args: $crate::private::Punctuated<$crate::private::GenericArgument, _> = $args;
args.push($crate::private::GenericArgument::Type($crate::ty!($($segment)::*)));
args
},
$leading_colon,
$($($body)*)?
)
};
}
#[cfg(test)]
mod tests {
use std::fmt::Debug;
use syn::parse::Parse;
#[track_caller]
fn assert_eq<T>(t: T, s: &str)
where
T: Debug + Eq + Parse
{
let expected: T = syn::parse_str(s).unwrap();
if expected != t {
panic!(
r#"assertion `left == right` failed
left: {expected:#?}
right: {t:#?}"#
)
}
}
#[test]
fn type_with_leading_colon() {
assert_eq(
ty!(::my_crate::my_mod::FooBar),
"::my_crate::my_mod::FooBar"
);
}
#[test]
fn type_without_leading_colon() {
assert_eq(ty!(my_crate::my_mod::FooBar), "my_crate::my_mod::FooBar");
}
#[test]
fn type_with_qself_with_leading_colon() {
assert_eq(
ty!(<::my_crate::my_mod::FooBar>::MyType),
"<::my_crate::my_mod::FooBar>::MyType"
);
}
#[test]
fn type_with_qself_without_leading_colon() {
assert_eq(
ty!(<my_crate::my_mod::FooBar>::MyType),
"<my_crate::my_mod::FooBar>::MyType"
);
}
#[test]
fn type_with_qself_with_leading_colon_with_as_with_leading_colon() {
assert_eq(
ty!(<::my_crate::my_mod::FooBar as ::my_crate::my_mod::MyTrait>::MyType),
"<::my_crate::my_mod::FooBar as ::my_crate::my_mod::MyTrait>::MyType"
);
}
#[test]
fn type_with_qself_with_leading_colon_with_as_without_leading_colon() {
assert_eq(
ty!(<::my_crate::my_mod::FooBar as my_crate::my_mod::MyTrait>::MyType),
"<::my_crate::my_mod::FooBar as my_crate::my_mod::MyTrait>::MyType"
);
}
#[test]
fn type_with_qself_without_leading_colon_with_as_with_leading_colon() {
assert_eq(
ty!(<my_crate::my_mod::FooBar as ::my_crate::my_mod::MyTrait>::MyType),
"<my_crate::my_mod::FooBar as ::my_crate::my_mod::MyTrait>::MyType"
);
}
#[test]
fn type_with_qself_without_leading_colon_with_as_without_leading_colon() {
assert_eq(
ty!(<my_crate::my_mod::FooBar as my_crate::my_mod::MyTrait>::MyType),
"<my_crate::my_mod::FooBar as my_crate::my_mod::MyTrait>::MyType"
);
}
#[test]
fn type_path_with_leading_colon() {
assert_eq(
type_path!(::my_crate::my_mod::FooBar),
"::my_crate::my_mod::FooBar"
);
}
#[test]
fn type_path_without_leading_colon() {
assert_eq(
type_path!(my_crate::my_mod::FooBar),
"my_crate::my_mod::FooBar"
);
}
#[test]
fn type_path_with_qself_with_leading_colon() {
assert_eq(
type_path!(<::my_crate::my_mod::FooBar>::MyType),
"<::my_crate::my_mod::FooBar>::MyType"
);
}
#[test]
fn type_path_with_qself_without_leading_colon() {
assert_eq(
type_path!(<my_crate::my_mod::FooBar>::MyType),
"<my_crate::my_mod::FooBar>::MyType"
);
}
#[test]
fn type_path_with_qself_with_leading_colon_with_as_with_leading_colon() {
assert_eq(
type_path!(
<::my_crate::my_mod::FooBar as ::my_crate::my_mod::MyTrait>::MyType
),
"<::my_crate::my_mod::FooBar as ::my_crate::my_mod::MyTrait>::MyType"
);
}
#[test]
fn type_path_with_qself_with_leading_colon_with_as_without_leading_colon() {
assert_eq(
type_path!(<::my_crate::my_mod::FooBar as my_crate::my_mod::MyTrait>::MyType),
"<::my_crate::my_mod::FooBar as my_crate::my_mod::MyTrait>::MyType"
);
}
#[test]
fn type_path_with_qself_without_leading_colon_with_as_with_leading_colon() {
assert_eq(
type_path!(<my_crate::my_mod::FooBar as ::my_crate::my_mod::MyTrait>::MyType),
"<my_crate::my_mod::FooBar as ::my_crate::my_mod::MyTrait>::MyType"
);
}
#[test]
fn type_path_with_qself_without_leading_colon_with_as_without_leading_colon() {
assert_eq(
type_path!(<my_crate::my_mod::FooBar as my_crate::my_mod::MyTrait>::MyType),
"<my_crate::my_mod::FooBar as my_crate::my_mod::MyTrait>::MyType"
);
}
#[test]
fn path_with_leading_colon() {
assert_eq(
path!(::my_crate::my_mod::FooBar),
"::my_crate::my_mod::FooBar"
);
}
#[test]
fn path_without_leading_colon() {
assert_eq(path!(my_crate::my_mod::FooBar), "my_crate::my_mod::FooBar");
}
#[test]
fn path_with_leading_colon_with_args() {
assert_eq(
path!(::my_crate::my_mod::FooBar<::some::Argument, AnotherArgument>),
"::my_crate::my_mod::FooBar<::some::Argument, AnotherArgument>"
)
}
#[test]
fn path_without_leading_colon_with_args() {
assert_eq(
path!(my_crate::my_mod::FooBar<::some::Argument, AnotherArgument>),
"my_crate::my_mod::FooBar<::some::Argument, AnotherArgument>"
)
}
}