Skip to content

Commit

Permalink
derive: Allow multiple extensions attributes for ExtensionDispatch
Browse files Browse the repository at this point in the history
This makes it easier to select the supported extensions using
conditional compilation (cfg_attr).
  • Loading branch information
robin-nitrokey committed Mar 25, 2024
1 parent 594c235 commit 9ca8866
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 19 deletions.
31 changes: 15 additions & 16 deletions derive/src/extension_dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,14 @@ impl ExtensionAttrs {
fn new(input: &DeriveInput) -> Result<Self> {
let mut extensions: HashMap<Ident, Path> = Default::default();

let attr = util::require_attr(input, &input.attrs, "extensions")?;
attr.parse_nested_meta(|meta| {
let ident = meta.path.require_ident()?;
let s: LitStr = meta.value()?.parse()?;
extensions.insert(ident.to_owned(), s.parse()?);
Ok(())
})?;
for attr in util::get_attrs(&input.attrs, "extensions") {
attr.parse_nested_meta(|meta| {
let ident = meta.path.require_ident()?;
let s: LitStr = meta.value()?.parse()?;
extensions.insert(ident.to_owned(), s.parse()?);
Ok(())
})?;
}

Ok(Self { extensions })
}
Expand All @@ -173,21 +174,19 @@ struct Backend {
}

impl Backend {
fn new(i: usize, field: &Field, extensions: &HashMap<Ident, Path>) -> Result<Self> {
fn new(i: usize, field: &Field, extension_types: &HashMap<Ident, Path>) -> Result<Self> {
let ident = field.ident.clone().ok_or_else(|| {
Error::new_spanned(
field,
"ExtensionDispatch can only be derived for a struct with named fields",
)
})?;
let extensions = if let Some(attr) = util::get_attr(&field.attrs, "extensions")? {
attr.parse_args_with(Punctuated::<LitStr, Token![,]>::parse_terminated)?
.into_iter()
.map(|s| Extension::new(&s, extensions))
.collect::<Result<_>>()?
} else {
Default::default()
};
let mut extensions = Vec::new();
for attr in util::get_attrs(&field.attrs, "extensions") {
for s in attr.parse_args_with(Punctuated::<LitStr, Token![,]>::parse_terminated)? {
extensions.push(Extension::new(&s, extension_types)?);
}
}
Ok(Self {
id: util::to_camelcase(&ident),
field: ident,
Expand Down
10 changes: 7 additions & 3 deletions derive/src/util.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
use quote::ToTokens;
use syn::{Attribute, Error, Ident, Result};

pub fn get_attr<'a>(attrs: &'a [Attribute], name: &str) -> Result<Option<&'a Attribute>> {
let mut attrs = attrs.iter().filter(|attr| attr.path().is_ident(name));
pub fn get_attrs<'a>(attrs: &'a [Attribute], name: &'a str) -> impl Iterator<Item = &'a Attribute> {
attrs.iter().filter(|attr| attr.path().is_ident(name))
}

pub fn get_attr<'a>(attrs: &'a [Attribute], name: &'a str) -> Result<Option<&'a Attribute>> {
let mut attrs = get_attrs(attrs, name);
let first = attrs.next();
if let Some(next) = attrs.next() {
Err(Error::new_spanned(
Expand All @@ -17,7 +21,7 @@ pub fn get_attr<'a>(attrs: &'a [Attribute], name: &str) -> Result<Option<&'a Att
pub fn require_attr<'a>(
span: &dyn ToTokens,
attrs: &'a [Attribute],
name: &str,
name: &'a str,
) -> Result<&'a Attribute> {
get_attr(attrs, name)?
.ok_or_else(|| Error::new_spanned(span, format!("missing #[{}(...)] attribute", name)))
Expand Down

0 comments on commit 9ca8866

Please sign in to comment.