option-chain 0.1.2

A macro for using `?` operator in functions that don't return `Option`.
Documentation
  • Coverage
  • 100%
    2 out of 2 items documented1 out of 1 items with examples
  • Size
  • Source code size: 6.77 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 575.14 kB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 9s Average build duration of successful builds.
  • all releases: 8s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • PRO-2684/Candy-Pile
    3 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • PRO-2684

option-chain

A macro for using ? operator in functions that don't return Option.

Features

  • 🪶 Lightweight: Just a single macro_rules!, without any dependency - even the standard library!

Examples

use option_chain::opt;

struct Test1 {
    a: Option<Test2>,
}
struct Test2 {
    b: Option<Test3>,
}
struct Test3 {
    c: i32,
}

let v = Test1 {
    a: Some(Test2 { b: Some(Test3 { c: 42 }) }),
};
let c = opt!(v.a?.b?.c);
assert_eq!(c.unwrap(), 42);

Why?

Consider the following scenario:

struct Test1 {
    a: Option<Test2>,
}
struct Test2 {
    b: Option<Test3>,
}
struct Test3 {
    c: i32,
}

fn main() {
    let v = Test1 {
        a: Some(Test2 { b: Some(Test3 { c: 42 }) }),
    };
    // We want to get the value of the `c` field, returning `None` if any member in the "chain of fields" is `None`.
}

Essentially, we're looking for Rust-equivalent of the following JavaScript code:

const c = v?.a?.b?.c;

Usually you'd utilize the and_then and map methods:

# struct Test1 {
#     a: Option<Test2>,
# }
# struct Test2 {
#     b: Option<Test3>,
# }
# struct Test3 {
#     c: i32,
# }
#
# fn main() {
#     let v = Test1 {
#         a: Some(Test2 { b: Some(Test3 { c: 42 }) }),
#     };
let c = v.a.and_then(|a| a.b).map(|b| b.c);
assert_eq!(c.unwrap(), 42);
# }

Which looks quite verbose. flatten is also a good choice:

# struct Test1 {
#     a: Option<Test2>,
# }
# struct Test2 {
#     b: Option<Test3>,
# }
# struct Test3 {
#     c: i32,
# }
#
# fn main() {
#     let v = Test1 {
#         a: Some(Test2 { b: Some(Test3 { c: 42 }) }),
#     };
let c = v.a.map(|a| a.b).flatten().map(|b| b.c);
assert_eq!(c.unwrap(), 42);
# }

But it's still not as concise as the JavaScript code. Also, you might think of creating a helper function:

# struct Test1 {
#     a: Option<Test2>,
# }
# struct Test2 {
#     b: Option<Test3>,
# }
# struct Test3 {
#     c: i32,
# }
#
# fn main() {
#     let v = Test1 {
#         a: Some(Test2 { b: Some(Test3 { c: 42 }) }),
#     };
fn get_c(v: Test1) -> Option<i32> {
    Some(v.a?.b?.c)
}

let c = get_c(v);
assert_eq!(c.unwrap(), 42);
# }

Which is better, but you'll need to create a function for every different chain of fields you want to access.

This is where option-chain comes in:

# use option_chain::opt;
#
# struct Test1 {
#     a: Option<Test2>,
# }
# struct Test2 {
#     b: Option<Test3>,
# }
# struct Test3 {
#     c: i32,
# }
#
# fn main() {
#     let v = Test1 {
#         a: Some(Test2 { b: Some(Test3 { c: 42 }) }),
#     };
let c = opt!(v.a?.b?.c);
assert_eq!(c.unwrap(), 42);
# }

How?

It just wraps the expression in a closure which returns Option, and immediately calls it:

macro_rules! opt {
    ($e:expr) => {{ || -> Option<_> { Some($e) }() }};
}