extern crate alloc;
use alloc::{vec, vec::Vec};
use quote::quote;
use syn::{
Expr, ExprLit, Lit, MetaNameValue, Token, Type,
parse::{Parse, ParseStream},
punctuated::Punctuated,
spanned::Spanned,
};
use crate::utils::try_convert_type_expr_into_type;
pub struct TopLevelAttribute {
pub allow_runtime_configurable: bool,
pub use_partial_matching: bool,
pub value_types: Vec<Type>,
}
impl TopLevelAttribute {
fn set_allow_runtime_configurable(&mut self, expr: &Expr) -> syn::Result<()> {
self.allow_runtime_configurable = match expr {
Expr::Lit(ExprLit {
lit: Lit::Bool(val),
..
}) => val.value(),
_ => return Err(syn::Error::new(expr.span(), "Invalid expression")),
};
Ok(())
}
fn set_use_partial_matching(&mut self, expr: &Expr) -> syn::Result<()> {
self.use_partial_matching = match expr {
Expr::Lit(ExprLit {
lit: Lit::Bool(val),
..
}) => val.value(),
_ => return Err(syn::Error::new(expr.span(), "Invalid expression")),
};
Ok(())
}
fn set_value_types(&mut self, expr: &Expr) -> syn::Result<()> {
self.value_types = match expr {
Expr::Array(arr) => {
let mut types: Vec<Type> = Vec::with_capacity(arr.elems.len());
for expr in &arr.elems {
types.push(try_convert_type_expr_into_type(expr)?);
}
types
}
_ => vec![try_convert_type_expr_into_type(expr)?],
};
Ok(())
}
}
impl Parse for TopLevelAttribute {
fn parse(input: ParseStream) -> syn::Result<Self> {
let mut enum_attr = Self::default();
let name_values = Punctuated::<MetaNameValue, Token![,]>::parse_terminated(input)?;
for MetaNameValue {
ref path,
ref value,
..
} in name_values
{
if path.is_ident("allow_runtime_configurable") {
enum_attr.set_allow_runtime_configurable(value)?;
} else if path.is_ident("value_type") || path.is_ident("value_types") {
enum_attr.set_value_types(value)?;
} else if path.is_ident("use_partial") {
enum_attr.set_use_partial_matching(value)?;
} else {
return Err(syn::Error::new(
path.span(),
format_args!(
"Invalid attribute provided: '{}'",
path.get_ident().unwrap()
),
));
}
}
Ok(enum_attr)
}
}
impl Default for TopLevelAttribute {
fn default() -> Self {
Self {
allow_runtime_configurable: false,
use_partial_matching: false,
value_types: vec![syn::parse2(quote! {i32}).unwrap()],
}
}
}