Derive Macro enum_to_enum::FromEnum [−][src]
#[derive(FromEnum)]
{
// Attributes available to this derive:
#[from_enum]
#[from_case]
}
Expand description
You can add #[derive(FromEnum)]
to any enum to generate a possibly effectful From
implementation to convert from other source enums to the annotated destination enum.
from_enum
- You must annotate the destination enum with
#[from_enum(SrcEnum1, SrcEnum2, ...)]
. - You may include
effect_container = YourEffectContainer
, like this:#[from_enum(SrcEnum1, effect_container = YourEffectContainer)]
. Ifeffect_container
is specified, the conversion will beFrom<SrcEnum1> for YourEffectContainer<Value = DestEnum>
.YourEffectContainer
must implementenum_to_enum::WithEffects
. Ifeffect_container
is not specified, the conversion will beFrom<SrcEnum1> for DestEnum
.
from_case
- You may also annotate any variant of the destination enum with
#[from_case(SomeCase)]
to convert fromSomeCase
on all source enums to the annotated variant. - You may annotate
#[from_case(DefaultCase, source_enum_1 = SourceEnum1Case)]
to convert fromSourceEnum1Case
ofsource_enum_1
to the annotated case and fromDefaultCase
of all other source enums to the annotated case. - Without any
from_case
annotation, the we default to converting from same-named variants.
Examples
1-to-1 conversion
1-to-1 conversion from source to destination enum variants, demonstrating recursive, field-level conversions and from_case usage.
use enum_to_enum::FromEnum;
#[derive(Debug)]
enum Src {
Case1(),
Case2(SrcStrField),
Case3 { a: SrcStrField, b: u8 },
}
#[derive(FromEnum, Debug, PartialEq, Eq)]
#[from_enum(Src)]
enum Dest {
Case1(),
#[from_case(Case2)]
DestCase2(DestStrField),
#[from_case(Src = Case3)]
DestCase3 { a: DestStrField, b: u8 },
}
#[derive(Debug, PartialEq, Eq)]
struct SrcStrField(String);
#[derive(Debug, PartialEq, Eq)]
struct DestStrField(String);
impl From<SrcStrField> for DestStrField {
fn from(src: SrcStrField) -> DestStrField {
DestStrField(src.0 + " world")
}
}
assert_eq!(
Dest::from(Src::Case1()),
Dest::Case1(),
);
assert_eq!(
Dest::from(Src::Case2(SrcStrField(String::from("hello")))),
Dest::DestCase2(DestStrField(String::from("hello world"))),
);
assert_eq!(
Dest::from(Src::Case3 {
a: SrcStrField(String::from("hello")),
b: 100u8,
}),
Dest::DestCase3 {
a: DestStrField(String::from("hello world")),
b: 100u8,
},
);
Many-to-one conversion
Many-to-one conversion, demonstrating mapping from many source variants to a single destination variant, using whichever source variant’s try_into succeeds.
use enum_to_enum::FromEnum;
use std::convert::TryFrom;
#[derive(Debug)]
enum Src {
Case1(SrcField),
Case2(SrcField),
}
#[derive(FromEnum, Debug, PartialEq, Eq)]
#[from_enum(Src)]
enum Dest {
#[from_case(Case1, Case2)]
Big(BigDestField),
#[from_case(Case1, Case2)]
Small(SmallDestField),
}
#[derive(Debug, PartialEq, Eq, Clone)]
struct SrcField(u32);
#[derive(Debug, PartialEq, Eq)]
struct BigDestField(u32);
#[derive(Debug, PartialEq, Eq)]
struct SmallDestField(u32);
impl TryFrom<SrcField> for SmallDestField {
type Error = &'static str;
fn try_from(src: SrcField) -> Result<SmallDestField, Self::Error> {
if src.0 < 100 {
Ok(SmallDestField(src.0 - 1))
} else {
Err("too big")
}
}
}
impl TryFrom<SrcField> for BigDestField {
type Error = &'static str;
fn try_from(src: SrcField) -> Result<BigDestField, Self::Error> {
if src.0 >= 100 {
Ok(BigDestField(src.0 + 1))
} else {
Err("too small")
}
}
}
assert_eq!(
Dest::from(Src::Case1(SrcField(10))),
Dest::Small(SmallDestField(9)),
);
Effectful conversion
Effectful conversion, demonstrating an effect_container and effect combination.
use enum_to_enum::{FromEnum, WithEffects};
#[derive(Debug)]
enum Src {
Case1(SrcField),
Case2(SrcField, SrcField),
}
#[derive(FromEnum, Debug, PartialEq, Eq)]
#[from_enum(Src, effect_container = EffectContainer)]
enum Dest {
Case1(DestField),
Case2(DestField, DestField),
}
#[derive(Debug, PartialEq, Eq, Clone)]
struct SrcField(String);
#[derive(Debug, PartialEq, Eq)]
struct DestField(String);
#[derive(Debug, PartialEq, Eq)]
enum Eff {
Log(String),
}
#[derive(Debug, PartialEq, Eq)]
struct EffectContainer<Value> {
value: Value,
effects: Vec<Eff>,
}
impl<Value> WithEffects for EffectContainer<Value> {
type Value = Value;
type Effect = Eff;
fn new(value: Self::Value, effects: Vec<Self::Effect>) -> Self {
Self { value, effects }
}
fn into_value_and_effects(self) -> (Self::Value, Box<dyn Iterator<Item = Self::Effect>>) {
(self.value, Box::new(self.effects.into_iter()))
}
}
impl From<SrcField> for EffectContainer<DestField> {
fn from(src: SrcField) -> EffectContainer<DestField> {
let log = Eff::Log(format!("Log: {}", &src.0));
EffectContainer {
value: DestField(src.0),
effects: vec![log],
}
}
}
assert_eq!(
EffectContainer::from(Src::Case1(SrcField(String::from("hello")))),
EffectContainer {
value: Dest::Case1(DestField(String::from("hello"))),
effects: vec![Eff::Log(String::from("Log: hello"))],
},
);
assert_eq!(
EffectContainer::from(Src::Case2(SrcField(String::from("hi")), SrcField(String::from("bye")))),
EffectContainer {
value: Dest::Case2(DestField(String::from("hi")), DestField(String::from("bye"))),
effects: vec![
Eff::Log(String::from("Log: hi")),
Eff::Log(String::from("Log: bye")),
],
},
);