#chain #macro #options #no-std

no-std option-chain

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

3 releases

Uses new Rust 2024

new 0.1.2 Mar 28, 2025
0.1.1 Mar 25, 2025
0.1.0 Mar 22, 2025

#240 in Procedural macros

Download history 75/week @ 2025-03-16 231/week @ 2025-03-23

306 downloads per month

MIT license

8KB
78 lines

Logo

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) }() }};
}

No runtime deps