use syn::{Ident, LitBool, LitInt, LitStr, Token, parenthesized, parse::{Parse, ParseStream}};
use crate::parsing::attribute::models::{TasksConfig, TusksAttr};
impl Parse for TusksAttr {
fn parse(input: ParseStream) -> syn::Result<Self> {
let mut attr = TusksAttr::default();
while !input.is_empty() {
let ident: Ident = input.parse()?;
match ident.to_string().as_str() {
"debug" => attr.debug = parse_bool_flag(input)?,
"root" => attr.root = parse_bool_flag(input)?,
"derive_debug_for_parameters" => {
attr.derive_debug_for_parameters = parse_bool_flag(input)?
},
"tasks" => {
attr.tasks = Some(parse_optional_nested_config::<TasksConfig>(input)?);
},
other => return Err(unknown_attribute_error(&ident, other)),
}
parse_trailing_comma(input)?;
}
Ok(attr)
}
}
fn parse_optional_nested_config<T>(input: ParseStream) -> syn::Result<T>
where
T: Parse + Default,
{
if input.peek(syn::token::Paren) {
parse_nested_config(input)
} else {
Ok(T::default())
}
}
impl Parse for TasksConfig {
fn parse(input: ParseStream) -> syn::Result<Self> {
let mut config = TasksConfig::default();
while !input.is_empty() {
let ident: Ident = input.parse()?;
match ident.to_string().as_str() {
"max_groupsize" => config.max_groupsize = parse_required_value(input, parse_usize)?,
"max_depth" => config.max_depth = parse_required_value(input, parse_usize)?,
"separator" => config.separator = parse_required_value(input, parse_string)?,
"use_colors" => config.use_colors = parse_bool_flag(input)?,
other => return Err(unknown_parameter_error(&ident, other)),
}
parse_trailing_comma(input)?;
}
Ok(config)
}
}
fn parse_bool_flag(input: ParseStream) -> syn::Result<bool> {
if input.peek(Token![=]) {
input.parse::<Token![=]>()?;
let value: LitBool = input.parse()?;
Ok(value.value)
} else {
Ok(true)
}
}
fn parse_required_value<T, F>(input: ParseStream, parser: F) -> syn::Result<T>
where
F: FnOnce(ParseStream) -> syn::Result<T>,
{
input.parse::<Token![=]>()?;
parser(input)
}
fn parse_nested_config<T: Parse>(input: ParseStream) -> syn::Result<T> {
let content;
parenthesized!(content in input);
content.parse::<T>()
}
fn parse_trailing_comma(input: ParseStream) -> syn::Result<()> {
if !input.is_empty() {
input.parse::<Token![,]>()?;
}
Ok(())
}
fn parse_usize(input: ParseStream) -> syn::Result<usize> {
let value: LitInt = input.parse()?;
value.base10_parse()
}
fn parse_string(input: ParseStream) -> syn::Result<String> {
let value: LitStr = input.parse()?;
Ok(value.value())
}
fn unknown_attribute_error(ident: &Ident, name: &str) -> syn::Error {
syn::Error::new(
ident.span(),
format!("unknown tusks attribute: {}", name)
)
}
fn unknown_parameter_error(ident: &Ident, name: &str) -> syn::Error {
syn::Error::new(
ident.span(),
format!("unknown tasks parameter: {}", name)
)
}