Expand description
§enum_convert
Crate to derive From implementations between enums.
§Features
- EnumFrom: Derive
From<Source> for AnnotatedEnum
- EnumInto: Derive
From<AnnotatedEnum> for Target
- Support for multiple source/target enums
- Flexible variant name mapping (one-to-many, many-to-one)
- Field-level mapping for named struct variants
- Automatic type conversion for fields via
.into()
§Usage
§EnumFrom - Convert from source enums to annotated target enum
use enum_convert::EnumFrom;
enum Source {
Unit,
Tuple(i32, String),
Struct { x: i32, y: i32 },
}
#[derive(EnumFrom)]
#[enum_from(Source)]
enum Target {
#[enum_from] // Maps from Source::Unit
Unit,
#[enum_from] // Maps from Source::Tuple with type conversion
Tuple(i64, String),
#[enum_from] // Maps from Source::Struct with type conversion
Struct { x: f64, y: f64 },
Extra, // This variant has no mapping
}
// Usage
let source = Source::Tuple(42, "hello".to_string());
let target: Target = source.into();
§EnumInto - Convert from annotated source enum to target enums
ℹ️ While the macro is named EnumInto
, it still implements From<AnnotatedEnum> for TargetEnum
and thus has an indirect implementation of Into
as recommended by the docs.
This is similar to derive_more
’s Into.
use enum_convert::EnumInto;
#[derive(EnumInto)]
#[enum_into(Target)]
enum Source {
Unit, // Maps to Target::Unit
#[enum_into(Target::Different)] // Maps to Target::Different
Variant(i32),
}
enum Target {
Unit,
Different(i64),
Extra,
}
// Usage
let source = Source::Variant(42);
let target: Target = source.into();
§Advanced Features
§Multiple source/target enums
use enum_convert::EnumFrom;
enum FirstSource {
Unit,
Data(String),
}
enum SecondSource {
Empty,
}
#[derive(EnumFrom)]
#[enum_from(FirstSource, SecondSource)]
enum Target {
#[enum_from(FirstSource, SecondSource::Empty)]
Unit,
#[enum_from(FirstSource)]
Data(String),
}
§Field mapping
use enum_convert::EnumFrom;
enum Source {
Tuple(String, u8),
Record {
name: String,
value: i32,
},
Point(i32, i32),
}
#[derive(EnumFrom)]
#[enum_from(Source)]
enum Target {
#[enum_from]
Tuple(
// We effectively re-order fields
#[enum_from(Source::Tuple.1)] u8,
#[enum_from(Source::Tuple.0)] String,
),
#[enum_from]
Record {
#[enum_from(Source::Record.name)] // Maps Source::Record.name to Target::Record.title
title: String,
value: i32,
},
#[enum_from]
Point {
#[enum_from(Source::Point.0)]
x: i64,
#[enum_from(Source::Point.1)]
y: i64,
},
}
§Related and similar crates
§derive_more
This crate has some similarities with derive_more’s From
and Into
derive macros.
The difference is that with derive_more
the conversion is field → variant (From
) and variant → field (Into
); with this crate it is variant ↔ variant.
#[derive(derive_more::From, enum_convert::EnumFrom)]
#[enum_from(OtherEnum)]
enum MyEnum {
#[enum_from]
Variant1(i32),
}
enum OtherEnum {
Variant1(i32),
}
// `derive_more::From` get expanded to
impl From<i32> for MyEnum {
fn from(value: i32) -> MyEnum {
MyEnum::Variant1(value)
}
}
// `enum_convert::EnumFrom` get expanded to
impl From<OtherEnum> for MyEnum {
fn from(value: OtherEnum) -> MyEnum {
match value {
OtherEnum::Variant1(i) => MyEnum::Variant1(i),
}
}
}
§enum_to_enum
This crate is very similar to enum_to_enum.
At the time of writing (enum_to_enum
in version 0.1.0) the differences are:
enum_convert
does not support many-to-one conversion with try_into logic .enum_convert
does not support effectful conversion.enum_to_enum
does not supportEnumInto
.enum_to_enum
does not support having variants in the target for which there is no mapping from source.enum_to_enum
does not support fields mapping.
For the common features, here is a comparison of how they are expressed in both crates:
enum SourceA {
Unit,
Tuple(i32, String),
Struct { x: i32, y: i32 },
}
enum SourceB {
Unit,
NoField,
Tuple(i32, String),
Struct { x: i32, y: i32 },
}
#[derive(enum_to_enum::FromEnum)]
#[from_enum(SourceA, SourceB)]
enum TargetEnumToEnum {
#[from_case(SourceB = NoField, Unit)]
Unit,
Tuple(i64, String),
Struct { x: f64, y: f64 },
}
#[derive(enum_convert::EnumFrom)]
#[enum_from(SourceA, SourceB)]
enum TargetEnumConvert {
#[enum_from(SourceA, SourceB::Unit, SourceB::NoField)]
Unit,
#[enum_from(SourceA, SourceB)]
Tuple(i64, String),
#[enum_from(SourceA, SourceB)]
Struct { x: f64, y: f64 },
}
§subenum
The subenum crate allows to implement easily subset of enums with conversion between parent and child.
However, there are cases where it is not desirable or possible to use subenum
.
For example:
- You don’t want to declare the child enum in the same module or crate as the parent enum.
- There already is a child enum coming from another crate and you want to convert from that child enum to your own parent enum.