use syn::ext::IdentExt;
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
use syn::{Ident, LitStr, Path, Token};
struct SetupFunc(Path);
impl Parse for SetupFunc {
fn parse(input: ParseStream) -> syn::Result<Self> {
let lookahead = input.lookahead1();
if lookahead.peek(LitStr) {
let lit: LitStr = input.parse()?;
Ok(SetupFunc(lit.parse()?))
} else if lookahead.peek(Ident::peek_any) {
Ok(SetupFunc(input.call(Path::parse_mod_style)?))
} else {
Err(lookahead.error())
}
}
}
enum Attribute {
Setup(Option<SetupFunc>),
}
impl Parse for Attribute {
fn parse(input: ParseStream) -> syn::Result<Self> {
let key: Ident = input.parse()?;
let setup = if key == "setup" {
let _: Token![=] = input.parse()?;
Some(input.parse()?)
} else if key == "no_setup" {
None
} else {
return Err(syn::Error::new_spanned(
key,
"unsupported attribute for testx",
));
};
Ok(Attribute::Setup(setup))
}
}
pub struct AttributeList {
attrs: Punctuated<Attribute, Token![,]>,
def_setup: Path,
}
impl AttributeList {
fn default_setup_func() -> syn::Result<Path> {
syn::parse_str("setup")
}
pub fn setup_func(&self) -> Option<&Path> {
for attr in self.attrs.iter() {
match attr {
Attribute::Setup(opt) => {
return opt.as_ref().map(|func| &func.0);
}
};
}
Some(&self.def_setup)
}
}
impl Parse for AttributeList {
fn parse(input: ParseStream) -> syn::Result<Self> {
let attrs = if input.is_empty() {
Punctuated::new()
} else {
input.call(Punctuated::parse_separated_nonempty)?
};
let def_setup = Self::default_setup_func()?;
Ok(AttributeList { attrs, def_setup })
}
}