Skip to main content

FieldType

Derive Macro FieldType 

Source
#[derive(FieldType)]
{
    // Attributes available to this derive:
    #[stem_type]
    #[ste_type]
    #[stem_type_derive]
    #[ste_type_derive]
    #[stem_type_attr]
    #[ste_type_attr]
}
Expand description

Generates {StructName}FieldType, an enum whose variants wrap struct field values. For enum variants without values use FieldName instead.

Each non-skipped field becomes a variant VariantName(FieldType) where the variant name is the field name in PascalCase. The variants are ordered by field declaration order.

No derives are added by default. Add derives with #[stem_type_derive(...)].

§Attributes

AttributeTargetDescription
#[stem_type(skip)]fieldExclude this field from the generated enum.
#[stem_type(nested)]fieldFlatten the nested struct’s FieldType variants into this enum.
#[stem_type_derive(...)]structDerives for the generated enum. None are added by default.
#[stem_type_attr(...)]structExtra attributes applied verbatim to the generated enum.

All stem_type* attributes have short aliases: ste_type, ste_type_derive, ste_type_attr.

§Generated items

For a struct Foo with N non-skipped fields, this macro generates:

enum FooFieldType { Field1(T1), Field2(T2), ... }

impl From<Foo> for [FooFieldType; N] { ... }

§Example

use struct_to_enum::FieldType;

#[derive(Clone)]
#[derive(FieldType)]
#[stem_type_derive(Debug, PartialEq, Clone)]
struct Config {
    width: u32,
    height: u32,
    #[stem_type(skip)]
    name: String,
}

// Generated: 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));

§Flattening nested structs

Mark a field with #[stem_type(nested)] to inline the variants of a nested struct (which must also derive FieldType) directly into the parent enum. Nesting can be arbitrarily deep.

use struct_to_enum::FieldType;

#[derive(FieldType)]
#[stem_type_derive(Debug, PartialEq)]
struct Color {
    r: u8,
    g: u8,
    b: u8,
}

#[derive(FieldType)]
#[stem_type_derive(Debug, PartialEq)]
struct Pixel {
    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));
}

§Generics

Generic structs are supported. The generated enum carries the same type parameters:

use struct_to_enum::FieldType;

#[derive(FieldType)]
#[stem_type_derive(Debug, PartialEq)]
struct Pair<A, B> {
    first: A,
    second: B,
}

// Generated: enum PairFieldType<A, B> { First(A), Second(B) }

let fields: [PairFieldType<i32, &str>; 2] = Pair { first: 42_i32, second: "hi" }.into();
assert_eq!(fields[0], PairFieldType::First(42));

§Combining with other derives

Use #[stem_type_derive] and #[stem_type_attr] to pass anything to the generated enum. This works with crates like strum:

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"))]
struct Request {
    user_id: u64,
    payload: Vec<u8>,
}

assert_eq!(RequestFieldType::VARIANTS, ["USER-ID", "PAYLOAD"]);