#[extract]
Expand description
The extract
attribute attached to an enum turns each variant into a separate struct that then
becomes the only field of the variant. It supports generics and variants of every type, with
named or unnamed fields or no fields attached. Variants without data are turned into unit
structs, variants with unnamed fields get turned into tuple structs, and variants with named
fields are transformed into structs, each named after the enum and variant, i.e.
EnumVariant
. The structs generated inherit the visibility modifier of the target enum.
Additionally, doc comments attached to the variants and variant fields are inherited by the
generated structs. The macro also automatically implements the From
trait for every extracted
type to convert it into its corresponding enum variant.
In parethesis, the following arguments to extract
can be used to specify which variant types
to extract. Without any arguments, all variants will be extracted.
Unit
: Extracts variants without data into unit structs.Single
: Extracts variants with a single unnamed field into tuple structs.Unnamed
: Extracts variants with multiple unnamed fields into tuple structs.Named
: Extracts variants with named fields into structs.All
: Extracts all variants into structs.
This example will extract all variants.
#[extract(All)]
enum IpAddress {
None,
V4(u8, u8, u8, u8),
V6(String),
Multi {
v4: (u8, u8, u8, u8),
v6: String,
},
}
// Using the modified enum variants and its generated structs
IpAddress::None(IpAddressNone);
IpAddress::V4(IpAddressV4(192, 168, 0, 1));
IpAddress::V6(IpAddressV6("::1".into()));
IpAddress::Multi(IpAddressMulti { v4: (192, 168, 0, 1), v6: "::1".into() });
This example will extract all variants with multiple unnamed fields or named fields into separate structs.
#[extract(Unnamed, Named)]
enum IpAddress {
None,
V4(u8, u8, u8, u8),
V6(String),
Multi {
v4: (u8, u8, u8, u8),
v6: String,
},
}
// Using the unmodified enum variants
IpAddress::None;
IpAddress::V6("::1".into());
// Using the modified enum variants and its generated structs
IpAddress::V4(IpAddressV4(192, 168, 0, 1));
IpAddress::Multi(IpAddressMulti { v4: (192, 168, 0, 1), v6: "::1".into() });
An additional derive
macro attached to the enum should come after extract
to make sure the automatically derived implementations match the changed enum structure.
Configuration
The helper attribute inner
is used to configure the main macros expand
and enpow
. For this, inner
can be attached to both the enum itself and to individual variants. However, it has to be placed after each main macro it should be effective for. An inner
macro placed after multiple main macros will be effective for each one of them.
Derives
The argument derive()
enables to add auto trait derives to the automatically generated types. The position of the attribute decides on whether the given traits are implemented for all variant types or just for the selected ones.
ℹ️
Ref
structs always automatically deriveClone
andCopy
, whileMut
structs are prohibited from deriving these traits. This exclusion will be handled automatically by the macro.
#[extract(Unit, Single, Unnamed)]
#[enpow(UnwrapVar, VarAsRef)]
#[inner(derive(Debug, PartialEq))]
enum IpAddress {
None,
V4(u8, u8, u8, u8),
V6(String),
#[inner(derive(Clone))]
Multi {
v4: (u8, u8, u8, u8),
v6: String,
},
}
// Using PartialEq, Debug, and Clone derive
assert_eq!(
IpAddress::Multi { v4: (0, 0, 0, 0), v6: "::".into() }.unwrap_multi(),
IpAddressMulti { v4: (0, 0, 0, 0), v6: "::".into() }.clone()
);
// Using automatic Copy derive on Ref struct
let ip = IpAddress::Multi { v4: (0, 0, 0, 0), v6: "::".into() };
let copy = ip.unwrap_multi_as_ref();
let another_copy = copy;
assert_eq!(copy, IpAddressMultiRef { v4: &(0, 0, 0, 0), v6: &"::".into() });
assert_eq!(another_copy, IpAddressMultiRef { v4: &(0, 0, 0, 0), v6: &"::".into() });
Type Names
With the argument type_name
or type_names
, the standard way of naming the generated structs can be changed. There are multiple naming schemes possible, depending on the keyword or string literal provided:
type_name=EnumVar
[default] will give each type the name of the enum followed by the name of the corresponding variant, e.g.IpAddressMulti
type_name=Var
will let each type be named just like its corresponding variant, e.g.Multi
type_name=VarEnum
will give each type the name of the corresponding variant followed by the name of the enum, e.g.MultiIpAddress
type_name="My{enum}Var{var}"
will give each type the specified name with occurences of{enum}
and{var}
replaced by the name of the enum and the name of the corresponding variant, e.g.MyIpAddressMulti
This example generates the types IpNone
, IpV4
, IpV6
, and IpV4_6
.
#[extract(All)]
#[enpow(UnwrapVar)]
#[inner(type_names="Ip{var}", derive(Debug, PartialEq))]
#[derive(Debug, PartialEq)]
enum IpAddress {
None,
V4(u8, u8, u8, u8),
V6(String),
#[inner(type_name="IpV4_6")]
Multi {
v4: (u8, u8, u8, u8),
v6: String,
},
}
assert_eq!(IpAddress::from(IpNone).unwrap_none(), IpNone);
assert_eq!(IpAddress::from(IpV4(192, 168, 0, 1)).unwrap_v4(), IpV4(192, 168, 0, 1));
assert_eq!(IpAddress::from(IpV6("::1".into())).unwrap_v6(), IpV6("::1".into()));
assert_eq!(
IpAddress::from(IpV4_6 { v4: (0, 0, 0, 0), v6: "::1".into() }).unwrap_multi(),
IpV4_6 { v4: (0, 0, 0, 0), v6: "::1".into() }
);