[−][src]Crate 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); // boolean helper function for determining variant: assert!(color.is_hsv()); assert!(!color.is_rgb()); // Get inner values: let (h, s, v) = color.unwrap_hsv(); assert_eq!((h, s, v), (123, 45, 67)); // Single values don't require tuple destructuring: let color = Color::Grey(128); let value = color.unwrap_grey(); assert_eq!(value, 128); // Alter inner value, only if hsv: 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)); // Safely unwrap with a fallback: 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)); // Since color is of the HSV variant, the default is not used. // Safely unwrap using the fallback let color = Color::FromOutOfSpace; let (r, g, b) = color.unwrap_or_rgb((0, 0, 0)); assert_eq!((r, g, b), (0, 0, 0)); // Convert into an Option let color = Color::RGB(0, 255, 255); let optional_rgb = color.ok_rgb(); assert_eq!(Some((0, 255, 255)), optional_rgb); // Convert into a Result 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); // Operations like this can also use their familiar `_else` versions: let color = Color::FromOutOfSpace; let result_rgb = color.ok_or_else_rgb(|| Some("This is a computationally expensive error!")); assert!(result_rgb.is_err()); // The `#[variantly(rename = "darkness")]` attribute renames associated functions: 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.
Derive Macros
Variantly | The |