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