#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md"))]
use proc_macro::TokenStream;
use quote::quote;
use syn::punctuated::Punctuated;
#[proc_macro]
pub fn parse_map(input: TokenStream) -> TokenStream {
let Map { fields } = syn::parse_macro_input!(input as Map);
let list = fields.into_iter().map(|pair| {
let (k, v) = (pair.key, pair.value);
quote! { (#k, #v) }
});
quote! { [#(#list),*] }.into()
}
struct Map {
pub fields: Punctuated<Field, syn::Token![,]>,
}
impl syn::parse::Parse for Map {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let fields = Punctuated::<Field, syn::Token![,]>::parse_terminated(input)?;
Ok(Map { fields })
}
}
struct Field {
pub key: syn::Expr,
pub value: syn::Expr,
}
impl syn::parse::Parse for Field {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let key = input.parse()?;
if input.peek(syn::Token![:]) {
input.parse::<syn::Token![:]>()?;
} else if input.peek(syn::Token![=>]) {
input.parse::<syn::Token![=>]>()?;
} else {
return Err(syn::Error::new(
input.span(),
"the expected separator is `:` or `=>` between key and value",
));
}
let value = input.parse()?;
Ok(Field { key, value })
}
}