struct-to-enum crate provides two derive macros for generating enums corresponding to the fields of structs:
FieldName— generates a unit enum where each variant represents a field nameFieldType— generates an enum where each variant wraps the type of a struct field
Both macros support generics, field skipping, nesting, and custom derives/attributes on the generated enum.
Intended use-case is to generate enums from struct fields, enabling compile-time column filter validation for queries.
[dependencies]
struct-to-enum = {version="1.0", features = ["derive"] }Generates a unit enum {StructName}FieldName and implements [FieldNames<N>] on the struct,
which provides a field_names() static method returning an ordered array of all variants.
use struct_to_enum::{FieldName,FieldNames};#[derive(FieldName)]structPoint{x:f32,y:f32,#[stem_name(skip)]label:String,}// Generated:// #[derive(Debug, PartialEq, Eq, Clone, Copy)]// enum PointFieldName { X, Y }let names:[PointFieldName;2] = Point::field_names();assert_eq!(names,[PointFieldName::X,PointFieldName::Y]);Mark a field with #[stem_name(nested)] to flatten its FieldName variants into the parent enum.
The nested struct must also derive FieldName. Nesting can be arbitrarily deep.
use struct_to_enum::{FieldName,FieldNames};#[derive(FieldName)]pubstructAddress{pubstreet:String,pubcity:String,}#[derive(FieldName)]structPerson{name:String,#[stem_name(nested)]address:Address,}// PersonFieldName has variants: Name, Street, City (Address's variants are inlined)let names:[PersonFieldName;3] = Person::field_names();assert_eq!(names,[PersonFieldName::Name,PersonFieldName::Street,PersonFieldName::City]);Generates a tuple-variant enum {StructName}FieldType and implements From<Struct> for
[FieldType; N], converting the struct into an ordered array of variants holding the field values.
use struct_to_enum::FieldType;#[derive(FieldType)]#[stem_type_derive(Debug,Clone,PartialEq)]structConfig{width:u32,height:u32,#[stem_type(skip)]name:String,}// Generated:// #[derive(Debug, Clone, PartialEq)]// enum ConfigFieldType {// Width(u32),// Height(u32),// }let cfg = Config{width:1920,height:1080,name:"hd".into()};let fields:[ConfigFieldType;2] = cfg.into();assert_eq!(fields[0],ConfigFieldType::Width(1920));assert_eq!(fields[1],ConfigFieldType::Height(1080));Mark a field with #[stem_type(nested)] to flatten the nested struct's FieldType variants
into the parent enum. The nested struct must also derive FieldType. Nesting can be arbitrarily deep.
use struct_to_enum::FieldType;#[derive(FieldType)]#[stem_type_derive(Debug,PartialEq)]structColor{r:u8,g:u8,b:u8,}#[derive(FieldType)]#[stem_type_derive(Debug,PartialEq)]structPixel{x:i32,y:i32,#[stem_type(nested)]color:Color,}// PixelFieldType has variants: X(i32), Y(i32), R(u8), G(u8), B(u8)let p = Pixel{x:10,y:20,color:Color{r:255,g:128,b:0}};let fields:[PixelFieldType;5] = p.into();assert_eq!(fields[0],PixelFieldType::X(10));assert_eq!(fields[2],PixelFieldType::R(255));Both macros handle generic structs with lifetime and type parameters.
use struct_to_enum::FieldType;#[derive(FieldType)]#[stem_type_derive(Debug,PartialEq)]structPair<A,B>{first:A,second:B,}let fields:[PairFieldType<i32,&str>;2] = Pair{first:1_i32,second:"hello"}.into();assert_eq!(fields[0],PairFieldType::First(1));use struct_to_enum::{FieldName,FieldNames,FieldType};#[derive(FieldName,FieldType)]#[stem_type_derive(Debug)]structRecord{id:u64,value:f64,}// RecordFieldName and RecordFieldType are both generatedlet _names:[RecordFieldName;2] = Record::field_names();| Attribute | Location | Description |
|---|---|---|
#[stem_name_derive(...)] | Struct | Merge additional derives onto the generated enum (defaults Debug, PartialEq, Eq, Clone, Copy are always kept) |
#[stem_name_attr(...)] | Struct | Add extra attributes to the generated enum |
#[stem_name(skip)] | Field | Exclude this field from the generated enum |
#[stem_name(nested)] | Field | Flatten the field's FieldName variants into the parent enum |
| Attribute | Location | Description |
|---|---|---|
#[stem_type_derive(...)] | Struct | Specify derives for the generated enum (none by default) |
#[stem_type_attr(...)] | Struct | Add extra attributes to the generated enum |
#[stem_type(skip)] | Field | Exclude this field from the generated enum |
#[stem_type(nested)] | Field | Flatten the field's FieldType variants into the parent enum |
Attribute aliases:
stem_name/ste_nameandstem_type/ste_typeare interchangeable.
use struct_to_enum::FieldType;use strum::VariantNames;#[derive(FieldType)]#[stem_type_derive(Debug, strum_macros::VariantNames)]#[stem_type_attr(strum(serialize_all = "SCREAMING-KEBAB-CASE"))]structRequest{user_id:u64,payload:Vec<u8>,}assert_eq!(RequestFieldType::VARIANTS,&["USER-ID","PAYLOAD"]);- field_types - the original inspiration for this crate.
struct-to-enumextends the idea with nesting, derive attributes, generics, and more. - strum - solves a similar problem (enum utilities via derive macros); a useful companion crate and a reference during development.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in struct-to-enum by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.