Skip to content

Commit

Permalink
Pass through all other attributes to discriminant enum.
Browse files Browse the repository at this point in the history
  • Loading branch information
azriel91 committed Sep 20, 2018
1 parent d71e593 commit 236f41d
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 13 deletions.
13 changes: 12 additions & 1 deletion strum_macros/src/enum_discriminants.rs
@@ -1,7 +1,9 @@
use proc_macro2::{Span, TokenStream};
use syn;

use helpers::{extract_list_metas, extract_meta, get_meta_ident, get_meta_list, unique_meta_list};
use helpers::{
extract_list_metas, extract_meta, filter_metas, get_meta_ident, get_meta_list, unique_meta_list,
};

pub fn enum_discriminants_inner(ast: &syn::DeriveInput) -> TokenStream {
let name = &ast.ident;
Expand Down Expand Up @@ -37,6 +39,14 @@ pub fn enum_discriminants_inner(ast: &syn::DeriveInput) -> TokenStream {
.and_then(|metas| metas.filter_map(get_meta_ident).next())
.unwrap_or(&default_name);

// Pass through all other attributes
let pass_though_attributes =
filter_metas(discriminant_attrs.iter().map(|&m| m), |meta| match meta {
syn::Meta::List(ref metalist) => metalist.ident != "derive" && metalist.ident != "name",
_ => true,
}).map(|meta| quote! { #[ #meta ] })
.collect::<Vec<_>>();

// Add the variants without fields, but exclude the `strum` meta item
let mut discriminants = Vec::new();
for variant in variants {
Expand All @@ -56,6 +66,7 @@ pub fn enum_discriminants_inner(ast: &syn::DeriveInput) -> TokenStream {
quote!{
/// Auto-generated discriminant enum variants
#derives
#(#pass_though_attributes)*
#vis enum #discriminants_name {
#(#discriminants),*
}
Expand Down
41 changes: 29 additions & 12 deletions strum_macros/src/helpers.rs
Expand Up @@ -10,6 +10,34 @@ pub fn extract_meta(attrs: &[Attribute]) -> Vec<Meta> {
.collect()
}

pub fn filter_metas<'meta, MetaIt, F>(metas: MetaIt, filter: F) -> impl Iterator<Item = &'meta Meta>
where
MetaIt: Iterator<Item = &'meta Meta>,
F: Fn(&Meta) -> bool,
{
metas.filter_map(move |meta| if filter(meta) { Some(meta) } else { None })
}

pub fn filter_meta_lists<'meta, MetaIt, F>(
metas: MetaIt,
filter: F,
) -> impl Iterator<Item = &'meta MetaList>
where
MetaIt: Iterator<Item = &'meta Meta>,
F: Fn(&MetaList) -> bool,
{
metas.filter_map(move |meta| match meta {
Meta::List(ref metalist) => {
if filter(metalist) {
Some(metalist)
} else {
None
}
}
_ => None,
})
}

/// Returns the `MetaList`s with the given attr name.
///
/// For example, `get_meta_list(type_meta.iter(), "strum_discriminant")` for the following snippet
Expand All @@ -29,18 +57,7 @@ pub fn get_meta_list<'meta, MetaIt>(
where
MetaIt: Iterator<Item = &'meta Meta>,
{
metas
// Get all the attributes with our tag on them.
.filter_map(move |meta| match meta {
Meta::List(ref metalist) => {
if metalist.ident == attr {
Some(metalist)
} else {
None
}
}
_ => None,
})
filter_meta_lists(metas, move |metalist| metalist.ident == attr)
}

pub fn unique_meta_list<'meta, MetaIt>(metas: MetaIt, attr: &'meta str) -> Option<&'meta MetaList>
Expand Down
27 changes: 27 additions & 0 deletions strum_tests/tests/enum_discriminants.rs
Expand Up @@ -118,3 +118,30 @@ fn split_attributes_test() {
assert_eq!(expected, discriminants);
assert_eq!("Variant0", format!("{}", SplitAttributesBoo::Variant0));
}

#[allow(dead_code)]
#[derive(Debug, Eq, PartialEq, EnumDiscriminants)]
#[strum_discriminants(
name(PassThroughBoo),
derive(Display, EnumIter, EnumString),
strum(serialize_all = "snake_case"),
)]
enum PassThrough {
DarkBlack(bool),
BrightWhite(i32),
}

#[test]
fn arbitrary_attributes_pass_through() {
use std::str::FromStr;

let discriminants = PassThroughBoo::iter().collect::<Vec<_>>();
let expected = vec![PassThroughBoo::DarkBlack, PassThroughBoo::BrightWhite];

assert_eq!(expected, discriminants);
assert_eq!("dark_black", PassThroughBoo::DarkBlack.to_string());
assert_eq!(
PassThroughBoo::DarkBlack,
PassThroughBoo::from_str("dark_black").unwrap()
);
}

0 comments on commit 236f41d

Please sign in to comment.