#![recursion_limit = "4096"] use syn::Type; use tt_call::{parse_type, tt_call}; macro_rules! assert_type { ($($tokens:tt)*) => { tt_call! { macro = [{ parse_type }] input = [{ $($tokens)* @ }] ~~> assert_type_return! { expected = [{ $($tokens)* }] } } }; } macro_rules! assert_type_return { { expected = [{ $($expected:tt)* }] type = [{ $($actual:tt)* }] rest = [{ @ }] } => { check(stringify!($($expected)*), stringify!($($actual)*)); }; } fn check(expected: &str, actual: &str) { assert_eq!( syn::parse_str::<Type>(expected).unwrap(), syn::parse_str::<Type>(actual).unwrap(), ); } #[test] fn test_parse_type() { // Paths assert_type!(u8); assert_type!(std::collections::HashMap); assert_type!(::std::collections::HashMap); // Angle brackets assert_type!(Vec<u8>); assert_type!(<u8>::Associated); assert_type!(<u8 as Trait>::Associated); assert_type!(<u8 as Trait<T>>::Associated); assert_type!(<Vec<u8> as Trait>::Associated); assert_type!(Iterator<Item = u8>); assert_type!(RefMut<'a, u8>); // Square brackets assert_type!([u8]); assert_type!([u8; 64]); // Pointers assert_type!(*const u8); assert_type!(*mut u8); // References assert_type!(&u8); assert_type!(&mut u8); assert_type!(&'a u8); assert_type!(&'a mut u8); // Functions assert_type!(fn()); assert_type!(fn(u8)); assert_type!(fn(u8)); assert_type!(fn(u8, u8)); assert_type!(fn(a: u8, b: u8)); assert_type!(fn() -> u8); // Tuples assert_type!(()); assert_type!((u8)); assert_type!((u8,)); assert_type!((u8, u8)); // Traits assert_type!(dyn Display); assert_type!(dyn Display + Send); assert_type!(impl Display); assert_type!(impl Display + Send); assert_type!(impl Fn() -> Box<Display + Send> + 'static); // Type macros assert_type!(m!()); assert_type!(m![]); assert_type!(m! {}); assert_type!(::m!()); assert_type!(::m!(u8)); assert_type!(crate::m!(u8)); // Special punctuation assert_type!(!); assert_type!(_); } #[test] fn test_futures() { assert_type!( futures::MapErr< futures::Map< futures::sink::SendAll< futures::stream::SplitSink< futures::stream::AndThen< tokio_core::io::Framed< Client, ipc::LenDelimited<protobuf::Message::Message>, >, fn( tokio_core::io::EasyBuf, ) -> std::result::Result<protobuf::Message::Message, std::io::Error>, std::result::Result<protobuf::Message::Message, std::io::Error>, >, >, futures::stream::Map< futures::stream::SplitStream< futures::stream::AndThen< tokio_core::io::Framed< Client, ipc::LenDelimited<protobuf::Message::Message>, >, fn( tokio_core::io::EasyBuf, ) -> std::result::Result< protobuf::Message::Message, std::io::Error, >, std::result::Result<protobuf::Message::Message, std::io::Error>, >, >, H, >, >, fn( ( futures::stream::SplitSink< futures::stream::AndThen< tokio_core::io::Framed< Client, ipc::LenDelimited<protobuf::Message::Message>, >, fn( tokio_core::io::EasyBuf, ) -> std::result::Result< protobuf::Message::Message, std::io::Error, >, std::result::Result<protobuf::Message::Message, std::io::Error>, >, >, futures::stream::Map< futures::stream::SplitStream< futures::stream::AndThen< tokio_core::io::Framed< Client, ipc::LenDelimited<protobuf::Message::Message>, >, fn( tokio_core::io::EasyBuf, ) -> std::result::Result< protobuf::Message::Message, std::io::Error, >, std::result::Result<protobuf::Message::Message, std::io::Error>, >, >, H, > ), ), >, EH, > ); }