option

Macro option 

Source
option!() { /* proc-macro */ }
Expand description

a macro for making debugging more ergonomic when handling Option<T> results

§Anotomy of the option! macro

The option! macro consists of a @when section and one to three optional evaluation sections @some, @debug and/or @none, at least one must be defined.

When the option! macro is used in place of an expression and the intention is to assign the Some(T) value, the @when section can be skipped and replaced with a simplified @some section, which behaves as the @when section, * see below for more details


* code block <expr>s, can not be terminated with a ;, i.e. { ... };

§@when

The @when section is defined as [@when] <expr>[?][;]

  • @when - optional, section identifier
  • <expr> - an expression that must evaluate to an Option<T> value
  • [?] - optional, try operator, returns None after completing @debug and/or @none
  • [;] - optional, section terminator

Example A: @when foo();
Example B: @when foo()?;

§@some

The @some section is defined as @some <[[(identifier) =>]<message|expr>[;]|[<expr>[?][;]]]

  • @some - required section identifier
  • In Success Mode
    • [(identifier) =>] - optional, custom defined identifier which maps to the Some(T) value
    • <message|expr>
      • message - outputs to stdout with a println! statement, therefore has the same args
      • expr - any expression to evaluate

        * can access Some(T) value with the some keyword or custom identifier

    • [;] - optional, section terminator

      * only evaluates if the result of the @when expression is Option::Some

      Example A: @some "success: {}", some;
      Example B: @some (foo) => "success: {}", foo;
      Example C: @some (foo) => { success(foo); }
  • In Expression Mode
    • <expr> - an expression that must evaluate to an Option<T> value
    • [?] - optional, try operator, returns None after completing @debug and/or @none
    • [;] - optional, section terminator

      Example A: @some foo();
      Example B: @some foo()?;

§@debug

The @debug section is defined as @debug <message>[;]

* only evaluates if the result of the @when expression is Option::None

  • @debug - required section identifier
  • message - outputs to stdout with a println! statement, therefore has the same args
  • [;] - optional, section terminator

Example: @debug "dbg: foo failed!";

§@none

The @none section is defined as @none [<message>[;]][<expr>][;], must provide at least a message and/or expr

* only evaluates if the result of the @when expression is Option::None

  • @none - required section identifier
  • [message][;] - optional, outputs to_ stderr with a eprintln! statement, therefore accepts the same args

    * requires the ; terminator if an <expr>[;] is also defined

  • [<expr>] - optional, any expression to evaluate
  • [;] - optional, section terminator

Example A: @none { on_fail_baz(); }
Example B: @none "err: foo failed!"
Example C: @none "err: foo failed!"; { on_fail_baz(); }

§Example

  • Success Mode
use macrofied_toolbox::option;

fn main() {
    let file_name = "foo.txt";

    if let None = example(file_name) {
        eprintln!("failed to create {:?} file!", file_name);
        exit(-1);
    }
}

fn example(file_name: &str) -> Option<()> {
    option! {
        @when  File::create(file_name).ok()?;
        @some  (file) => {
                   let mut out = BufWriter::new(file);

                   writeln!(out, "some content").ok()?;
                   writeln!(out, "some more content").ok()?;
               }
        @debug "problem creating file: {:?}", file_name;
        @none  "{:?} failed; attempting recovery ...", file_name;
               recovery_from_fail(file_name);
    }

    Some(())
}

fn recovery_from_fail(_: &str) {
    // some very import recovery logic
}
  • Expression Mode
use macrofied_toolbox::option;

let result = option! {
    @some  computed_value(21)
    @debug "Invalid input"
    @none  0
};

assert_eq!(42, result);

fn computed_value(input: usize) -> Option<usize> {
    if input == 21 {
        Some(input * 2)
    } else {
        None
    }
}