#![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, Path, 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 {
(:: $($segment:ident)::*) => {
$crate::private::Type::Path($crate::type_path!(:: $($segment)::*))
};
($($segment:ident)::*) => {
$crate::private::Type::Path($crate::type_path!($($segment)::*))
};
(< $($ty_segment:ident)::* > :: $($segment:ident)::*) => {
$crate::private::Type::Path($crate::type_path!(<$($ty_segment)::*>::$($segment)::*))
};
(< :: $($ty_segment:ident)::* > :: $($segment:ident)::*) => {
$crate::private::Type::Path($crate::type_path!(<:: $($ty_segment)::*>::$($segment)::*))
};
(< $($ty_segment:ident)::* as $($as_segment:ident)::* > :: $($segment:ident)::*) => {
$crate::private::Type::Path(
$crate::type_path!(<$($ty_segment)::* as $($as_segment)::*>::$($segment)::*)
)
};
(< :: $($ty_segment:ident)::* as $($as_segment:ident)::* > :: $($segment:ident)::*) => {
$crate::private::Type::Path(
$crate::type_path!(<:: $($ty_segment)::* as $($as_segment)::*>::$($segment)::*)
)
};
(< $($ty_segment:ident)::* as :: $($as_segment:ident)::* > :: $($segment:ident)::*) => {
$crate::private::Type::Path(
$crate::type_path!(<$($ty_segment)::* as :: $($as_segment)::*>::$($segment)::*)
)
};
(< :: $($ty_segment:ident)::* as :: $($as_segment:ident)::* > :: $($segment:ident)::*) => {
$crate::private::Type::Path(
$crate::type_path!(<:: $($ty_segment)::* as :: $($as_segment)::*>::$($segment)::*)
)
};
}
#[macro_export]
macro_rules! type_path {
(:: $($segment:ident)::*) => {
$crate::type_path_impl!($crate::private::None, $crate::path!(:: $($segment)::*))
};
($($segment:ident)::*) => {
$crate::type_path_impl!($crate::private::None, $crate::path!($($segment)::*))
};
(< $($ty_segment:ident)::* > :: $($segment:ident)::*) => {
$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!(:: $($segment)::*)
)
};
(< :: $($ty_segment:ident)::* > :: $($segment:ident)::*) => {
$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!(:: $($segment)::*)
)
};
(< $($ty_segment:ident)::* as $($as_segment:ident)::* > :: $($segment:ident)::*) => {
$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)::* :: $($segment)::*)
)
};
(< :: $($ty_segment:ident)::* as $($as_segment:ident)::* > :: $($segment:ident)::*) => {
$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)::* :: $($segment)::*)
)
};
(< $($ty_segment:ident)::* as :: $($as_segment:ident)::* > :: $($segment:ident)::*) => {
$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)::* :: $($segment)::*)
)
};
(< :: $($ty_segment:ident)::* as :: $($as_segment:ident)::* > :: $($segment:ident)::*) => {
$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)::* :: $($segment)::*)
)
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! type_path_impl {
($qself:expr, $path:expr) => {
$crate::private::TypePath {
qself: $qself,
path: $path
}
};
}
#[macro_export]
macro_rules! path {
(:: $($segment:ident)::*) => {
$crate::path_impl!($crate::private::Some($crate::private::default()), $($segment),*)
};
($($segment:ident)::*) => {
$crate::path_impl!($crate::private::None, $($segment),*)
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! path_impl {
($leading_colon: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::default()
});
)*
$crate::private::Path {
leading_colon: $leading_colon,
segments
}
}
};
}
#[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();
assert_eq!(expected, 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");
}
}