use syn::{LitStr, Type, meta::ParseNestedMeta};
#[derive(Default)]
pub(super) struct Attr {
pub(super) name: Option<String>,
pub(super) out: Option<Type>,
pub(super) state: Option<Type>,
}
impl Attr {
pub(super) fn parse(&mut self, meta: &ParseNestedMeta) -> syn::Result<()> {
if meta.path.is_ident("name") {
let lit: LitStr = meta.value()?.parse()?;
self.name = Some(lit.value());
return Ok(());
}
if meta.path.is_ident("output") {
let ty: syn::Type = meta.value()?.parse()?;
self.out = Some(ty);
return Ok(());
}
if meta.path.is_ident("state") {
let ty: syn::Type = meta.value()?.parse()?;
self.state = Some(ty);
return Ok(());
}
Err(meta.error("unknown key in `node(...)`, expected one of: name or output"))
}
}
#[cfg(test)]
mod tests {
use super::Attr;
use quote::ToTokens;
use syn::{meta::ParseNestedMeta, parse::Parser, parse_quote};
fn parse_args(args: proc_macro2::TokenStream) -> Attr {
let mut attr = Attr::default();
let parser = syn::meta::parser(|meta: ParseNestedMeta| attr.parse(&meta));
parser.parse2(args).expect("failed to parse node args");
attr
}
#[test]
fn test_parse_results_name_output() {
let args = parse_quote! { name = "foo", output = Foo, state = State };
let args = parse_args(args);
assert_eq!(args.out.into_token_stream().to_string(), "Foo");
assert_eq!(args.name.as_deref(), Some("foo"));
assert_eq!(args.state.into_token_stream().to_string(), "State");
}
}