Skip to main content

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}