syn_path/
lib.rs

1#![warn(rust_2018_idioms, unreachable_pub)]
2#![deny(elided_lifetimes_in_paths)]
3#![forbid(unsafe_code)]
4
5//! This crate contains the [`path!`] macro to turn a path into a [`syn::Path`] at
6//! compile time.
7
8#[doc(hidden)]
9pub mod private {
10	pub use core::{
11		default::Default,
12		option::Option::{None, Some},
13		stringify
14	};
15	pub use proc_macro2::{Ident, Span};
16	pub use syn::{punctuated::Punctuated, Path, PathSegment};
17}
18
19/// A simple macro that can take paths of the form `my_crate::my_mod::FooBar` and
20/// `::my_crate::my_mod::FooBar` and turn them into a `syn::Path`.
21#[macro_export]
22macro_rules! path {
23	(:: $($segment:ident)::*) => {
24		$crate::private!($crate::private::Some($crate::private::Default::default()), $($segment),*)
25	};
26	($($segment:ident)::*) => {
27		$crate::private!($crate::private::None, $($segment),*)
28	};
29}
30
31#[macro_export]
32#[doc(hidden)]
33macro_rules! private {
34	($leading_colon:expr, $($segment:ident),*) => {
35		{
36			#[allow(unused_mut)]
37			let mut segments: $crate::private::Punctuated<$crate::private::PathSegment, _> = $crate::private::Default::default();
38			$(
39				segments.push($crate::private::PathSegment {
40					ident: $crate::private::Ident::new(
41						$crate::private::stringify!($segment),
42						$crate::private::Span::call_site()
43					),
44					arguments: $crate::private::Default::default()
45				});
46			)*
47			$crate::private::Path {
48				leading_colon: $leading_colon,
49				segments
50			}
51		}
52	};
53}
54
55#[cfg(test)]
56mod tests {
57	use syn::Path;
58
59	#[test]
60	fn with_leading_colon() {
61		let path = path!(::my_crate::my_mod::FooBar);
62		let expected: Path = syn::parse_str("::my_crate::my_mod::FooBar").unwrap();
63		assert_eq!(expected, path);
64	}
65
66	#[test]
67	fn without_leading_colon() {
68		let path = path!(my_crate::my_mod::FooBar);
69		let expected: Path = syn::parse_str("my_crate::my_mod::FooBar").unwrap();
70		assert_eq!(expected, path);
71	}
72}