use super::config::Config;
use proc_macro2::Span;
use syn::{
parse::Result,
spanned::Spanned,
};
fn unsupported_argument<T>(arg: T) -> syn::Error
where
T: Spanned,
{
format_err!(arg, "encountered unsupported #[bitfield] attribute")
}
pub struct ParamArgs {
args: syn::AttributeArgs,
}
impl syn::parse::Parse for ParamArgs {
fn parse(input: syn::parse::ParseStream) -> Result<Self> {
let punctuated =
<syn::punctuated::Punctuated<_, syn::Token![,]>>::parse_terminated(input)?;
Ok(Self {
args: punctuated.into_iter().collect::<Vec<_>>(),
})
}
}
impl IntoIterator for ParamArgs {
type Item = syn::NestedMeta;
type IntoIter = std::vec::IntoIter<syn::NestedMeta>;
fn into_iter(self) -> Self::IntoIter {
self.args.into_iter()
}
}
impl Config {
fn feed_int_param<F>(
name_value: syn::MetaNameValue,
name: &str,
on_success: F,
) -> Result<()>
where
F: FnOnce(usize, Span) -> Result<()>,
{
assert!(name_value.path.is_ident(name));
match &name_value.lit {
syn::Lit::Int(lit_int) => {
let span = lit_int.span();
let value = lit_int.base10_parse::<usize>().map_err(|err| {
format_err!(
span,
"encountered malformatted integer value for `{}` parameter: {}",
name,
err
)
})?;
on_success(value, name_value.span())?;
}
invalid => {
return Err(format_err!(
invalid,
"encountered invalid value argument for #[bitfield] `{}` parameter",
name
))
}
}
Ok(())
}
fn feed_bytes_param(&mut self, name_value: syn::MetaNameValue) -> Result<()> {
Self::feed_int_param(name_value, "bytes", |value, span| self.bytes(value, span))
}
fn feed_bits_param(&mut self, name_value: syn::MetaNameValue) -> Result<()> {
Self::feed_int_param(name_value, "bits", |value, span| self.bits(value, span))
}
fn feed_filled_param(&mut self, name_value: syn::MetaNameValue) -> Result<()> {
assert!(name_value.path.is_ident("filled"));
match &name_value.lit {
syn::Lit::Bool(lit_bool) => {
self.filled(lit_bool.value, name_value.span())?;
}
invalid => {
return Err(format_err!(
invalid,
"encountered invalid value argument for #[bitfield] `filled` parameter",
))
}
}
Ok(())
}
pub fn feed_params<'a, P>(&mut self, params: P) -> Result<()>
where
P: IntoIterator<Item = syn::NestedMeta> + 'a,
{
for nested_meta in params {
match nested_meta {
syn::NestedMeta::Meta(meta) => {
match meta {
syn::Meta::NameValue(name_value) => {
if name_value.path.is_ident("bytes") {
self.feed_bytes_param(name_value)?;
} else if name_value.path.is_ident("bits") {
self.feed_bits_param(name_value)?;
} else if name_value.path.is_ident("filled") {
self.feed_filled_param(name_value)?;
} else {
return Err(unsupported_argument(name_value))
}
}
unsupported => return Err(unsupported_argument(unsupported)),
}
}
unsupported => return Err(unsupported_argument(unsupported)),
}
}
Ok(())
}
}