use std::collections::HashMap;
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::{
parse::{Parse, ParseStream},
punctuated::Punctuated,
Ident, Lit, MetaNameValue, Result, Token,
};
pub struct Setting {
pub settings: HashMap<String, String>,
}
macro_rules! default {
($map:ident, $key:expr) => {
$map.entry($key.to_string())
.or_insert_with(|| $key.to_string())
};
($map:ident, $key:expr, $value:expr) => {
$map.entry($key.to_string())
.or_insert_with(|| $value.to_string())
};
}
impl Parse for Setting {
fn parse(input: ParseStream) -> Result<Self> {
let a: Punctuated<_, Token![,]> = input.parse_terminated(MetaNameValue::parse)?;
let mut map: HashMap<_, _> = a
.iter()
.map(|nv| {
let lit = if let Lit::Str(s) = &nv.lit {
s.value()
} else {
panic!()
};
(nv.ident.to_string(), lit)
})
.collect();
default!(map, "players");
default!(map, "check_player");
Ok(Setting { settings: map })
}
}
pub fn use_default(settings: Setting) -> TokenStream {
let name = Ident::new(&settings.settings["players"], Span::call_site());
let check_player = Ident::new(&settings.settings["check_player"], Span::call_site());
quote! {
fn add_player(&mut self, p: Player) -> Result<()> {
self.#check_player(&p)?;
self.players.add(p);
Ok(())
}
fn current_player(&self) -> &String {
self.#name.current_ident()
}
fn next_player(&mut self) -> &String {
self.stage = 0;
if self.#name.next_player() == 0 {
self.round += 1;
}
self.#name.current_ident()
}
fn is_start(&self) -> bool {
self.#name.is_start()
}
}
}