├── .gitignore ├── .travis.yml ├── Cargo.toml ├── README.md ├── bitbucket-pipelines.yml ├── enum-kinds-macros ├── Cargo.toml ├── README.md ├── src │ └── lib.rs └── tests │ └── kinds.rs ├── enum-kinds-traits ├── Cargo.toml └── src │ └── lib.rs └── enum-kinds ├── Cargo.toml ├── README.md ├── src └── lib.rs └── tests └── kinds.rs /.gitignore: -------------------------------------------------------------------------------- 1 | **/target/ 2 | **/*.rs.bk 3 | **/Cargo.lock 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - stable 4 | - beta 5 | - nightly 6 | script: 7 | - cargo test --verbose --all 8 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "enum-kinds-macros", 4 | "enum-kinds-traits", 5 | "enum-kinds" 6 | ] 7 | 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | enum-kinds/README.md -------------------------------------------------------------------------------- /bitbucket-pipelines.yml: -------------------------------------------------------------------------------- 1 | image: rust:latest 2 | 3 | pipelines: 4 | default: 5 | - step: 6 | script: 7 | - echo "Running Tests"; cargo test --all 8 | -------------------------------------------------------------------------------- /enum-kinds-macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "enum-kinds-macros" 3 | version = "0.2.1" 4 | authors = ["Samuel Laurén "] 5 | homepage = "https://bitbucket.org/Soft/enum-kinds" 6 | repository = "https://bitbucket.org/Soft/enum-kinds" 7 | description = "Deprecated in favor of the enum-kinds crate. Generate enums with matching variants but without any of the associated data. enum-kinds-traits crate contains trait definitions used by this crate." 8 | readme = "README.md" 9 | license = "MIT" 10 | keywords = ["macro", "enum", "derive", "proc-macro", "deriving"] 11 | 12 | [lib] 13 | proc-macro = true 14 | 15 | [dependencies] 16 | syn = "0.12.13" 17 | quote = "0.4.2" 18 | 19 | [dev-dependencies] 20 | enum-kinds-traits = { path = "../enum-kinds-traits", version = "0.1.2" } 21 | 22 | [badges] 23 | maintenance = { status = "deprecated" } -------------------------------------------------------------------------------- /enum-kinds-macros/README.md: -------------------------------------------------------------------------------- 1 | # enum-kinds-macros 2 | 3 | [![Build Status](https://api.travis-ci.org/Soft/enum-kinds.svg?branch=master)](https://travis-ci.org/Soft/enum-kinds) 4 | [![Latest Version](https://img.shields.io/crates/v/enum-kinds-macros.svg)](https://crates.io/crates/enum-kinds-macros) 5 | [![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/enum-kinds-macros) 6 | 7 | **DEPRECATED**: This crate along with `enum-kinds-traits` have been replaced 8 | with `enum-kinds` crate. Users are asked to migrate to the new crate as further 9 | development will take place there. 10 | 11 | Generate enums with matching variants, but without any of the associated data. 12 | `enum-kinds-traits` crate contains trait definitions used by this crate. 13 | 14 | In other words, `enum-kinds-macros` automatically generates `enum`s that have 15 | the same set of variants as the original `enum`, but with all the embedded data 16 | stripped away (that is, all the variants are unit variants). Additionally, 17 | `enum-kinds-macros` implements `ToKind` trait for the original `enum` allowing 18 | one to get the associated unit variant. 19 | 20 | The crates are compatible with stable Rust releases. 21 | 22 | # Example 23 | 24 | ```rust 25 | #[macro_use] 26 | extern crate enum_kinds_macros; 27 | extern crate enum_kinds_traits; 28 | 29 | use enum_kinds_traits::ToKind; 30 | 31 | #[derive(EnumKind)] 32 | #[enum_kind_name(SomeEnumKind)] 33 | enum SomeEnum { 34 | First(String, u32), 35 | Second(char), 36 | Third 37 | } 38 | 39 | #[test] 40 | fn test_enum_kind() { 41 | let first = SomeEnum::First("Example".to_owned(), 32); 42 | assert_eq!(first.kind(), SomeEnumKind::First); 43 | } 44 | ``` 45 | 46 | The `#[derive(EnumKind)]` attribute automatically creates another `enum` named 47 | `SomeEnumKind` that contains matching unit variant for each of the variants in 48 | `SomeEnum`. Additionally, `SomeEnum` implements `ToKind` trait that provides the 49 | `kind` method for constructing matching values from `SomeEnumKind`. 50 | 51 | # Issues 52 | 53 | While the crates are fairly simple, issues are still possible. If you encounter 54 | any problems using these crates, please report them 55 | at [the issue tracker](https://bitbucket.org/Soft/enum-kinds/issues). 56 | 57 | # License 58 | 59 | The crates are available under the terms of [MIT license](https://opensource.org/licenses/MIT). 60 | -------------------------------------------------------------------------------- /enum-kinds-macros/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Generate enums with matching variants, but without any of the associated data. 2 | //! `enum-kinds-traits` crate contains trait definitions used by this crate. 3 | //! 4 | //! In other words, `enum-kinds-macros` automatically generates `enum`s that have 5 | //! the same set of variants as the original `enum`, but with all the embedded data 6 | //! stripped away (that is, all the variants are unit variants). Additionally, 7 | //! `enum-kinds-macros` implements `ToKind` trait for the original `enum` allowing 8 | //! one to get the associated unit variant. 9 | //! 10 | //! The crates are compatible with stable Rust releases. 11 | //! 12 | //! # Example 13 | //! 14 | //! ```rust,ignore 15 | //! #[macro_use] 16 | //! extern crate enum_kinds_macros; 17 | //! extern crate enum_kinds_traits; 18 | //! 19 | //! use enum_kinds_traits::ToKind; 20 | //! 21 | //! #[derive(EnumKind)] 22 | //! #[enum_kind_name(SomeEnumKind)] 23 | //! enum SomeEnum { 24 | //! First(String, u32), 25 | //! Second(char), 26 | //! Third 27 | //! } 28 | //! 29 | //! #[test] 30 | //! fn test_enum_kind() { 31 | //! let first = SomeEnum::First("Example".to_owned(), 32); 32 | //! assert_eq!(first.kind(), SomeEnumKind::First); 33 | //! } 34 | //! ``` 35 | //! 36 | //! The `#[derive(EnumKind)]` attribute automatically creates another `enum` named 37 | //! `SomeEnumKind` that contains matching unit variant for each of the variants in 38 | //! `SomeEnum`. Additionally, `SomeEnum` implements `ToKind` trait that provides the 39 | //! `kind` method for constructing matching values from `SomeEnumKind`. 40 | //! 41 | 42 | #![no_std] 43 | 44 | #[macro_use] 45 | extern crate quote; 46 | extern crate proc_macro; 47 | extern crate syn; 48 | 49 | use proc_macro::TokenStream; 50 | use quote::Tokens; 51 | use syn::{DeriveInput, Meta, NestedMeta, Ident, Data, MetaList, DataEnum, Fields}; 52 | use syn::punctuated::Pair; 53 | 54 | #[proc_macro_derive(EnumKind, attributes(enum_kind_name))] 55 | pub fn enum_kind(input: TokenStream) -> TokenStream { 56 | let ast = syn::parse(input).expect("#[derive(EnumKind)] failed to parse input"); 57 | let name = get_enum_name(&ast) 58 | .expect("#[derive(EnumKind)] requires an associated #[enum_kind_name(NAME)] to be specified"); 59 | let enum_ = create_kind_enum(&ast, &name); 60 | let impl_ = create_impl(&ast, &name); 61 | let code = quote! { 62 | #enum_ 63 | #impl_ 64 | }; 65 | code.into() 66 | } 67 | 68 | fn get_enum_name(definition: &DeriveInput) -> Option { 69 | for attr in definition.attrs.iter() { 70 | match attr.interpret_meta() { 71 | Some(Meta::List(MetaList { ident, ref nested, .. })) if ident == "enum_kind_name" => { 72 | if let Some(Pair::End(&NestedMeta::Meta(Meta::Word(ident)))) = nested.pairs().next() { 73 | return Some(ident.clone()); 74 | } else { 75 | panic!("#[enum_kind_name(NAME)] requires an identifier NAME to be specified"); 76 | } 77 | }, 78 | _ => continue 79 | } 80 | } 81 | return None; 82 | } 83 | 84 | fn create_kind_enum(definition: &DeriveInput, kind_ident: &Ident) -> Tokens { 85 | let variant_idents = match &definition.data { 86 | &Data::Enum(DataEnum { ref variants, .. }) => { 87 | variants.iter().map(|ref v| v.ident.clone()) 88 | } 89 | _ => { 90 | panic!("#[derive(EnumKind)] is only allowed for enums"); 91 | } 92 | }; 93 | let visibility = &definition.vis; 94 | quote! { 95 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 96 | #[allow(dead_code)] 97 | #[allow(non_snake_case)] 98 | #visibility enum #kind_ident { 99 | #(#variant_idents),* 100 | } 101 | } 102 | } 103 | 104 | fn create_impl(definition: &DeriveInput, kind_ident: &Ident) -> Tokens { 105 | let (impl_generics, ty_generics, where_clause) = definition.generics.split_for_impl(); 106 | let ident = &definition.ident; 107 | 108 | let arms = match &definition.data { 109 | &Data::Enum(DataEnum { ref variants, .. }) => { 110 | variants.iter().map(|ref v| { 111 | let variant = &v.ident; 112 | match v.fields { 113 | Fields::Unit => quote! { 114 | &#ident::#variant => #kind_ident::#variant, 115 | }, 116 | Fields::Unnamed(_) => quote! { 117 | &#ident::#variant(..) => #kind_ident::#variant, 118 | }, 119 | Fields::Named(_) => quote! { 120 | &#ident::#variant{..} => #kind_ident::#variant, 121 | } 122 | } 123 | }) 124 | } 125 | _ => { 126 | panic!("#[derive(EnumKind)] is only defined for enums"); 127 | } 128 | }; 129 | 130 | quote! { 131 | #[automatically_derived] 132 | #[allow(unused_attributes)] 133 | impl #impl_generics ::enum_kinds_traits::ToKind 134 | for #ident #ty_generics #where_clause { 135 | type Kind = #kind_ident; 136 | 137 | #[inline] 138 | fn kind(&self) -> Self::Kind { 139 | match self { 140 | #(#arms)* 141 | } 142 | } 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /enum-kinds-macros/tests/kinds.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate enum_kinds_macros; 3 | extern crate enum_kinds_traits; 4 | 5 | use enum_kinds_traits::ToKind; 6 | 7 | #[derive(EnumKind)] 8 | #[enum_kind_name(UnnamedEnumKind)] 9 | #[allow(dead_code)] 10 | enum UnnamedEnum { 11 | First(String, u32), 12 | Second(char), 13 | Third 14 | } 15 | 16 | #[derive(EnumKind)] 17 | #[enum_kind_name(NamedEnumKind)] 18 | #[allow(dead_code)] 19 | enum NamedEnum { 20 | Foo { 21 | foo: String, 22 | bar: u32 23 | }, 24 | Bar { 25 | zap: char 26 | } 27 | } 28 | 29 | #[test] 30 | fn test_unnamed() { 31 | let first = UnnamedEnum::First("Example".to_owned(), 32); 32 | assert_eq!(first.kind(), UnnamedEnumKind::First); 33 | } 34 | 35 | #[test] 36 | fn test_named() { 37 | let foo = NamedEnum::Foo { 38 | foo: "Example".to_owned(), 39 | bar: 32 40 | }; 41 | assert_eq!(foo.kind(), NamedEnumKind::Foo); 42 | } 43 | -------------------------------------------------------------------------------- /enum-kinds-traits/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "enum-kinds-traits" 3 | version = "0.1.2" 4 | authors = ["Samuel Laurén "] 5 | homepage = "https://bitbucket.org/Soft/enum-kinds" 6 | repository = "https://bitbucket.org/Soft/enum-kinds" 7 | description = "Deprecated in favor of the enum-kinds crate. Traits for enum-kinds-macros crate." 8 | license = "MIT" 9 | keywords = ["macro", "enum", "deriving"] 10 | 11 | [dependencies] 12 | 13 | [badges] 14 | maintenance = { status = "deprecated" } -------------------------------------------------------------------------------- /enum-kinds-traits/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | pub trait ToKind { 4 | type Kind; 5 | 6 | fn kind(&self) -> Self::Kind; 7 | } 8 | -------------------------------------------------------------------------------- /enum-kinds/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "enum-kinds" 3 | version = "0.5.1" 4 | authors = ["Samuel Laurén "] 5 | homepage = "https://github.com/Soft/enum-kinds" 6 | repository = "https://github.com/Soft/enum-kinds" 7 | description = "Generate enums with matching variants but without any of the associated data." 8 | readme = "README.md" 9 | license = "MIT" 10 | keywords = ["macro", "enum", "derive", "proc-macro", "deriving"] 11 | edition = "2018" 12 | 13 | [lib] 14 | proc-macro = true 15 | 16 | [dependencies] 17 | syn = "1.0.74" 18 | quote = "1.0.9" 19 | proc-macro2 = "1.0.28" 20 | 21 | [dev-dependencies] 22 | serde = "1.0.127" 23 | serde_derive = "1.0.127" 24 | serde_json = "1.0.66" 25 | 26 | [features] 27 | default = [] 28 | no-stdlib = [] 29 | 30 | [badges] 31 | travis-ci = { repository = "Soft/enum-kinds" } 32 | -------------------------------------------------------------------------------- /enum-kinds/README.md: -------------------------------------------------------------------------------- 1 | # enum-kinds 2 | 3 | [![Build Status](https://api.travis-ci.org/Soft/enum-kinds.svg?branch=master)](https://travis-ci.org/Soft/enum-kinds) 4 | [![Latest Version](https://img.shields.io/crates/v/enum-kinds.svg)](https://crates.io/crates/enum-kinds) 5 | [![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/enum-kinds) 6 | 7 | Custom derive for generating enums with matching variants but without any of 8 | the data. 9 | 10 | In other words, `enum-kinds` automatically generates enums that have the same 11 | set of variants as the original enum, but with all the embedded data stripped 12 | away (that is, all the variants of the newly-generated enum are unit variants). 13 | Additionally, `enum-kinds` implements `From` trait for going from the original 14 | enum to the unit variant version. 15 | 16 | The crate is compatible with stable Rust releases. This crate replaces 17 | earlier `enum_kinds_macros` and `enum_kinds_traits` crates. 18 | 19 | # Example 20 | 21 | ```rust,ignore 22 | #[macro_use] 23 | extern crate enum_kinds; 24 | 25 | #[derive(EnumKind)] 26 | #[enum_kind(SomeEnumKind)] 27 | enum SomeEnum { 28 | First(String, u32), 29 | Second(char), 30 | Third 31 | } 32 | 33 | #[test] 34 | fn test_enum_kind() { 35 | let first = SomeEnum::First("Example".to_owned(), 32); 36 | assert_eq!(SomeEnumKind::from(&first), SomeEnumKind::First); 37 | } 38 | ``` 39 | 40 | The `#[derive(EnumKind)]` attribute automatically creates another `enum` named 41 | `SomeEnumKind` that contains matching unit variant for each of the variants in 42 | `SomeEnum`. 43 | 44 | # Additional Attributes for Generated Enums 45 | 46 | By default, derived kind enums implement `Debug`, `Clone`, `Copy`, `PartialEq` 47 | and `Eq` traits. Additional attributes can be attached to the generated `enum` 48 | by including them to the `enum_kind` attribute: `#[enum_kind(NAME, 49 | derive(SomeTrait), derive(AnotherTrait))]`. For example, to implement 50 | [Serde's](https://serde.rs) Serialize and Deserialize traits: 51 | 52 | ``` rust,ignore 53 | #[macro_use] 54 | extern crate enum_kinds; 55 | 56 | #[macro_use] 57 | extern crate serde_derive; 58 | extern crate serde; 59 | 60 | #[derive(EnumKind)] 61 | #[enum_kind(AdditionalDerivesKind, derive(Serialize, Deserialize))] 62 | enum AdditionalDerives { 63 | Variant(String, u32), 64 | Another(String) 65 | } 66 | ``` 67 | 68 | # no_std support 69 | 70 | `enum-kinds` can be used without the standard library by enabling `no-stdlib` 71 | feature. 72 | 73 | # Issues 74 | 75 | If you encounter any problems using the crate, please report them at [the issue 76 | tracker](https://github.com/Soft/enum-kinds/issues). 77 | 78 | # License 79 | 80 | The crate is available under the terms of [MIT license](https://opensource.org/licenses/MIT). 81 | -------------------------------------------------------------------------------- /enum-kinds/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc = include_str!("../README.md")] 2 | 3 | extern crate proc_macro; 4 | extern crate proc_macro2; 5 | extern crate quote; 6 | #[macro_use] 7 | extern crate syn; 8 | 9 | use proc_macro2::TokenStream; 10 | use quote::quote; 11 | use std::collections::HashSet; 12 | use syn::punctuated::Punctuated; 13 | use syn::{ 14 | Data, DataEnum, DeriveInput, Fields, GenericParam, Lifetime, LifetimeDef, Meta, MetaList, 15 | MetaNameValue, NestedMeta, Path, 16 | }; 17 | 18 | #[proc_macro_derive(EnumKind, attributes(enum_kind))] 19 | pub fn enum_kind(input: proc_macro::TokenStream) -> proc_macro::TokenStream { 20 | let ast = syn::parse(input).expect("#[derive(EnumKind)] failed to parse input"); 21 | let (name, traits) = get_enum_specification(&ast); 22 | let enum_ = create_kind_enum(&ast, &name, traits); 23 | let impl_ = create_impl(&ast, &name); 24 | let code = quote! { 25 | #enum_ 26 | #impl_ 27 | }; 28 | proc_macro::TokenStream::from(code) 29 | } 30 | 31 | fn find_attribute( 32 | definition: &DeriveInput, 33 | name: &str, 34 | ) -> Option> { 35 | for attr in definition.attrs.iter() { 36 | match attr.parse_meta() { 37 | Ok(Meta::List(MetaList { 38 | ref path, 39 | ref nested, 40 | .. 41 | })) if path.is_ident(name) => return Some(nested.clone()), 42 | _ => continue, 43 | } 44 | } 45 | None 46 | } 47 | 48 | fn get_enum_specification(definition: &DeriveInput) -> (Path, Vec) { 49 | let params = find_attribute(definition, "enum_kind") 50 | .expect("#[derive(EnumKind)] requires an associated enum_kind attribute to be specified"); 51 | let mut iter = params.iter(); 52 | if let Some(&NestedMeta::Meta(Meta::Path(ref path))) = iter.next() { 53 | return (path.to_owned(), iter.cloned().collect()); 54 | } else { 55 | panic!("#[enum_kind(NAME)] attribute requires NAME to be specified"); 56 | } 57 | } 58 | 59 | fn has_docs(traits: &[NestedMeta]) -> bool { 60 | traits.iter().any(|attr| { 61 | if let NestedMeta::Meta(Meta::NameValue(MetaNameValue { path, .. })) = attr { 62 | path.is_ident("doc") 63 | } else { 64 | false 65 | } 66 | }) 67 | } 68 | 69 | fn create_kind_enum( 70 | definition: &DeriveInput, 71 | kind_ident: &Path, 72 | traits: Vec, 73 | ) -> TokenStream { 74 | let variant_idents = match &definition.data { 75 | &Data::Enum(DataEnum { ref variants, .. }) => variants.iter().map(|ref v| v.ident.clone()), 76 | _ => { 77 | panic!("#[derive(EnumKind)] is only allowed for enums"); 78 | } 79 | }; 80 | let visibility = &definition.vis; 81 | let docs_attr = if !has_docs(traits.as_ref()) { 82 | quote! {#[allow(missing_docs)]} 83 | } else { 84 | quote! {} 85 | }; 86 | let code = quote! { 87 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 88 | #[allow(dead_code)] 89 | #docs_attr 90 | #( #[#traits] )* 91 | #visibility enum #kind_ident { 92 | #(#variant_idents),* 93 | } 94 | }; 95 | TokenStream::from(code) 96 | } 97 | 98 | fn is_uninhabited_enum(definition: &DeriveInput) -> bool { 99 | if let Data::Enum(ref data) = definition.data { 100 | return data.variants.len() == 0; 101 | } 102 | return false; 103 | } 104 | 105 | fn create_impl(definition: &DeriveInput, kind_ident: &Path) -> TokenStream { 106 | let (_, ty_generics, where_clause) = definition.generics.split_for_impl(); 107 | let ident = &definition.ident; 108 | 109 | let arms = match &definition.data { 110 | &Data::Enum(DataEnum { ref variants, .. }) => variants.iter().map(|ref v| { 111 | let variant = &v.ident; 112 | match v.fields { 113 | Fields::Unit => quote! { 114 | &#ident::#variant => #kind_ident::#variant, 115 | }, 116 | Fields::Unnamed(_) => quote! { 117 | &#ident::#variant(..) => #kind_ident::#variant, 118 | }, 119 | Fields::Named(_) => quote! { 120 | &#ident::#variant{..} => #kind_ident::#variant, 121 | }, 122 | } 123 | }), 124 | _ => { 125 | panic!("#[derive(EnumKind)] is only allowed for enums"); 126 | } 127 | }; 128 | 129 | let trait_: Path = if cfg!(feature = "no-stdlib") { 130 | parse_quote!(::core::convert::From) 131 | } else { 132 | parse_quote!(::std::convert::From) 133 | }; 134 | 135 | let mut counter: u32 = 1; 136 | let used: HashSet = definition 137 | .generics 138 | .lifetimes() 139 | .map(|ld| ld.lifetime.clone()) 140 | .collect(); 141 | let a = loop { 142 | let lifetime: Lifetime = syn::parse_str(&format!("'__enum_kinds{}", counter)).unwrap(); 143 | if !used.contains(&lifetime) { 144 | break LifetimeDef::new(lifetime); 145 | } 146 | counter += 1; 147 | }; 148 | 149 | let mut generics = definition.generics.clone(); 150 | generics.params.insert(0, GenericParam::Lifetime(a.clone())); 151 | let (impl_generics, _, _) = generics.split_for_impl(); 152 | 153 | let impl_ = if is_uninhabited_enum(definition) { 154 | quote! { 155 | unreachable!(); 156 | } 157 | } else { 158 | quote! { 159 | match _value { 160 | #(#arms)* 161 | } 162 | } 163 | }; 164 | 165 | let tokens = quote! { 166 | #[automatically_derived] 167 | #[allow(unused_attributes)] 168 | impl #impl_generics #trait_<&#a #ident#ty_generics> for #kind_ident #where_clause { 169 | fn from(_value: &#a #ident#ty_generics) -> Self { 170 | #impl_ 171 | } 172 | } 173 | 174 | #[automatically_derived] 175 | #[allow(unused_attributes)] 176 | impl #impl_generics #trait_<#ident#ty_generics> for #kind_ident #where_clause { 177 | fn from(value: #ident#ty_generics) -> Self { 178 | #kind_ident::from(&value) 179 | } 180 | } 181 | }; 182 | TokenStream::from(tokens) 183 | } 184 | -------------------------------------------------------------------------------- /enum-kinds/tests/kinds.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate enum_kinds; 3 | 4 | use std::fmt::Debug; 5 | 6 | #[macro_use] 7 | extern crate serde_derive; 8 | extern crate serde; 9 | extern crate serde_json; 10 | 11 | #[derive(EnumKind)] 12 | #[enum_kind(UnnamedEnumKind)] 13 | #[allow(dead_code)] 14 | enum UnnamedEnum { 15 | First(String, u32), 16 | Second(char), 17 | Third, 18 | } 19 | 20 | #[derive(EnumKind)] 21 | #[enum_kind(NamedEnumKind)] 22 | #[allow(dead_code)] 23 | enum NamedEnum { 24 | Foo { foo: String, bar: u32 }, 25 | Bar { zap: char }, 26 | } 27 | 28 | #[derive(EnumKind)] 29 | #[enum_kind(WithLifetimeKind)] 30 | #[allow(dead_code)] 31 | enum WithLifetime<'a> { 32 | First(&'a str), 33 | } 34 | 35 | #[derive(EnumKind)] 36 | #[enum_kind(WithWhereClauseKind)] 37 | #[allow(dead_code)] 38 | enum WithWhereClause<'b, T> 39 | where 40 | T: Debug, 41 | T: 'b, 42 | T: ?Sized, 43 | { 44 | First { value: &'b T }, 45 | } 46 | 47 | #[derive(EnumKind)] 48 | #[enum_kind(WithCollisionKind)] 49 | #[allow(dead_code)] 50 | enum WithCollision<'__enum_kinds1> { 51 | First(&'__enum_kinds1 str), 52 | } 53 | 54 | #[derive(EnumKind)] 55 | #[enum_kind(UninhabitedEnumKind)] 56 | #[allow(dead_code)] 57 | enum UninhabitedEnum {} 58 | 59 | #[derive(EnumKind)] 60 | #[enum_kind(WithExtraTraitsKind, derive(Serialize, Deserialize))] 61 | #[allow(dead_code)] 62 | enum WithExtraTraits { 63 | First(u32, u32), 64 | Second(String), 65 | } 66 | 67 | #[derive(EnumKind)] 68 | #[enum_kind(WithExtraTraitsMultipleKind, derive(Serialize), derive(Deserialize))] 69 | #[allow(dead_code)] 70 | enum WithExtraTraitsMultiple { 71 | First(u32, u32), 72 | Second(String), 73 | } 74 | 75 | mod forbids_missing_docs { 76 | #![forbid(missing_docs)] 77 | 78 | #[derive(EnumKind)] 79 | #[enum_kind(WithDocumentationKind, doc = "a documented kind enum")] 80 | #[allow(dead_code)] 81 | enum WithDocumentation { 82 | First(u32, u32), 83 | Second(String), 84 | } 85 | } 86 | 87 | #[test] 88 | fn test_unnamed() { 89 | let first = UnnamedEnum::First("Example".to_owned(), 32); 90 | assert_eq!(UnnamedEnumKind::from(first), UnnamedEnumKind::First); 91 | } 92 | 93 | #[test] 94 | fn test_named() { 95 | let foo = NamedEnum::Foo { 96 | foo: "Example".to_owned(), 97 | bar: 32, 98 | }; 99 | assert_eq!(NamedEnumKind::from(&foo), NamedEnumKind::Foo); 100 | } 101 | 102 | #[test] 103 | fn test_with_lifetimes() { 104 | let first = WithLifetime::First("hello"); 105 | assert_eq!(WithLifetimeKind::from(&first), WithLifetimeKind::First); 106 | } 107 | 108 | #[test] 109 | fn test_with_where_clause() { 110 | let first = WithWhereClause::First { value: "hello" }; 111 | assert_eq!( 112 | WithWhereClauseKind::from(&first), 113 | WithWhereClauseKind::First 114 | ); 115 | } 116 | 117 | #[test] 118 | fn test_with_collision() { 119 | let first = WithCollision::First("hello"); 120 | assert_eq!(WithCollisionKind::from(&first), WithCollisionKind::First); 121 | } 122 | 123 | #[test] 124 | fn test_with_extra_traits() { 125 | let first = WithExtraTraits::First(20, 30); 126 | let kind: WithExtraTraitsKind = first.into(); 127 | serde_json::to_string(&kind).unwrap(); 128 | } 129 | 130 | #[test] 131 | fn test_with_extra_traits_multiple() { 132 | let first = WithExtraTraitsMultiple::First(20, 30); 133 | let kind: WithExtraTraitsMultipleKind = first.into(); 134 | serde_json::to_string(&kind).unwrap(); 135 | } 136 | --------------------------------------------------------------------------------