async_monad 0.2.0

Asynchronous monad for rust
Documentation
use std::future::Future;
use std::pin::Pin;

use super::option::AsyncOption;

pub struct AsyncResult<T: 'static, E: 'static> {
    future: Pin<Box<dyn Future<Output = Result<T, E>>>>,
}

impl<T, E> From<Result<T, E>> for AsyncResult<T, E> {
    fn from(value: Result<T, E>) -> Self {
        Self {
            future: Box::pin(async move { value }),
        }
    }
}

impl<T, E> Future for AsyncResult<T, E> {
    type Output = Result<T, E>;

    fn poll(
        mut self: Pin<&mut Self>,
        cx: &mut std::task::Context<'_>,
    ) -> std::task::Poll<Self::Output> {
        Future::poll(self.future.as_mut(), cx)
    }
}

impl<T, E> AsyncResult<T, E> {
    /// Create a new asynchronous result.
    ///
    /// # Examples
    ///
    /// ```
    /// use tokio::runtime::Runtime;
    /// # use async_monad::async_wrapped::result::AsyncResult;
    ///
    /// let runtime = Runtime::new().unwrap();
    /// let result = runtime.block_on(async {
    ///     let res: AsyncResult<u8, String> = AsyncResult::new(Ok(1));
    ///     res.await
    /// });
    /// println!("{:?}", result);
    /// ```
    #[inline]
    #[must_use]
    pub fn new(value: Result<T, E>) -> AsyncResult<T, E> {
        Self {
            future: Box::pin(async move { value }),
        }
    }

    /// Create a new asynchronous result from a raw future.
    ///
    /// # Examples
    ///
    /// ```
    /// use tokio::runtime::Runtime;
    /// # use async_monad::async_wrapped::result::AsyncResult;
    ///
    /// let runtime = Runtime::new().unwrap();
    /// let result = runtime.block_on(async {
    ///     let res: AsyncResult<u8, String> = AsyncResult::raw(async { Ok(1) });
    ///     res.await
    /// });
    /// println!("{:?}", result);
    /// ```
    #[inline]
    #[must_use]
    pub fn raw<V: Future<Output = Result<T, E>> + 'static>(value: V) -> AsyncResult<T, E> {
        Self {
            future: Box::pin(value),
        }
    }

    #[inline]
    #[must_use]
    pub fn and<U>(self, optb: impl Future<Output = Result<U, E>> + 'static) -> AsyncResult<U, E> {
        AsyncResult {
            future: Box::pin(async move {
                match self.future.await {
                    Ok(_) => optb.await,
                    Err(e) => Err(e),
                }
            }),
        }
    }

    #[inline]
    #[must_use]
    pub fn and_then<F, V>(self, f: impl FnOnce(T) -> F + 'static) -> AsyncResult<V, E>
    where
        F: Future<Output = AsyncResult<V, E>> + 'static,
        V: 'static,
    {
        AsyncResult {
            future: Box::pin(async move {
                match self.future.await {
                    Ok(val) => f(val).await.await,
                    Err(err) => Err(err),
                }
            }),
        }
    }

    #[inline]
    #[must_use]
    pub fn or<F>(self, res: impl Future<Output = Result<T, F>> + 'static) -> AsyncResult<T, F> {
        AsyncResult {
            future: Box::pin(async move {
                match self.future.await {
                    Ok(val) => Ok(val),
                    Err(_) => res.await,
                }
            }),
        }
    }

    #[inline]
    #[must_use]
    pub fn or_else<F, V>(self, f: impl FnOnce(E) -> F + 'static) -> AsyncResult<T, V>
    where
        F: Future<Output = Result<T, V>> + 'static,
        V: 'static,
    {
        AsyncResult {
            future: Box::pin(async move {
                match self.future.await {
                    Ok(val) => Ok(val),
                    Err(err) => f(err).await,
                }
            }),
        }
    }

    #[inline]
    #[must_use]
    pub fn map<F, U>(self, f: impl FnOnce(T) -> F + 'static) -> AsyncResult<U, E>
    where
        F: Future<Output = U> + 'static,
        U: 'static,
    {
        AsyncResult {
            future: Box::pin(async move {
                match self.future.await {
                    Ok(v) => Ok(f(v).await),
                    Err(e) => Err(e),
                }
            }),
        }
    }

    #[inline]
    #[must_use]
    pub async fn map_or<U, F>(self, default: F, f: impl FnOnce(T) -> F) -> U
    where
        F: Future<Output = U> + 'static,
        U: 'static,
    {
        match self.future.await {
            Ok(v) => f(v).await,
            Err(_) => default.await,
        }
    }

    #[inline]
    #[must_use]
    pub async fn map_or_else<U, F>(self, default: impl FnOnce() -> F, f: impl FnOnce(T) -> F) -> U
    where
        F: Future<Output = U> + 'static,
        U: 'static,
    {
        match self.future.await {
            Ok(v) => f(v).await,
            Err(_) => default().await,
        }
    }

    #[inline]
    #[must_use]
    pub fn map_err<F, U>(self, f: impl FnOnce(E) -> F + 'static) -> AsyncResult<T, U>
    where
        F: Future<Output = U> + 'static,
        U: 'static,
    {
        AsyncResult {
            future: Box::pin(async move {
                match self.future.await {
                    Ok(v) => Ok(v),
                    Err(e) => Err(f(e).await),
                }
            }),
        }
    }

    #[inline]
    #[must_use]
    pub async fn map_err_or<U, F>(self, default: F, f: impl FnOnce(E) -> F) -> U
    where
        F: Future<Output = U> + 'static,
        U: 'static,
    {
        match self.future.await {
            Err(v) => f(v).await,
            Ok(_) => default.await,
        }
    }

    #[inline]
    #[must_use]
    pub async fn map_err_or_else<U, F>(
        self,
        default: impl FnOnce() -> F,
        f: impl FnOnce(E) -> F,
    ) -> U
    where
        F: Future<Output = U> + 'static,
        U: 'static,
    {
        match self.future.await {
            Err(v) => f(v).await,
            Ok(_) => default().await,
        }
    }

    #[inline]
    #[must_use]
    pub fn inspect(self, f: impl FnOnce(&T) + 'static) -> Self {
        AsyncResult {
            future: Box::pin(async move {
                match self.future.await {
                    Ok(val) => {
                        f(&val);
                        Ok(val)
                    }
                    Err(err) => Err(err),
                }
            }),
        }
    }

    #[inline]
    #[must_use]
    pub fn inspect_err(self, f: impl FnOnce(&E) + 'static) -> Self {
        AsyncResult {
            future: Box::pin(async move {
                match self.future.await {
                    Err(val) => {
                        f(&val);
                        Err(val)
                    }
                    Ok(err) => Ok(err),
                }
            }),
        }
    }

    #[inline]
    #[must_use]
    pub fn ok(self) -> AsyncOption<T> {
        AsyncOption::raw(async move { self.future.await.ok() })
    }

    #[inline]
    #[must_use]
    pub fn err(self) -> AsyncOption<E> {
        AsyncOption::raw(async move { self.future.await.err() })
    }

    #[inline]
    #[must_use]
    pub async fn is_ok(self) -> bool {
        self.future.await.is_ok()
    }

    #[inline]
    #[must_use]
    pub async fn is_ok_and<F>(self, f: impl FnOnce(T) -> F) -> bool
    where
        F: Future<Output = bool>,
    {
        if let Ok(val) = self.future.await {
            f(val).await
        } else {
            false
        }
    }

    #[inline]
    #[must_use]
    pub async fn is_ok_or<F>(self, f: impl FnOnce(E) -> F) -> bool
    where
        F: Future<Output = bool>,
    {
        if let Err(err) = self.future.await {
            f(err).await
        } else {
            true
        }
    }

    #[inline]
    #[must_use]
    pub async fn is_err(self) -> bool {
        self.future.await.is_err()
    }

    #[inline]
    #[must_use]
    pub async fn is_err_and<F>(self, f: impl FnOnce(E) -> F) -> bool
    where
        F: Future<Output = bool>,
    {
        if let Err(err) = self.future.await {
            f(err).await
        } else {
            false
        }
    }

    #[inline]
    #[must_use]
    pub async fn is_err_or<F>(self, f: impl FnOnce(T) -> F) -> bool
    where
        F: Future<Output = bool>,
    {
        if let Ok(val) = self.future.await {
            f(val).await
        } else {
            true
        }
    }
}

impl<T, E> AsyncResult<AsyncOption<T>, E> {
    /// This operation does not return an [`AsyncResult`] because it has to `await` both
    /// the result and the option, thus creating another [`AsyncResult`] is only an
    /// additional burden.
    pub fn transpose(self) -> AsyncOption<Result<T, E>> {
        AsyncOption::raw(async move {
            match self.future.await {
                Ok(val) => val.await.map(Ok),
                Err(e) => Some(Err(e)),
            }
        })
    }
}

impl<T, E> AsyncResult<Option<T>, E> {
    /// This operation does not return an [`AsyncResult`] because it has to `await`
    /// the result, thus creating another [`AsyncResult`] is only an additional burden.
    pub fn transpose(self) -> AsyncOption<Result<T, E>> {
        AsyncOption::raw(async move {
            match self.future.await {
                Ok(val) => val.map(Ok),
                Err(e) => Some(Err(e)),
            }
        })
    }
}

impl<T, E> AsyncResult<AsyncResult<T, E>, E> {
    pub fn flatten(self) -> AsyncResult<T, E> {
        AsyncResult {
            future: Box::pin(async move {
                match self.future.await {
                    Ok(val) => val.await,
                    Err(e) => Err(e),
                }
            }),
        }
    }
}

impl<T, E> AsyncResult<Result<T, E>, E> {
    pub fn flatten(self) -> AsyncResult<T, E> {
        AsyncResult {
            future: Box::pin(async move { self.future.await? }),
        }
    }
}