#[enpow]
Expand description
The enpow
attribute attached to the target enum derives typical methods for working with
variants as known from Result<T, E>
and Option<T>
. It supports generics and variants of
every type, with named or unnamed fields or no fields attached. Variants with unnamed fields
get unwrapped into a tuple, while variants with named fields are transformed into an
automatically generated struct named after the enum and variant, i.e. EnumVariant
. The
functions and struct generated inherit the visibility modifier of the target enum.
In parethesis, the following arguments to enpow
can be used to specify which methods to
generate. Without any arguments, all methods will be generated. The method identifiers are
generated from the variant names turned into snake case.
Var
fn <variant>(self) -> Option<<inner>>
Returns the inner data, if the enum value is of the expected type, otherwise returnsNone
.
IsVar
fn is_<variant>(&self) -> bool
Returnstrue
, if the enum value is of the expected type, otherwise returnsfalse
.fn is_<variant>_and(&self, f: impl FnOnce(<ref_inner>) -> bool) -> bool
Returnstrue
, if the enum value is of the expected type and the given closure evalutates totrue
, otherwise returnsfalse
.
VarAsRef
fn <variant>_as_ref(&self) -> Option<<ref_inner>>
Returns a reference to the inner data, if the enum value is of the expected type, otherwise returnsNone
.fn <variant>_as_mut(&mut self) -> Option<<mut_inner>>
Returns a mutable reference to the inner data, if the enum value is of the expected type, otherwise returnsNone
.
MapVar
fn map_<variant>_or<T>(self, default: T, op: impl FnOnce(<inner>) -> T) -> T
Applies the given operation to the inner data and returns its result, if the enum value is of the expected type, otherwise returns the given default value.fn map_<variant>_or_else<T>(self, default: impl FnOnce(Self) -> T, op: impl FnOnce(<inner>) -> T) -> T
Applies the given operation to the inner data and returns its result, if the enum value is of the expected type, otherwise returns the value that the given default closure evaluates to.
UnwrapVar
fn unwrap_<variant>(self) -> <inner>
Returns the inner data, if the enum value is of the expected type, otherwise panics.fn unwrap_<variant>_or(self, default: <inner>) -> <inner>
Returns the inner data, if the enum value is of the expected type, otherwise returns the given default value.fn unwrap_<variant>_or_else(self, f: impl FnOnce(Self) -> <inner>) -> <inner>
Returns the inner data, if the enum value is of the expected type, otherwise returns the value that the given closure evaluated to.
UnwrapVar, VarAsRef
fn unwrap_<variant>_as_ref(self) -> <ref_inner>
Returns a reference to the inner data, if the enum value is of the expected type, otherwise panics.fn unwrap_<variant>_as_mut(self) -> <mut_inner>
Returns a mutable reference to the inner data, if the enum value is of the expected type, otherwise panics.
ExpectVar
fn expect_<variant>(self, msg: &str) -> <inner>
Returns the inner data, if the enum is of the expected type, otherwise panics with the given error message.
ExpectVar, VarAsRef
fn expect_<variant>_as_ref(self, msg: &str) -> <ref_inner>
Returns a reference to the inner data, if the enum is of the expected type, otherwise panics with the given error message.fn expect_<variant>_as_mut(self, msg: &str) -> <mut_inner>
Returns a mutable reference to the inner data, if the enum is of the expected type, otherwise panics with the given error message.
All
- Generates all methods mentioned.
This example will generate all methods.
#[enpow(All)]
#[inner(derive(Debug, PartialEq))]
#[derive(Debug, PartialEq)]
enum IpAddress {
None,
V4(u8, u8, u8, u8),
V6(String),
Multi {
v4: (u8, u8, u8, u8),
v6: String,
},
}
// fn <variant>()
assert_eq!(IpAddress::V4(192, 168, 0, 1).v4(), Some((192, 168, 0, 1)));
assert_eq!(IpAddress::V6("::1".into()).v6(), Some("::1".into()));
assert_eq!(IpAddress::None.multi(), None);
// fn is_<variant>()
assert_eq!(IpAddress::None.is_none(), true);
assert_eq!(IpAddress::V6("::1".into()).is_v4(), false);
// fn is_<variant>_and()
assert_eq!(IpAddress::V4(192, 168, 0, 1).is_v4_and(|ip| *ip.0 == 192), true);
assert_eq!(IpAddress::V6("::1".into()).is_v6_and(|ip| *ip == "::"), false);
assert_eq!(IpAddress::None.is_v4_and(|_| true), false);
// fn <variant>_as_ref()
assert_eq!(IpAddress::V4(192, 168, 0, 1).v4_as_ref(), Some((&192, &168, &0, &1)));
assert_eq!(
IpAddress::Multi { v4: (0, 0, 0, 0), v6: "::".into() }.multi_as_ref(),
Some(IpAddressMultiRef { v4: &(0, 0, 0, 0), v6: &"::".into() })
);
assert_eq!(IpAddress::V6("::1".into()).none_as_ref(), None);
// fn <variant>_as_mut()
let mut ip = IpAddress::V4(192, 168, 0, 1);
if let Some(v4) = ip.v4_as_mut() {
*v4.3 = 2;
}
assert_eq!(ip, IpAddress::V4(192, 168, 0, 2));
// fn map_<variant>_or()
assert_eq!(
IpAddress::V4(192, 168, 0, 1).map_v4_or((0, 0, 0, 0), |mut v4| { v4.3 = 2; v4 }),
(192, 168, 0, 2)
);
assert_eq!(
IpAddress::None.map_v6_or("::".into(), |v6| v6),
"::".to_owned()
);
// fn map_<variant>_or_else()
assert_eq!(
IpAddress::V6("::".into()).map_v6_or_else(|_| unreachable!(), |v6| v6 + "1"),
"::1".to_owned()
);
assert_eq!(
IpAddress::None.map_v4_or_else(|_| (0, 0, 0, 0), |_| unreachable!()),
(0, 0, 0, 0)
);
// fn unwrap_<variant>()
assert_eq!(IpAddress::V6("::1".into()).unwrap_v6(), "::1".to_owned());
// fn unwrap_<variant>_as_ref()
assert_eq!(IpAddress::V4(192, 168, 0, 1).unwrap_v4_as_ref(), (&192, &168, &0, &1));
// fn unwrap_<variant>_as_mut()
let mut ip = IpAddress::V4(192, 168, 0, 1);
*ip.unwrap_v4_as_mut().3 = 2;
assert_eq!(ip, IpAddress::V4(192, 168, 0, 2));
// fn unwrap_<variant>_or()
assert_eq!(IpAddress::V6("::1".into()).unwrap_v6_or("::".into()), "::1".to_owned());
assert_eq!(IpAddress::V4(192, 168, 0, 2).unwrap_v6_or("::".into()), "::".to_owned());
// fn unwrap_<variant>_or_else()
assert_eq!(IpAddress::None.unwrap_v4_or_else(|_| (0, 0, 0, 0)), (0, 0, 0, 0));
assert_eq!(
IpAddress::V6("::1".into()).unwrap_v6_or_else(|_| unreachable!()),
"::1".to_owned()
);
// fn expect_<variant>()
assert_eq!(IpAddress::V4(192, 168, 0, 1).expect_v4("Expected V4"), (192, 168, 0, 1));
// fn unwrap_<variant>_as_ref()
assert_eq!(
IpAddress::V6("::1".into()).expect_v6_as_ref("Unexpected variant"),
&"::1".to_owned()
);
// fn unwrap_<variant>_as_mut()
let mut ip = IpAddress::V6("::".into());
ip.expect_v6_as_mut("Expected V6").push('1');
assert_eq!(ip, IpAddress::V6("::1".into()));
This example will generate methods of the category Var
and IsVar
.
#[enpow(Var, IsVar)]
#[inner(derive(Debug, PartialEq))]
#[derive(Debug, PartialEq)]
enum IpAddress {
None,
V4(u8, u8, u8, u8),
V6(String),
Multi {
v4: (u8, u8, u8, u8),
v6: String,
},
}
// fn <variant>()
assert_eq!(IpAddress::V4(192, 168, 0, 1).v4(), Some((192, 168, 0, 1)));
assert_eq!(IpAddress::None.multi(), None);
// fn is_<variant>()
assert_eq!(IpAddress::None.is_none(), true);
assert_eq!(IpAddress::V6("::1".into()).is_v4(), false);
// fn is_<variant>_and()
assert_eq!(IpAddress::V4(192, 168, 0, 1).is_v4_and(|ip| *ip.0 == 192), true);
assert_eq!(IpAddress::V6("::1".into()).is_v6_and(|ip| *ip == "::"), false);
assert_eq!(IpAddress::None.is_v4_and(|_| true), false);
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() }
);
Method Names
With the argument method_name
, the standard way of naming the generated structs can be changed. The usage is method_name="my_new_name"
. The given name will be used instead of the variant’s name turned into snake_case. Note, that this argument can only be applied to variants directly, not to the enum itself.
#[extract(All)]
#[enpow(UnwrapVar)]
#[inner(type_names="Ip{var}", derive(Debug, PartialEq))]
#[derive(Debug, PartialEq)]
enum IpAddress {
None,
#[inner(method_name="ipv4")]
V4(u8, u8, u8, u8),
#[inner(method_name="ipv6")]
V6(String),
Multi {
v4: (u8, u8, u8, u8),
v6: String,
},
}
assert_eq!(IpAddress::from(IpV4(192, 168, 0, 1)).unwrap_ipv4(), IpV4(192, 168, 0, 1));
assert_eq!(IpAddress::from(IpV6("::1".into())).unwrap_ipv6(), IpV6("::1".into()));