1#![doc = include_str!("../README.md")]
2#![doc(
3 html_favicon_url = "https://raw.githubusercontent.com/PRO-2684/Candy-Pile/refs/heads/main/option-chain/logo.svg"
4)]
5#![doc(
6 html_logo_url = "https://raw.githubusercontent.com/PRO-2684/Candy-Pile/refs/heads/main/option-chain/logo.svg"
7)]
8#![no_std]
9#![deny(missing_docs)]
10#![warn(clippy::all, clippy::nursery, clippy::pedantic, clippy::cargo)]
11
12#[macro_export]
16macro_rules! opt {
17 ($e:expr) => {{ || -> ::core::option::Option<_> { ::core::option::Option::Some($e) }() }};
18}
19
20#[cfg(test)]
21mod tests {
22 use super::*;
23
24 #[test]
25 fn test_macro_named() {
26 #[derive(Clone, Copy)]
27 struct Test1 {
28 a: Option<Test2>,
29 }
30 #[derive(Clone, Copy)]
31 struct Test2 {
32 b: Option<Test3>,
33 }
34 #[derive(Clone, Copy)]
35 struct Test3 {
36 c: i32,
37 }
38
39 let mut v = Test1 { a: None };
40 let v1 = opt!(v.a?.b?.c);
41 assert!(v1.is_none());
42
43 v.a.replace(Test2 { b: None });
44 let v2 = opt!(v.a?.b?.c);
45 assert!(v2.is_none());
46
47 v.a.as_mut().unwrap().b.replace(Test3 { c: 42 });
48 let v3 = opt!(v.a?.b?.c);
49 assert_eq!(v3.unwrap(), 42);
50 }
51
52 #[test]
53 fn test_macro_unnamed() {
54 struct Test1(Option<Test2>);
55 struct Test2(Option<Test3>);
56 struct Test3(i32);
57
58 let v1 = Test1(None);
59 let v1 = opt!(v1.0?.0?.0);
60 assert!(v1.is_none());
61
62 let v2 = Test1(Some(Test2(None)));
63 let v2 = opt!(v2.0?.0?.0);
64 assert!(v2.is_none());
65
66 let v3 = Test1(Some(Test2(Some(Test3(42)))));
67 let v3 = opt!(v3.0?.0?.0);
68 assert_eq!(v3.unwrap(), 42);
69 }
70
71 #[test]
72 fn test_macro_mixed() {
73 struct Test1 {
74 a: Option<Test2>,
75 }
76 struct Test2(Option<Test3>);
77 struct Test3(i32);
78
79 let v1 = Test1 { a: None };
80 let v1 = opt!(v1.a?.0?.0);
81 assert!(v1.is_none());
82
83 let v2 = Test1 {
84 a: Some(Test2(None)),
85 };
86 let v2 = opt!(v2.a?.0?.0);
87 assert!(v2.is_none());
88
89 let v3 = Test1 {
90 a: Some(Test2(Some(Test3(42)))),
91 };
92 let v3 = opt!(v3.a?.0?.0);
93 assert_eq!(v3.unwrap(), 42);
94 }
95}