├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── src └── lib.rs └── tests ├── field_name.rs ├── field_type.rs └── field_types.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | 12 | /.idea 13 | *.iml -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "field_types" 3 | version = "1.1.0" 4 | authors = ["Alexander Mescheryakov "] 5 | license = "MIT" 6 | 7 | description = "Some derive macros for deriving enums, corresponding to the fields of structs." 8 | readme = "README.md" 9 | documentation = "https://docs.rs/field_types" 10 | 11 | repository = "https://github.com/XX/field_types" 12 | keywords = ["struct", "field", "type", "name", "enum"] 13 | categories = ["rust-patterns"] 14 | 15 | [dependencies] 16 | quote = "1.0" 17 | syn = "1.0" 18 | heck = "0.3" 19 | 20 | [dev-dependencies] 21 | variant_count = "1.0" 22 | 23 | [lib] 24 | proc-macro = true 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Alexander Mescheryakov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Field Types 2 | 3 | [![Crates.io](https://img.shields.io/crates/v/field_types.svg)](https://crates.io/crates/field_types) 4 | [![Docs](https://docs.rs/field_types/badge.svg)](https://docs.rs/field_types) 5 | 6 | This crate provides `FieldName` and `FieldType` derive macros for deriving `StructFieldName` and `StructFieldType` enums for any struct `Struct` with some fields. 7 | 8 | The `..FieldName` enum contains unit types with names corresponding to the names of the structure fields. 9 | Additionally, you can get static string representation of a field name with `name` method and get `..FieldName` variant by string with `by_name` method. 10 | 11 | The `FieldName` usage example: 12 | 13 | ```rust 14 | use field_types::FieldName; 15 | 16 | #[derive(FieldName)] 17 | struct Test { 18 | first: i32, 19 | second_field: Option, 20 | #[field_name(skip)] 21 | third: bool, 22 | } 23 | 24 | assert_eq!(TestFieldName::First.name(), "first"); 25 | assert_eq!(TestFieldName::SecondField.name(), "second_field"); 26 | 27 | assert_eq!(Some(TestFieldName::First), TestFieldName::by_name("first")); 28 | assert_eq!(Some(TestFieldName::SecondField), TestFieldName::by_name("second_field")); 29 | assert_eq!(None, TestFieldName::by_name("third")); 30 | 31 | let fields = Test::as_field_name_array(); 32 | assert_eq!([TestFieldName::First, TestFieldName::SecondField], fields); 33 | ``` 34 | 35 | The `..FieldType` enum contains some types with names corresponding to the names of the structure fields and 36 | with values corresponding to the value types of the structure fields. 37 | 38 | The `FieldType` usage example: 39 | 40 | ```rust 41 | use field_types::FieldType; 42 | use variant_count::VariantCount; 43 | 44 | #[derive(FieldType)] 45 | #[field_type_derive(VariantCount)] 46 | struct Test { 47 | first: i32, 48 | second_field: Option, 49 | #[field_type(skip)] 50 | third: bool, 51 | } 52 | 53 | let test = Test { 54 | first: 1, 55 | second_field: Some("test".to_string()), 56 | third: true, 57 | }; 58 | 59 | let fields: [TestFieldType; TestFieldType::VARIANT_COUNT] = test.into(); 60 | // or 61 | // let fields = test.into_field_type_array(); 62 | 63 | assert!(match fields { 64 | [TestFieldType::First(1), TestFieldType::SecondField(Some(ref s))] if s == "test" => true, 65 | _ => false, 66 | }); 67 | ``` 68 | 69 | In both cases you can skip fields with `#[attr(skip)]` or `#[attr = "skip"]` field attributes, where `attr` is `field_name` for `FieldName`, `field_type` for `FieldType` or `field_types` for any field type derives. 70 | You can also specifying some derives for generated enums with `#[attr_derive(..)]` structure attribute, where `attr_derive` is `field_name_derive`, `field_type_derive` or `field_types_derive`. For example: 71 | 72 | ```rust 73 | #[derive(FieldType, FieldName)] 74 | #[field_types_derive(VariantCount, Debug, Clone, PartialEq)] 75 | struct Test { 76 | first: i32, 77 | second: Option, 78 | #[field_types(skip)] 79 | third: bool, 80 | #[field_name = "skip"] 81 | fourth: bool, 82 | } 83 | ``` 84 | 85 | By default, `FieldName` has derive `Debug`, `PartialEq`, `Eq`, `Clone` and `Copy`. More usage examples see in [tests](tests) directory. 86 | 87 | ## Usage 88 | 89 | If you're using Cargo, just add it to your Cargo.toml: 90 | 91 | ```toml 92 | [dependencies] 93 | field_types = "*" 94 | ``` 95 | 96 | ## License 97 | 98 | MIT -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | This crate provides `FieldName` and `FieldType` derive macros for deriving enums, corresponding to the fields of structs. 3 | 4 | ## Features 5 | 6 | ### `..FieldName` enum 7 | 8 | * Variants with UpperCamelCase unit type names corresponding to the snake_case field names of the struct 9 | * Skipping fields with `#[field_name(skip)]` or `#[field_types(skip)]` attributes 10 | * Specifying some derives for generated enums with `#[field_name_derive(..)]` or `#[field_types_derive(..)]` structure attributes. 11 | By default, `..FieldName` has derive `Debug`, `PartialEq`, `Eq`, `Clone` and `Copy`. 12 | * Associated function `as_field_name_array` that returns array of variants 13 | * `From`/`Into` convert the struct reference to an array of variants 14 | * `name`/`by_name` methods for convert enum variants to/from string representation field names 15 | 16 | ### `..FieldType` enum 17 | 18 | * Variants with UpperCamelCase type names corresponding to the snake_case field names of the struct 19 | and with values corresponding to the value types of the struct fields 20 | * Skipping fields with `#[field_type(skip)]` or `#[field_types(skip)]` attributes 21 | * Specifying some derives for generated enums with `#[field_type_derive(..)]` or `#[field_types_derive(..)]` structure attributes 22 | * Associated function `into_field_type_array` that convert the struct into an array of variants with field values 23 | * `Into` convert the struct into an array of variants with field values 24 | 25 | ## Example 26 | 27 | ```rust 28 | extern crate variant_count; 29 | extern crate field_types; 30 | 31 | use variant_count::VariantCount; 32 | use field_types::{FieldName, FieldType}; 33 | 34 | #[derive(FieldName, FieldType)] 35 | #[field_type_derive(VariantCount)] 36 | struct Test { 37 | first: i32, 38 | second_field: Option, 39 | #[field_types(skip)] 40 | third: bool, 41 | } 42 | 43 | fn main() { 44 | assert_eq!(TestFieldName::First.name(), "first"); 45 | assert_eq!(TestFieldName::SecondField.name(), "second_field"); 46 | 47 | assert_eq!(Some(TestFieldName::First), TestFieldName::by_name("first")); 48 | assert_eq!(Some(TestFieldName::SecondField), TestFieldName::by_name("second_field")); 49 | assert_eq!(None, TestFieldName::by_name("third")); 50 | 51 | let fields = Test::as_field_name_array(); 52 | assert_eq!([TestFieldName::First, TestFieldName::SecondField], fields); 53 | 54 | let test = Test { 55 | first: 1, 56 | second_field: Some("test".to_string()), 57 | third: true, 58 | }; 59 | 60 | let fields = test.into_field_type_array(); 61 | assert!(match fields { 62 | [TestFieldType::First(1), TestFieldType::SecondField(Some(ref s))] if s == "test" => true, 63 | _ => false, 64 | }); 65 | 66 | let test = Test { 67 | first: 1, 68 | second_field: Some("test".to_string()), 69 | third: true, 70 | }; 71 | 72 | let fields: [TestFieldType; TestFieldType::VARIANT_COUNT] = test.into(); 73 | assert!(match fields { 74 | [TestFieldType::First(1), TestFieldType::SecondField(Some(ref s))] if s == "test" => true, 75 | _ => false, 76 | }); 77 | } 78 | ``` 79 | 80 | ## Usage 81 | 82 | If you're using Cargo, just add it to your Cargo.toml: 83 | 84 | ```toml 85 | [dependencies] 86 | field_types = "*" 87 | ``` 88 | 89 | Use `FieldName` and/or `FieldType` in `derive` struct attribute. 90 | !*/ 91 | 92 | extern crate proc_macro; 93 | extern crate syn; 94 | extern crate quote; 95 | extern crate heck; 96 | 97 | use std::iter::FromIterator; 98 | use proc_macro::TokenStream; 99 | use syn::{ 100 | DeriveInput, Ident, Type, Attribute, Fields, Meta, Path, PathArguments, PathSegment, 101 | export::{Span, TokenStream2}, 102 | punctuated::Punctuated, 103 | }; 104 | use quote::{quote, ToTokens}; 105 | use heck::CamelCase; 106 | 107 | #[proc_macro_derive(FieldType, attributes(field_types, field_type, field_types_derive, field_type_derive))] 108 | pub fn field_type(input: TokenStream) -> TokenStream { 109 | let ast: DeriveInput = syn::parse(input).unwrap(); 110 | let (vis, ty, generics) = (&ast.vis, &ast.ident, &ast.generics); 111 | let enum_ty = Ident::new(&(ty.to_string() + "FieldType"), Span::call_site()); 112 | let derive = get_enum_derive(&ast.attrs, &["field_types_derive", "field_type_derive"], quote! {}); 113 | 114 | let fields = filter_fields(match ast.data { 115 | syn::Data::Struct(ref s) => &s.fields, 116 | _ => panic!("FieldType can only be derived for structures"), 117 | }, "field_type"); 118 | 119 | if fields.is_empty() { 120 | panic!("FieldType can only be derived for non-empty structures"); 121 | } 122 | 123 | let field_type_variants = fields.iter() 124 | .map(|(_, field_ty, variant_ident)| { 125 | quote! { 126 | #variant_ident(#field_ty) 127 | } 128 | }); 129 | 130 | let field_type_constructs = fields.iter() 131 | .map(|(field_ident, _, variant_ident)| { 132 | quote! { 133 | #enum_ty::#variant_ident(#field_ident) 134 | } 135 | }); 136 | 137 | let from_field_type_constructs = field_type_constructs.clone(); 138 | 139 | let fields_idents = fields.iter() 140 | .map(|(field_ident, _, _)| { 141 | quote! { 142 | #field_ident 143 | } 144 | }); 145 | 146 | let destructuring = quote! { #ty { #(#fields_idents,)* .. } }; 147 | 148 | let fields_count = fields.len(); 149 | 150 | let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 151 | 152 | let converter = if generics.params.is_empty() { 153 | quote! { 154 | impl From<#ty> for [#enum_ty; #fields_count] { 155 | fn from(source: #ty) -> Self { 156 | let #destructuring = source; 157 | [#(#from_field_type_constructs),*] 158 | } 159 | } 160 | } 161 | } else { 162 | quote! { 163 | impl #impl_generics Into<[#enum_ty #ty_generics; #fields_count]> for #ty #ty_generics 164 | #where_clause 165 | { 166 | fn into(self) -> [#enum_ty #ty_generics; #fields_count] { 167 | let #destructuring = self; 168 | [#(#from_field_type_constructs),*] 169 | } 170 | } 171 | } 172 | }; 173 | 174 | let tokens = quote! { 175 | #derive 176 | #vis enum #enum_ty #generics 177 | #where_clause 178 | { 179 | #(#field_type_variants),* 180 | } 181 | 182 | #converter 183 | 184 | impl #impl_generics #ty #ty_generics 185 | #where_clause 186 | { 187 | #vis fn into_field_type_array(self) -> [#enum_ty #ty_generics; #fields_count] { 188 | let #destructuring = self; 189 | [#(#field_type_constructs),*] 190 | } 191 | } 192 | }; 193 | tokens.into() 194 | } 195 | 196 | #[proc_macro_derive(FieldName, attributes(field_types, field_name, field_types_derive, field_name_derive))] 197 | pub fn field_name(input: TokenStream) -> TokenStream { 198 | let ast: DeriveInput = syn::parse(input).unwrap(); 199 | let (vis, ty, generics) = (&ast.vis, &ast.ident, &ast.generics); 200 | let enum_ty = Ident::new(&(ty.to_string() + "FieldName"), Span::call_site()); 201 | let derive = get_enum_derive(&ast.attrs, &["field_types_derive", "field_name_derive"], 202 | quote! { #[derive(Debug, PartialEq, Eq, Clone, Copy)] }); 203 | 204 | let fields = filter_fields(match ast.data { 205 | syn::Data::Struct(ref s) => &s.fields, 206 | _ => panic!("FieldName can only be derived for structures"), 207 | }, "field_name"); 208 | 209 | if fields.is_empty() { 210 | panic!("FieldName can only be derived for non-empty structures"); 211 | } 212 | 213 | let field_name_variants = fields.iter() 214 | .map(|(_, _, variant_ident)| { 215 | quote! { 216 | #variant_ident 217 | } 218 | }); 219 | 220 | let field_name_to_strs = fields.iter() 221 | .map(|(field_ident, _, variant_ident)| { 222 | let field_name = field_ident.to_string(); 223 | quote! { 224 | #enum_ty::#variant_ident => #field_name 225 | } 226 | }); 227 | 228 | let field_name_by_strs = fields.iter() 229 | .map(|(_, _, variant_ident)| { 230 | quote! { 231 | if #enum_ty::#variant_ident.name() == name { return Some(#enum_ty::#variant_ident) } 232 | } 233 | }); 234 | 235 | let field_name_constructs = fields.iter() 236 | .map(|(_, _, variant_ident)| { 237 | quote! { 238 | #enum_ty::#variant_ident 239 | } 240 | }); 241 | 242 | let from_field_name_constructs = field_name_constructs.clone(); 243 | 244 | let fields_count = fields.len(); 245 | 246 | let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 247 | let from_lifetime = quote! { 'field_name_from_lifetime__ }; 248 | 249 | let mut impl_generics_tokens = TokenStream2::new(); 250 | impl_generics.to_tokens(&mut impl_generics_tokens); 251 | if impl_generics_tokens.is_empty() { 252 | impl_generics_tokens = quote! { <#from_lifetime> }; 253 | } else { 254 | let mut tokens: Vec<_> = quote! { #from_lifetime, }.into_iter().collect(); 255 | let mut gen_iter = impl_generics_tokens.into_iter(); 256 | if let Some(token) = gen_iter.next() { 257 | tokens.insert(0, token); 258 | } 259 | tokens.extend(gen_iter); 260 | impl_generics_tokens = TokenStream2::from_iter(tokens); 261 | } 262 | 263 | let tokens = quote! { 264 | #derive 265 | #vis enum #enum_ty { 266 | #(#field_name_variants),* 267 | } 268 | 269 | impl #enum_ty { 270 | #vis fn name(&self) -> &'static str { 271 | match *self { 272 | #(#field_name_to_strs),* 273 | } 274 | } 275 | 276 | #vis fn by_name(name: &str) -> Option { 277 | #(#field_name_by_strs)* 278 | None 279 | } 280 | } 281 | 282 | impl #impl_generics #ty #ty_generics 283 | #where_clause 284 | { 285 | #vis fn as_field_name_array() -> [#enum_ty; #fields_count] { 286 | [#(#field_name_constructs),*] 287 | } 288 | } 289 | 290 | impl #impl_generics_tokens From<& #from_lifetime #ty #ty_generics> for [#enum_ty; #fields_count] { 291 | fn from(_source: & #from_lifetime #ty #ty_generics) -> Self { 292 | [#(#from_field_name_constructs),*] 293 | } 294 | } 295 | }; 296 | tokens.into() 297 | } 298 | 299 | fn get_enum_derive(attrs: &[Attribute], derive_attr_names: &[&str], default: TokenStream2) -> TokenStream2 { 300 | attrs.iter() 301 | .filter_map(|attr| attr.parse_meta() 302 | .ok() 303 | .and_then(|meta| { 304 | for attr_name in derive_attr_names { 305 | let attr_ident = Some(Ident::new(attr_name, Span::call_site())); 306 | let ident = meta.path().get_ident(); 307 | if ident == attr_ident.as_ref() { 308 | if let Meta::List(meta_list) = &meta { 309 | let mut meta_list = meta_list.clone(); 310 | meta_list.path = Path { 311 | leading_colon: None, 312 | segments: { 313 | let mut segments = Punctuated::new(); 314 | segments.push(PathSegment { 315 | ident: Ident::new("derive", Span::call_site()), 316 | arguments: PathArguments::None, 317 | }); 318 | segments 319 | } 320 | }; 321 | return Some(meta_list); 322 | } 323 | } 324 | } 325 | None 326 | }) 327 | ) 328 | .next() 329 | .map(|meta_list| quote! { #[#meta_list] }) 330 | .unwrap_or(default) 331 | } 332 | 333 | fn filter_fields(fields: &Fields, skip_attr_name: &str) -> Vec<(Ident, Type, Ident)> { 334 | fields.iter() 335 | .filter_map(|field| { 336 | if field.attrs.iter() 337 | .find(|attr| has_skip_attr(attr, &["field_types", skip_attr_name])) 338 | .is_none() && field.ident.is_some() 339 | { 340 | let field_ty = field.ty.clone(); 341 | let field_ident = field.ident.as_ref().unwrap().clone(); 342 | let field_name = field.ident.as_ref().unwrap().to_string(); 343 | let variant_ident = Ident::new(&field_name.to_camel_case(), Span::call_site()); 344 | Some((field_ident, field_ty, variant_ident)) 345 | } else { 346 | None 347 | } 348 | }) 349 | .collect::>() 350 | } 351 | 352 | fn has_skip_attr(attr: &Attribute, attr_names: &[&str]) -> bool { 353 | attr.parse_meta() 354 | .ok() 355 | .and_then(|meta| { 356 | for attr_name in attr_names { 357 | let attr_ident = Some(Ident::new(attr_name, Span::call_site())); 358 | let ident = meta.path().get_ident(); 359 | if ident == attr_ident.as_ref() { 360 | return Some(meta); 361 | } 362 | } 363 | None 364 | }) 365 | .map(|meta| { 366 | let value = match meta { 367 | Meta::List(ref list) => list.nested.first() 368 | .expect("Attribute value can't be empty") 369 | .clone() 370 | .into_token_stream() 371 | .to_string(), 372 | 373 | Meta::NameValue(ref name_value) => name_value.lit 374 | .clone() 375 | .into_token_stream() 376 | .to_string(), 377 | 378 | _ => panic!("Unknown attribute value, only `skip` allowed."), 379 | }; 380 | if value != "skip" && value.find("\"skip\"").is_none() { 381 | panic!("Unknown attribute value `{}`, only `skip` allowed.", value); 382 | } 383 | }) 384 | .is_some() 385 | } 386 | -------------------------------------------------------------------------------- /tests/field_name.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | extern crate variant_count; 4 | extern crate field_types; 5 | 6 | use variant_count::VariantCount; 7 | use field_types::FieldName; 8 | 9 | #[derive(FieldName)] 10 | struct Test { 11 | first: i32, 12 | second_field: Option, 13 | #[field_name(skip)] 14 | third: bool, 15 | #[field_name = "skip"] 16 | fourth: bool, 17 | } 18 | 19 | #[derive(FieldName)] 20 | #[field_name_derive(VariantCount, Debug, Clone, PartialEq)] 21 | struct TestGen<'a, T: 'a, U> 22 | where U: 'a 23 | { 24 | first: T, 25 | second_field: Option<&'a U>, 26 | #[field_name(skip)] 27 | third: &'a T, 28 | #[field_types = "skip"] 29 | fourth: U, 30 | } 31 | 32 | #[derive(FieldName)] 33 | #[field_types_derive(VariantCount, Debug, Clone, PartialEq)] 34 | struct TestTypesDerive { 35 | first: i32, 36 | second: bool, 37 | } 38 | 39 | #[derive(FieldName)] 40 | #[field_name_derive(VariantCount, Debug, Clone, PartialEq)] 41 | struct TestNameDerive { 42 | first: i32, 43 | second: bool, 44 | } 45 | 46 | #[test] 47 | fn full_field_name_variants() { 48 | let _field = TestFieldName::First; 49 | let field = TestFieldName::SecondField; 50 | match field { 51 | TestFieldName::First => (), 52 | TestFieldName::SecondField => (), 53 | } 54 | 55 | let _field = TestGenFieldName::First; 56 | let field = TestGenFieldName::SecondField; 57 | match field { 58 | TestGenFieldName::First => (), 59 | TestGenFieldName::SecondField => (), 60 | } 61 | 62 | let _field = TestTypesDeriveFieldName::First; 63 | let field = TestTypesDeriveFieldName::Second; 64 | match field { 65 | TestTypesDeriveFieldName::First => (), 66 | TestTypesDeriveFieldName::Second => (), 67 | } 68 | 69 | let _field = TestNameDeriveFieldName::First; 70 | let field = TestNameDeriveFieldName::Second; 71 | match field { 72 | TestNameDeriveFieldName::First => (), 73 | TestNameDeriveFieldName::Second => (), 74 | } 75 | } 76 | 77 | #[test] 78 | fn derive_field_name() { 79 | let name = TestFieldName::First; 80 | assert_eq!(TestFieldName::First, name); 81 | assert_ne!(TestFieldName::SecondField, name); 82 | 83 | let name = TestGenFieldName::First; 84 | assert_eq!(TestGenFieldName::First, name); 85 | assert_ne!(TestGenFieldName::SecondField, name); 86 | 87 | let name = TestTypesDeriveFieldName::First.clone(); 88 | assert_eq!(TestTypesDeriveFieldName::First, name); 89 | assert_ne!(TestTypesDeriveFieldName::Second, name); 90 | 91 | let name = TestTypesDeriveFieldName::Second.clone(); 92 | assert_eq!(TestTypesDeriveFieldName::Second, name); 93 | assert_ne!(TestTypesDeriveFieldName::First, name); 94 | } 95 | 96 | #[test] 97 | fn into_field_name() { 98 | let test = Test { 99 | first: 1, 100 | second_field: Some("test".to_string()), 101 | third: true, 102 | fourth: true, 103 | }; 104 | let fields: [TestFieldName; 2] = (&test).into(); 105 | assert!(match fields { 106 | [TestFieldName::First, TestFieldName::SecondField] => true, 107 | _ => false, 108 | }); 109 | 110 | let message = "test".to_string(); 111 | let test = TestGen { 112 | first: 1, 113 | second_field: Some(&message), 114 | third: &2, 115 | fourth: message.clone(), 116 | }; 117 | let fields: [TestGenFieldName; TestGenFieldName::VARIANT_COUNT] = (&test).into(); 118 | assert!(match fields { 119 | [TestGenFieldName::First, TestGenFieldName::SecondField] => true, 120 | _ => false, 121 | }); 122 | 123 | let test = TestTypesDerive { 124 | first: 1, 125 | second: true, 126 | }; 127 | let fields: [TestTypesDeriveFieldName; TestTypesDeriveFieldName::VARIANT_COUNT] = (&test).into(); 128 | assert_eq!(TestTypesDeriveFieldName::First, fields[0]); 129 | assert_eq!(TestTypesDeriveFieldName::Second, fields[1]); 130 | } 131 | 132 | #[test] 133 | fn field_name_str() { 134 | assert_eq!(TestFieldName::First.name(), "first"); 135 | assert_eq!(TestFieldName::SecondField.name(), "second_field"); 136 | 137 | assert_eq!(Some(TestFieldName::First), TestFieldName::by_name("first")); 138 | assert_eq!(Some(TestFieldName::SecondField), TestFieldName::by_name("second_field")); 139 | assert_eq!(None, TestFieldName::by_name("third")); 140 | } 141 | -------------------------------------------------------------------------------- /tests/field_type.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | extern crate variant_count; 4 | extern crate field_types; 5 | 6 | use variant_count::VariantCount; 7 | use field_types::FieldType; 8 | 9 | #[derive(FieldType)] 10 | struct Test { 11 | first: i32, 12 | second_field: Option, 13 | #[field_type(skip)] 14 | third: bool, 15 | #[field_type = "skip"] 16 | fourth: bool, 17 | } 18 | 19 | #[derive(FieldType)] 20 | #[field_type_derive(VariantCount, Debug, Clone, PartialEq)] 21 | struct TestGen<'a, T: 'a, U> 22 | where U: 'a 23 | { 24 | first: T, 25 | second_field: Option<&'a U>, 26 | #[field_type(skip)] 27 | third: &'a T, 28 | #[field_types = "skip"] 29 | fourth: U, 30 | } 31 | 32 | #[derive(FieldType)] 33 | #[field_types_derive(VariantCount, Debug, Clone, PartialEq)] 34 | struct TestTypesDerive { 35 | first: i32, 36 | second: bool, 37 | } 38 | 39 | #[derive(FieldType)] 40 | #[field_type_derive(VariantCount, Debug, Clone, PartialEq)] 41 | struct TestTypeDerive { 42 | first: i32, 43 | second: bool, 44 | } 45 | 46 | #[test] 47 | fn full_field_type_variants() { 48 | let _field = TestFieldType::First(2); 49 | let field = TestFieldType::SecondField(None); 50 | match field { 51 | TestFieldType::First(_) => (), 52 | TestFieldType::SecondField(_) => (), 53 | } 54 | 55 | let _field = TestGenFieldType::First::<_, &str>(2); 56 | let field = TestGenFieldType::SecondField::(None); 57 | match field { 58 | TestGenFieldType::First(_) => (), 59 | TestGenFieldType::SecondField(_) => (), 60 | } 61 | 62 | let first_field = TestTypesDeriveFieldType::First(2); 63 | match first_field { 64 | TestTypesDeriveFieldType::First(_) => (), 65 | TestTypesDeriveFieldType::Second(_) => (), 66 | } 67 | 68 | let _field = TestTypeDeriveFieldType::First(2); 69 | let field = TestTypeDeriveFieldType::Second(false); 70 | match field { 71 | TestTypeDeriveFieldType::First(_) => (), 72 | TestTypeDeriveFieldType::Second(_) => (), 73 | } 74 | } 75 | 76 | #[test] 77 | fn derive_field_type() { 78 | let first_field = TestGenFieldType::First::<_, &str>(2); 79 | let second_field = TestGenFieldType::SecondField::(None); 80 | assert_ne!(first_field, second_field); 81 | assert_eq!(first_field, first_field.clone()); 82 | assert_eq!("First(2)", format!("{:?}", first_field)); 83 | 84 | let field = TestTypesDeriveFieldType::First(1).clone(); 85 | assert_eq!(TestTypesDeriveFieldType::First(1), field); 86 | assert_ne!(TestTypesDeriveFieldType::First(2), field); 87 | assert_eq!("First(1)", format!("{:?}", field)); 88 | 89 | let field = TestTypesDeriveFieldType::Second(true).clone(); 90 | assert_eq!(TestTypesDeriveFieldType::Second(true), field); 91 | assert_ne!(TestTypesDeriveFieldType::Second(false), field); 92 | assert_eq!("Second(true)", format!("{:?}", field)); 93 | 94 | let field = TestTypeDeriveFieldType::First(1).clone(); 95 | assert_eq!(TestTypeDeriveFieldType::First(1), field); 96 | assert_ne!(TestTypeDeriveFieldType::First(2), field); 97 | assert_eq!("First(1)", format!("{:?}", field)); 98 | 99 | let field = TestTypeDeriveFieldType::Second(true).clone(); 100 | assert_eq!(TestTypeDeriveFieldType::Second(true), field); 101 | assert_ne!(TestTypeDeriveFieldType::Second(false), field); 102 | assert_eq!("Second(true)", format!("{:?}", field)); 103 | } 104 | 105 | #[test] 106 | fn into_field_type() { 107 | let test = Test { 108 | first: 1, 109 | second_field: Some("test".to_string()), 110 | third: true, 111 | fourth: true, 112 | }; 113 | let fields: [TestFieldType; 2] = test.into(); 114 | assert!(match fields { 115 | [TestFieldType::First(1), TestFieldType::SecondField(Some(ref s))] if s == "test" => true, 116 | _ => false, 117 | }); 118 | 119 | let message = "test".to_string(); 120 | let test = TestGen { 121 | first: 1, 122 | second_field: Some(&message), 123 | third: &2, 124 | fourth: message.clone(), 125 | }; 126 | let fields: [TestGenFieldType; TestGenFieldType::::VARIANT_COUNT] = test.into(); 127 | assert!(match fields { 128 | [TestGenFieldType::First(1), TestGenFieldType::SecondField(Some(s))] if s == &message => true, 129 | _ => false, 130 | }); 131 | 132 | let test = TestTypesDerive { 133 | first: 1, 134 | second: true, 135 | }; 136 | let fields: [TestTypesDeriveFieldType; TestTypesDeriveFieldType::VARIANT_COUNT] = test.into(); 137 | assert_eq!(TestTypesDeriveFieldType::First(1), fields[0]); 138 | assert_eq!(TestTypesDeriveFieldType::Second(true), fields[1]); 139 | } 140 | -------------------------------------------------------------------------------- /tests/field_types.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | extern crate variant_count; 4 | extern crate field_types; 5 | 6 | use variant_count::VariantCount; 7 | use field_types::{FieldType, FieldName}; 8 | 9 | #[derive(FieldType, FieldName)] 10 | #[field_types_derive(VariantCount, Debug, Clone, PartialEq)] 11 | struct Test { 12 | first: i32, 13 | second_field: Option, 14 | #[field_types(skip)] 15 | third: bool, 16 | #[field_name = "skip"] 17 | fourth: bool, 18 | } 19 | 20 | impl Test { 21 | fn foo() -> bool { 22 | true 23 | } 24 | } 25 | 26 | mod bar { 27 | use variant_count::VariantCount; 28 | use field_types::{FieldType, FieldName}; 29 | 30 | #[derive(FieldType, FieldName)] 31 | #[field_types_derive(VariantCount, Debug, Clone, PartialEq)] 32 | pub struct TestGen<'a, T: 'a, U> 33 | where U: 'a 34 | { 35 | first: T, 36 | second_field: Option<&'a U>, 37 | #[field_types(skip)] 38 | third: &'a T, 39 | #[field_name = "skip"] 40 | fourth: U, 41 | } 42 | 43 | impl<'a, T: 'a, U> TestGen<'a, T, U> 44 | where U: 'a 45 | { 46 | pub fn new(first: T, second: &'a U, third: &'a T, fourth: U) -> Self { 47 | let second_field = Some(second); 48 | TestGen { 49 | first, 50 | second_field, 51 | third, 52 | fourth, 53 | } 54 | } 55 | } 56 | } 57 | 58 | use bar::{TestGen, TestGenFieldType, TestGenFieldName}; 59 | 60 | #[test] 61 | fn full_field_types_variants() { 62 | let _field = TestFieldType::First(2); 63 | let _field = TestFieldType::Fourth(false); 64 | let field = TestFieldType::SecondField(None); 65 | match field { 66 | TestFieldType::First(_) => (), 67 | TestFieldType::SecondField(_) => (), 68 | TestFieldType::Fourth(_) => (), 69 | } 70 | 71 | let _field = TestFieldName::First; 72 | let field = TestFieldName::SecondField; 73 | match field { 74 | TestFieldName::First => (), 75 | TestFieldName::SecondField => (), 76 | } 77 | 78 | let _field = TestGenFieldType::First::<_, bool>(2); 79 | let _field = TestGenFieldType::Fourth::(false); 80 | let field = TestGenFieldType::SecondField::(None); 81 | match field { 82 | TestGenFieldType::First(_) => (), 83 | TestGenFieldType::SecondField(_) => (), 84 | TestGenFieldType::Fourth(_) => (), 85 | } 86 | 87 | let _field = TestGenFieldName::First; 88 | let field = TestGenFieldName::SecondField; 89 | match field { 90 | TestGenFieldName::First => (), 91 | TestGenFieldName::SecondField => (), 92 | } 93 | } 94 | 95 | #[test] 96 | fn derive_field_types() { 97 | let field = TestFieldType::First(1).clone(); 98 | assert_eq!(TestFieldType::First(1), field); 99 | assert_ne!(TestFieldType::First(2), field); 100 | 101 | let first_field = TestGenFieldType::First::<_, &str>(2); 102 | let second_field = TestGenFieldType::SecondField::(None); 103 | assert_ne!(first_field, second_field); 104 | assert_eq!(first_field, first_field.clone()); 105 | assert_eq!("First(2)", format!("{:?}", first_field)); 106 | 107 | let field = TestFieldType::SecondField(Some("test".to_string())).clone(); 108 | assert_eq!(TestFieldType::SecondField(Some("test".to_string())), field); 109 | assert_ne!(TestFieldType::SecondField(Some("".to_string())), field); 110 | 111 | let name = TestFieldName::First; 112 | assert_eq!(TestFieldName::First, name); 113 | assert_ne!(TestFieldName::SecondField, name); 114 | 115 | let name = TestFieldName::SecondField; 116 | assert_eq!(TestFieldName::SecondField, name); 117 | assert_ne!(TestFieldName::First, name); 118 | } 119 | 120 | #[test] 121 | fn into_field_types() { 122 | let test = Test { 123 | first: 1, 124 | second_field: Some("test".to_string()), 125 | third: true, 126 | fourth: true, 127 | }; 128 | let fields: [TestFieldType; TestFieldType::VARIANT_COUNT] = test.into(); 129 | assert!(match fields { 130 | [TestFieldType::First(1), TestFieldType::SecondField(Some(ref s)), TestFieldType::Fourth(true)] if s == "test" => true, 131 | _ => false, 132 | }); 133 | 134 | let test = Test { 135 | first: 1, 136 | second_field: Some("test".to_string()), 137 | third: true, 138 | fourth: true, 139 | }; 140 | let names: [TestFieldName; TestFieldName::VARIANT_COUNT] = (&test).into(); 141 | assert!(match names { 142 | [TestFieldName::First, TestFieldName::SecondField] => true, 143 | _ => false, 144 | }); 145 | 146 | let message = "test".to_string(); 147 | 148 | let test = TestGen::new(1, &message, &2, message.clone()); 149 | let fields = test.into_field_type_array(); 150 | assert!(match fields { 151 | [TestGenFieldType::First(1), TestGenFieldType::SecondField(Some(s)), TestGenFieldType::Fourth(_)] if s == &message => true, 152 | _ => false, 153 | }); 154 | 155 | let test = TestGen::new(1, &message, &2, message.clone()); 156 | let fields: [TestGenFieldType; TestGenFieldType::::VARIANT_COUNT] = test.into(); 157 | assert!(match fields { 158 | [TestGenFieldType::First(1), TestGenFieldType::SecondField(Some(s)), TestGenFieldType::Fourth(_)] if s == &message => true, 159 | _ => false, 160 | }); 161 | 162 | let fields = TestGen::<'_, i32, String>::as_field_name_array(); 163 | assert!(match fields { 164 | [TestGenFieldName::First, TestGenFieldName::SecondField] => true, 165 | _ => false, 166 | }); 167 | 168 | let test = TestGen::new(1, &message, &2, message.clone()); 169 | let fields: [TestGenFieldName; TestGenFieldName::VARIANT_COUNT] = (&test).into(); 170 | assert!(match fields { 171 | [TestGenFieldName::First, TestGenFieldName::SecondField] => true, 172 | _ => false, 173 | }); 174 | } 175 | 176 | #[test] 177 | fn field_name_str() { 178 | assert_eq!(TestFieldName::First.name(), "first"); 179 | assert_eq!(TestFieldName::SecondField.name(), "second_field"); 180 | 181 | assert_eq!(Some(TestFieldName::First), TestFieldName::by_name("first")); 182 | assert_eq!(Some(TestFieldName::SecondField), TestFieldName::by_name("second_field")); 183 | assert_eq!(None, TestFieldName::by_name("third")); 184 | } 185 | --------------------------------------------------------------------------------