1use proc_macro::TokenStream;
4use quote::quote;
5use syn::punctuated::Punctuated;
6
7#[proc_macro]
9pub fn map(input: TokenStream) -> TokenStream {
10 let Map { fields } = syn::parse_macro_input!(input as Map);
11
12 let list = fields.into_iter().map(|pair| {
13 let (k, v) = (pair.key, pair.value);
14 quote! { (#k, #v) }
15 });
16
17 quote! { [#(#list),*] }.into()
18}
19
20struct Map {
22 pub fields: Punctuated::<Field, syn::Token![,]>,
23}
24
25impl syn::parse::Parse for Map {
26 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
27 let fields = Punctuated::<Field, syn::Token![,]>::parse_terminated(input)?;
28
29 Ok(Map { fields })
30 }
31}
32
33struct Field {
35 pub key: syn::Expr,
36 pub value: syn::Expr,
37}
38
39impl syn::parse::Parse for Field {
40 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
41 let key = input.parse()?;
42
43 if input.peek(syn::Token![:]) {
44 input.parse::<syn::Token![:]>()?;
45 } else if input.peek(syn::Token![=>]) {
46 input.parse::<syn::Token![=>]>()?;
47 } else {
48 return Err(syn::Error::new(input.span(), "the expected separator is `:` or `=>` between key and value"));
49 }
50
51 let value = input.parse()?;
52
53 Ok(Field {
54 key,
55 value,
56 })
57 }
58}