Skip to main content

macron_map/
lib.rs

1#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md"))]
2
3//! See the documentation here [macron documentation](https://docs.rs/macron)
4
5use proc_macro::TokenStream;
6use quote::quote;
7use syn::punctuated::Punctuated;
8
9/// The key-value collection parser
10#[proc_macro]
11pub fn parse_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
22/// The key-value collection
23struct 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
35/// The key-value collection field
36struct 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(
51                input.span(),
52                "the expected separator is `:` or `=>` between key and value",
53            ));
54        }
55
56        let value = input.parse()?;
57
58        Ok(Field { key, value })
59    }
60}