Skip to content

Allow the user to specify custom discriminant values #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions enum-kinds/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,26 @@ enum AdditionalDerives {
}
```

# Custom Discriminant Values

By default, derived kind enums do not specify values for the variants. To
specify values, use the `enum_kind_value` attribute: `#[enum_kind_value(10)]`.
For example,

``` rust,ignore
#[macro_use]
extern crate enum_kinds;

#[derive(EnumKind)]
#[enum_kind(WithValuesKind)]
enum WithValues {
#[enum_kind_value(10)]
Ten(String, u32),
#[enum_kind_value(20)]
Twenty(String)
}
```

# no_std support

`enum-kinds` can be used without the standard library by enabling `no-stdlib`
Expand Down
25 changes: 16 additions & 9 deletions enum-kinds/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ use quote::quote;
use std::collections::HashSet;
use syn::punctuated::Punctuated;
use syn::{
Data, DataEnum, DeriveInput, Fields, GenericParam, Lifetime, LifetimeDef, Meta, MetaList,
MetaNameValue, NestedMeta, Path,
Attribute, Data, DataEnum, DeriveInput, Fields, GenericParam, Lifetime, LifetimeDef, Meta,
MetaList, MetaNameValue, NestedMeta, Path,
};

#[proc_macro_derive(EnumKind, attributes(enum_kind))]
#[proc_macro_derive(EnumKind, attributes(enum_kind, enum_kind_value))]
pub fn enum_kind(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = syn::parse(input).expect("#[derive(EnumKind)] failed to parse input");
let (name, traits) = get_enum_specification(&ast);
Expand All @@ -29,10 +29,10 @@ pub fn enum_kind(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
}

fn find_attribute(
definition: &DeriveInput,
attrs: &[Attribute],
name: &str,
) -> Option<Punctuated<NestedMeta, syn::token::Comma>> {
for attr in definition.attrs.iter() {
for attr in attrs.iter() {
match attr.parse_meta() {
Ok(Meta::List(MetaList {
ref path,
Expand All @@ -46,7 +46,7 @@ fn find_attribute(
}

fn get_enum_specification(definition: &DeriveInput) -> (Path, Vec<NestedMeta>) {
let params = find_attribute(definition, "enum_kind")
let params = find_attribute(&definition.attrs, "enum_kind")
.expect("#[derive(EnumKind)] requires an associated enum_kind attribute to be specified");
let mut iter = params.iter();
if let Some(&NestedMeta::Meta(Meta::Path(ref path))) = iter.next() {
Expand All @@ -71,12 +71,19 @@ fn create_kind_enum(
kind_ident: &Path,
traits: Vec<NestedMeta>,
) -> TokenStream {
let variant_idents = match &definition.data {
&Data::Enum(DataEnum { ref variants, .. }) => variants.iter().map(|ref v| v.ident.clone()),
let variants = match &definition.data {
&Data::Enum(DataEnum { ref variants, .. }) => variants,
_ => {
panic!("#[derive(EnumKind)] is only allowed for enums");
}
};
let variant_defs = variants.iter().map(|ref v| {
let ident = v.ident.clone();
match find_attribute(&v.attrs, "enum_kind_value") {
Some(params) => quote! {#ident = #params},
None => quote! {#ident},
}
});
let visibility = &definition.vis;
let docs_attr = if !has_docs(traits.as_ref()) {
quote! {#[allow(missing_docs)]}
Expand All @@ -89,7 +96,7 @@ fn create_kind_enum(
#docs_attr
#( #[#traits] )*
#visibility enum #kind_ident {
#(#variant_idents),*
#(#variant_defs),*
}
};
TokenStream::from(code)
Expand Down
18 changes: 18 additions & 0 deletions enum-kinds/tests/kinds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,17 @@ enum WithExtraTraitsMultiple {
Second(String),
}

#[derive(EnumKind)]
#[enum_kind(WithValuesKind)]
#[allow(dead_code)]
enum WithValues {
#[enum_kind_value(10)]
Ten,
#[enum_kind_value(20)]
Twenty,
TwentyOne,
}

mod forbids_missing_docs {
#![forbid(missing_docs)]

Expand Down Expand Up @@ -133,3 +144,10 @@ fn test_with_extra_traits_multiple() {
let kind: WithExtraTraitsMultipleKind = first.into();
serde_json::to_string(&kind).unwrap();
}

#[test]
fn test_with_values() {
let twentyone = WithValues::TwentyOne;
let kind: WithValuesKind = twentyone.into();
assert_eq!(kind as usize, 21);
}