1use derive_syn_parse::Parse;
2use macroscope_utils::find_macroscope;
3use proc_macro2::Span;
4use quote::quote;
5use syn::{
6 parse::ParseStream, parse_macro_input, punctuated::Punctuated, Ident, LitStr, Path, Token,
7};
8
9#[derive(Debug, Parse)]
10struct UsingArgs {
11 crate_name: CrateName,
12 #[peek(Token![|])]
13 extra: Option<UsingArgsExtra>,
14}
15
16#[derive(Debug, Parse)]
17enum CrateName {
18 #[peek_with(is_lit_str, name = "Literal")]
19 Literal(LitStr),
20 #[peek_with(is_path, name = "Path")]
21 Path(Path),
22}
23
24impl CrateName {
25 fn path(self) -> proc_macro2::TokenStream {
26 match self {
27 CrateName::Literal(literal) => {
28 let id = Ident::new(&normalize(&literal.value()), Span::call_site());
29 quote!(#id)
30 }
31 CrateName::Path(path) => quote!(#path),
32 }
33 }
34}
35
36fn is_lit_str(token: ParseStream) -> bool {
37 token.peek(LitStr)
38}
39
40fn is_path(token: ParseStream) -> bool {
41 token.peek(syn::Token![::]) || token.peek(Ident)
42}
43
44#[derive(Debug, Parse)]
45struct UsingArgsExtra {
46 pipe: Token![|],
47 #[parse_terminated(parse_str)]
48 crates: Punctuated<LitStr, Token![|]>,
49}
50
51fn parse_str(input: ParseStream<'_>) -> syn::parse::Result<LitStr> {
52 input.parse()
53}
54
55#[proc_macro]
56pub fn build_using(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
57 let UsingArgs {
58 crate_name,
59 extra: _,
60 } = parse_macro_input!(input as UsingArgs);
61
62 let macroscope = find_macroscope();
63 let crate_name = crate_name.path();
64
65 (quote! {
73 macro_rules! using {
74 ($($path:tt)*) => {{
75 #macroscope::quote! { ::#crate_name::macros::crates::$($path)* }
76 }}
77 }
78 })
79 .into()
80
81 }
95
96fn normalize(name: &str) -> String {
97 name.replace("-", "_")
98}