pub trait ResultExt<T, E> {
fn map_err_into<U: From<E>>(self) -> Result<T, U>;
fn or_else_ok<F>(self, f: F) -> Result<T, E>
where
F: FnOnce(E) -> T;
fn and_then_async<F, Fut, U, E2>(self, f: F) -> impl std::future::Future<Output = Result<U, E2>>
where
F: FnOnce(T) -> Fut,
Fut: std::future::Future<Output = Result<U, E2>>,
E: Into<E2>;
}
impl<T, E> ResultExt<T, E> for Result<T, E> {
fn map_err_into<U: From<E>>(self) -> Result<T, U> {
self.map_err(Into::into)
}
fn or_else_ok<F>(self, f: F) -> Result<T, E>
where
F: FnOnce(E) -> T,
{
self.or_else(|e| Ok(f(e)))
}
fn and_then_async<F, Fut, U, E2>(self, f: F) -> impl std::future::Future<Output = Result<U, E2>>
where
F: FnOnce(T) -> Fut,
Fut: std::future::Future<Output = Result<U, E2>>,
E: Into<E2>,
{
async move {
match self {
Ok(val) => f(val).await,
Err(e) => Err(e.into()),
}
}
}
}
pub fn combine_results<T, E>(results: Vec<Result<T, E>>) -> Result<Vec<T>, Vec<E>> {
let mut values = Vec::new();
let mut errors = Vec::new();
for result in results {
match result {
Ok(val) => values.push(val),
Err(e) => errors.push(e),
}
}
if errors.is_empty() {
Ok(values)
} else {
Err(errors)
}
}