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