overture_core/options.rs
1/// Free `map` on Option for function composition.
2/// Equivalent to Swift's map<A, B>(_ transform: @escaping (A) -> B) -> (A?) -> B?
3///
4/// # Examples
5/// ```
6/// use overture_core::options::map;
7///
8/// let double = map(|x: i32| x * 2);
9/// assert_eq!(double(Some(5)), Some(10));
10/// assert_eq!(double(None), None);
11/// ```
12pub fn map<A, B>(transform: impl Fn(A) -> B + Clone + 'static) -> impl Fn(Option<A>) -> Option<B> {
13 move |opt| opt.map(transform.clone())
14}
15
16/// Free `map` on Option for throwing function composition.
17/// Equivalent to Swift's map<A, B>(_ transform: @escaping (A) throws -> B) -> (A?) throws -> B?
18///
19/// # Examples
20/// ```
21/// use overture_core::options::map_throwing;
22///
23/// let safe_divide = map_throwing(|x: i32| {
24/// if x == 0 { Err("Division by zero") } else { Ok(10 / x) }
25/// });
26/// assert_eq!(safe_divide(Some(2)), Ok(Some(5)));
27/// assert_eq!(safe_divide(Some(0)), Err("Division by zero"));
28/// assert_eq!(safe_divide(None), Ok(None));
29/// ```
30pub fn map_throwing<A, B, E>(
31 transform: impl Fn(A) -> Result<B, E> + Clone + 'static,
32) -> impl Fn(Option<A>) -> Result<Option<B>, E> {
33 move |opt| match opt {
34 Some(a) => transform.clone()(a).map(Some),
35 None => Ok(None),
36 }
37}
38
39/// Free `map` on Option for function composition with fallible transform.
40/// Legacy alias for map_throwing.
41#[doc(hidden)]
42pub fn map_try<A, B, E>(
43 transform: impl Fn(A) -> Result<B, E> + Clone + 'static,
44) -> impl Fn(Option<A>) -> Result<Option<B>, E> {
45 map_throwing(transform)
46}
47
48/// Transforms a pair of options into an option pair.
49/// Equivalent to Swift's zip<A, B>(_ optional1: A?, _ optional2: B?) -> (A, B)?
50///
51/// # Examples
52/// ```
53/// use overture_core::options::zip;
54///
55/// assert_eq!(zip(Some(1), Some(2)), Some((1, 2)));
56/// assert_eq!(zip(Some(1), None), None);
57/// assert_eq!(zip(None, Some(2)), None);
58/// assert_eq!(zip(None, None), None);
59/// ```
60pub fn zip<A, B>(opt1: Option<A>, opt2: Option<B>) -> Option<(A, B)> {
61 match (opt1, opt2) {
62 (Some(a), Some(b)) => Some((a, b)),
63 _ => None,
64 }
65}
66
67/// Transforms a pair of options into a new optional value using a transform function.
68/// Equivalent to Swift's zip<A, B, Z>(with transform: (A, B) -> Z, _ optional1: A?, _ optional2: B?) -> Z?
69///
70/// # Examples
71/// ```
72/// use overture_core::options::zip_with;
73///
74/// let add = |a: i32, b: i32| a + b;
75/// assert_eq!(zip_with(add, Some(1), Some(2)), Some(3));
76/// assert_eq!(zip_with(add, Some(1), None), None);
77/// assert_eq!(zip_with(add, None, Some(2)), None);
78/// ```
79pub fn zip_with<A, B, Z>(
80 transform: impl Fn(A, B) -> Z + Clone + 'static,
81 opt1: Option<A>,
82 opt2: Option<B>,
83) -> Option<Z> {
84 zip(opt1, opt2).map(|(a, b)| transform(a, b))
85}
86
87#[macro_export]
88macro_rules! map_macro {
89 ($f:expr) => {
90 rust_overture::options::map($f)
91 };
92}
93
94#[macro_export]
95macro_rules! map_try_macro {
96 ($f:expr) => {
97 rust_overture::options::map_try($f)
98 };
99}
100
101#[macro_export]
102macro_rules! zip_macro {
103 ($a:expr, $b:expr) => {
104 rust_overture::options::zip($a, $b)
105 };
106}
107
108#[macro_export]
109macro_rules! zip_with_macro {
110 ($f:expr, $a:expr, $b:expr) => {
111 rust_overture::options::zip_with($f, $a, $b)
112 };
113}