Variantly
Derive associated functions for enum variants that are familiar from std::option::Option
& std::result::Result
such as unwrap_or
or and_then
.
Example
#[derive(Variantly)]
enum Color {
RGB(u8, u8, u8),
HSV(u8, u8, u8),
Grey(u8),
FromOutOfSpace,
#[variantly(rename = "darkness")]
Black,
}
fn example() {
let color = Color::HSV(123, 45, 67);
assert!(color.is_hsv());
assert!(!color.is_rgb());
let (h, s, v) = color.unwrap_hsv();
assert_eq!((h, s, v), (123, 45, 67));
let color = Color::Grey(128);
let value = color.unwrap_grey();
assert_eq!(value, 128);
let color = Color::HSV(111, 22, 33);
let color = color.and_then_hsv(|(h, s, _)| (h, s, 100));
assert_eq!(color.unwrap_hsv(), (111, 22, 100));
let color = Color::RGB(255, 255, 0);
let (r, g, b) = color.unwrap_or_rgb((0, 0, 0));
assert_eq!((r, g, b), (255, 255, 0));
let color = Color::FromOutOfSpace;
let (r, g, b) = color.unwrap_or_rgb((0, 0, 0));
assert_eq!((r, g, b), (0, 0, 0));
let color = Color::RGB(0, 255, 255);
let optional_rgb = color.ok_rgb();
assert_eq!(Some((0, 255, 255)), optional_rgb);
let color = Color::RGB(255, 0, 255);
let result_rgb = color.ok_or_rgb("Error: This is not an RGB variant!");
assert_eq!(Ok((255, 0, 255)), result_rgb);
let color = Color::FromOutOfSpace;
let result_rgb = color.ok_or_else_rgb(|| Some("This is a computationally expensive error!"));
assert!(result_rgb.is_err());
let color = Color::Black;
assert!(color.is_darkness())
}
Derived functions
The following are supported function types that are derived for all enum variants:
is
is_not
The following are supported function types that are derived for tuple-like structs. This includes structs that hold one or many tuple style values.
and
and_then
expect
ok
ok_or
ok_or_else
or
unwrap
unwrap_or
unwrap_or_else
Derived function naming
Derived functions are named by parsing and combining the enum variant they correspond with and the name of the operation they perform.
Simplified, this looks like:
use inflector::cases::snakecase::to_snake_case;
fn name_fn(operation: String, variant_name: String) -> String {
let snake_case_variant = to_snake_case(&variant_name);
format!("{}_{}", snake_case_variant, operation)
}
#[test]
fn it_makes_a_name() {
assert_eq!(
name_fn("unwrap","VariantA"),
"unwrap_variant_a".into()
)
}
Renaming associated functions
The varianty
attribute may be placed on a variant in order to customize the resulting associated function names.
#[derive(Variantly)]
enum SomeEnum {
#[variantly(rename = "variant_a")]
SomeVariantWithALongName(String),
VariantB,
}
Functions associated with SomeVariantWithALongName
will now be accessible only with the variant_a
suffix, such as .unwrap_or_else_variant_a()
. This can help control overly verbose fn names.
Note that the input to rename
is used as is and is not coerced into snake_case.
The above is also relevant when two variant names would expand to create conflicting function names:
#[derive(Variantly)]
enum SomeEnum {
#[variantly(rename = "capital")]
ABC,
#[variantly(rename = "lower")]
abc,
}
Without the rename
attribute in the above, both variants would create conflicting functions such as .is_abc()
due to the coercion to snake_case.
This is avoided by using the rename input to create meaningful and unique fn names.
License