use crate::*;
use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use syn::{Lit, LitStr, Meta, NestedMeta};
struct MenuTitle(LitStr);
impl ToTokens for MenuTitle {
fn to_tokens(&self, tokens: &mut TokenStream) {
let lit = &self.0;
tokens.extend(quote! {
.title(#lit)
});
}
}
#[derive(Default)]
struct MetaMenuDesc {
title: Option<LitStr>,
fmt: FieldFormatting,
}
fn parse_arg_nested(
MetaMenuDesc {
ref mut title,
fmt:
FieldFormatting {
ref mut chip,
ref mut prefix,
ref mut new_line,
default: ref mut disp_default,
..
},
}: &mut MetaMenuDesc,
arg: String,
nested: &NestedMeta,
span: NestedMeta,
) {
match arg.as_str() {
s @ "title" => run_nested_str(s, nested, title),
s @ "chip" => run_nested_str(s, nested, chip),
s @ "prefix" => run_nested_str(s, nested, prefix),
s @ "new_line" => run_nested_bool(s, nested, new_line),
s @ "display_default" => run_nested_bool(s, nested, disp_default),
s => abort_invalid_arg_name(span, s),
}
}
fn parse_arg_nv(
MetaMenuDesc {
ref mut title,
fmt:
FieldFormatting {
ref mut chip,
ref mut prefix,
ref mut new_line,
default: ref mut disp_default,
..
},
}: &mut MetaMenuDesc,
arg: String,
lit: Lit,
span: NestedMeta,
) {
match arg.as_str() {
s @ "title" => run_nv_str(s, lit, title),
s @ "chip" => run_nv_str(s, lit, chip),
s @ "prefix" => run_nv_str(s, lit, prefix),
s @ "new_line" => run_nv_bool(s, lit, new_line),
s @ "display_default" => run_nv_bool(s, lit, disp_default),
s => abort_invalid_arg_name(span, s),
}
}
impl From<Meta> for MetaMenuDesc {
fn from(meta: Meta) -> Self {
let mut desc = MetaMenuDesc::default();
parse(&mut desc, parse_arg_nested, parse_arg_nv, meta);
let MetaMenuDesc {
title,
fmt:
FieldFormatting {
chip,
prefix,
new_line,
default: disp_default,
..
},
} = desc;
let custom_fmt =
chip.is_some() || prefix.is_some() || new_line.is_some() || disp_default.is_some();
let some_omitted =
!(chip.is_some() && prefix.is_some() && new_line.is_some() && disp_default.is_some());
Self {
title,
fmt: FieldFormatting {
chip,
prefix,
new_line,
default: disp_default,
custom_fmt,
some_omitted,
},
}
}
}
struct AllMenuInit {
title: Option<MenuTitle>,
fmt: FieldFormatting,
}
impl ToTokens for AllMenuInit {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.title.to_tokens(tokens);
self.fmt.to_tokens(tokens);
}
}
impl From<Meta> for AllMenuInit {
fn from(meta: Meta) -> Self {
let desc = MetaMenuDesc::from(meta);
let title = desc.title.map(MenuTitle);
Self {
title,
fmt: desc.fmt,
}
}
}
pub(crate) struct MenuInit {
all: Option<AllMenuInit>,
pub fields: Vec<FieldMenuInit>,
}
impl ToTokens for MenuInit {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.all.to_tokens(tokens);
let fields = &self.fields;
tokens.extend(quote! {#(
.with_field(#fields)
)*})
}
}
impl MenuInit {
pub fn new(struct_attr: Option<Meta>, fields: Vec<FieldMenuInit>) -> Self {
Self {
all: struct_attr.map(AllMenuInit::from),
fields,
}
}
}