async_iter_ext/result.rs
1/// An extension trait for `Result<T, E>` providing asynchronous combinators.
2pub trait AsyncResultTools<T, E> {
3 /// Asynchronously evaluates whether the result is `Ok` and satisfies a given predicate.
4 ///
5 /// If the result is `Ok`, the provided asynchronous predicate `f` is applied to the inner value.
6 /// Returns `true` if the predicate resolves to `true`, otherwise returns `false`.
7 /// If the result is `Err`, returns `false` without calling the predicate.
8 ///
9 /// # Example
10 ///
11 /// ```rust
12 /// use async_iter_ext::AsyncResultTools;
13 /// use async_std::task::block_on;
14 ///
15 /// async fn check_even(n: u32) -> bool {
16 /// n % 2 == 0
17 /// }
18 ///
19 /// let res: Result<u32, ()> = Ok(4);
20 /// assert!(block_on(async { res.is_ok_and_async(check_even).await }));
21 /// ```
22 #[allow(clippy::wrong_self_convention)]
23 fn is_ok_and_async<F, Fut>(self, f: F) -> impl Future<Output = bool>
24 where
25 F: FnOnce(T) -> Fut,
26 Fut: Future<Output = bool>;
27
28 /// Applies an asynchronous transformation to the `Ok` value, if present.
29 ///
30 /// If the result is `Ok`, the provided asynchronous function `f` is applied to the inner value,
31 /// and the result is wrapped in `Ok`. If the result is `Err`, it is returned unchanged.
32 ///
33 /// # Example
34 ///
35 /// ```rust
36 /// use async_iter_ext::AsyncResultTools;
37 /// use async_std::task::block_on;
38 ///
39 /// async fn double(x: u32) -> u32 {
40 /// x * 2
41 /// }
42 ///
43 /// let res: Result<u32, &str> = Ok(3);
44 /// let doubled = block_on(async { res.map_async(double).await });
45 /// assert_eq!(doubled, Ok(6));
46 /// ```
47 fn map_async<B, F, Fut>(self, f: F) -> impl Future<Output = Result<B, E>>
48 where
49 F: FnOnce(T) -> Fut,
50 Fut: Future<Output = B>;
51
52 /// Applies an asynchronous function to the contained `Ok` value, returning a new `Result`.
53 ///
54 /// Similar to `Result::and_then`, but with support for async functions.
55 fn and_then_async<B, F, Fut>(self, f: F) -> impl Future<Output = Result<B, E>>
56 where
57 F: FnOnce(T) -> Fut,
58 Fut: Future<Output = Result<B, E>>;
59
60 /// Applies an asynchronous function to the contained `Err` value, returning a new `Result`.
61 ///
62 /// Similar to `Result::map_err`, but with async support.
63 fn map_err_async<F, Fut, E2>(self, f: F) -> impl Future<Output = Result<T, E2>>
64 where
65 F: FnOnce(E) -> Fut,
66 Fut: Future<Output = E2>;
67
68 /// Applies an asynchronous fallback function if the result is an `Err`.
69 ///
70 /// Similar to `Result::or_else`, but async.
71 fn or_else_async<F, Fut>(self, f: F) -> impl Future<Output = Result<T, E>>
72 where
73 F: FnOnce(E) -> Fut,
74 Fut: Future<Output = Result<T, E>>;
75}
76
77impl<T, E> AsyncResultTools<T, E> for Result<T, E> {
78 async fn is_ok_and_async<F, Fut>(self, f: F) -> bool
79 where
80 F: FnOnce(T) -> Fut,
81 Fut: Future<Output = bool>,
82 {
83 if let Ok(x) = self { f(x).await } else { false }
84 }
85
86 async fn map_async<B, F, Fut>(self, f: F) -> Result<B, E>
87 where
88 F: FnOnce(T) -> Fut,
89 Fut: Future<Output = B>,
90 {
91 match self {
92 Ok(x) => Ok(f(x).await),
93 Err(e) => Err(e),
94 }
95 }
96
97 async fn and_then_async<B, F, Fut>(self, f: F) -> Result<B, E>
98 where
99 F: FnOnce(T) -> Fut,
100 Fut: Future<Output = Result<B, E>>,
101 {
102 match self {
103 Ok(x) => f(x).await,
104 Err(e) => Err(e),
105 }
106 }
107
108 async fn map_err_async<F, Fut, E2>(self, f: F) -> Result<T, E2>
109 where
110 F: FnOnce(E) -> Fut,
111 Fut: Future<Output = E2>,
112 {
113 match self {
114 Ok(x) => Ok(x),
115 Err(e) => Err(f(e).await),
116 }
117 }
118
119 async fn or_else_async<F, Fut>(self, f: F) -> Result<T, E>
120 where
121 F: FnOnce(E) -> Fut,
122 Fut: Future<Output = Result<T, E>>,
123 {
124 match self {
125 Ok(x) => Ok(x),
126 Err(e) => f(e).await,
127 }
128 }
129}