# Crate variant

Expand description

The `try_variant` macro matches an expression against a given pattern returning a `Result`. If the pattern matches, then the `Ok` branch is returned including any assignments from the pattern (or `unit` if none are given). If the match fails then `Err` is returned with either a given error, or a default `Box<dyn std::error::Error>` otherwise.

The `get_variant` macro works in exactly the same way, except it returns `Some` if the pattern matches and `None`, otherwise.

Finally, the `variant` macro also works the same way, but panics if the pattern does not match.

### Simple Example

``````use variant::{get_variant, try_variant, variant};

let val = Some((0, 1));
let res = try_variant!(val, Some((i, _))).expect("i");
assert_eq!(res, 0);

let res = try_variant!(val, Some((10, j)));
assert!(res.is_err());

let opt = get_variant!(val, Some((i, _)));
assert_eq!(opt, Some(0));

let opt = get_variant!(val, Some((10, j)));
assert_eq!(opt, None);

// Using just variant
let var = variant!(val, Some((i, _)));
assert_eq!(var, 0);

// calling `variant!(val, Some((10, j)))` will panic.``````

### Guards

Conditional guards work the same as with `matches!`.

``````use variant::try_variant;

struct Foo {
a: usize,
b: Option<bool>,
}

let val = Foo { a: 20, b: None };
let res = try_variant!(val, Foo { a, .. } if a == 20).expect("a");
assert_eq!(res, 20);

let res = try_variant!(val, Foo { b, .. } if b.is_some());
assert!(res.is_err());``````

### Multiple Assignments

When there is more than one assignment within a matching pattern all assignments are returned in a tuple. Since assignments in a pattern may not be ordered linearly, multiple assignments will be returned in lexicographic order.

``````use variant::try_variant;

let val = (Some(10), Some(true));
let (a, b) = try_variant!(val, (Some(b), Some(a))).expect("tuple");
assert_eq!((a, b), (true, 10));``````

### Custom Errors

``````use variant::try_variant;

#[derive(Debug)]
enum MyError {
Worse,
Expensive,
}

let val = Some(1);
let res = try_variant!(val, Some(i), MyError::Bad).expect("i");
assert_eq!(res, 1);

let res = try_variant!(val, Some(50), MyError::Worse);
assert!(matches!(res, Err(MyError::Worse)));

// We can also use an error returning closure with the following syntax
let err_closure = || MyError::Expensive;
let res = try_variant!(val, Some(50), else err_closure);
assert!(matches!(res, Err(MyError::Expensive)));

// Doesn't have to be a closure, any callable taking no parameters will do
fn make_err() -> MyError { MyError::Expensive }
let res = try_variant!(val, Some(50), else make_err);
assert!(matches!(res, Err(MyError::Expensive)));``````

### Or Patterns

None of the macros support `Or` patterns at any level. This is because there is no simple expected way to signal to the user what values are returned in the case where only some assignments may match. If a pragmatic solution to this problem is found then adding this feature in the future may be possible.