future_form 0.3.1

Abstractions over Send and !Send futures
Documentation
#![no_std]
#![doc = include_str!("../README.md")]

extern crate alloc;

use alloc::boxed::Box;
use core::future::Future;
use futures::future::{BoxFuture, LocalBoxFuture};

pub use future_form_macros::future_form;

pub mod extensions;

/// An abstraction over [`Future`]s.
///
/// This trait allows you to write async code that works with both `Send` and `!Send` futures,
/// avoiding the need to duplicate trait implementations for different runtime requirements.
///
/// # Example
///
/// Define a database trait generic over [`FutureForm`]:
///
/// ```rust
/// use future_form::{FutureForm, Sendable, Local};
/// use futures::future::{BoxFuture, LocalBoxFuture};
///
/// // Database trait that works with any FutureForm
/// trait Database<K: FutureForm> {
///     fn get<'a>(&'a self, key: &'a str) -> K::Future<'a, Option<String>>;
///     fn set<'a>(&'a mut self, key: &'a str, value: String) -> K::Future<'a, ()>;
/// }
///
/// struct InMemoryDb {
///     data: std::collections::HashMap<String, String>,
/// }
///
/// // Implement for Send futures (e.g., tokio runtime)
/// impl Database<Sendable> for InMemoryDb {
///     fn get<'a>(&'a self, key: &'a str) -> BoxFuture<'a, Option<String>> {
///         Sendable::from_future(async move { self.data.get(key).cloned() })
///     }
///
///     fn set<'a>(&'a mut self, key: &'a str, value: String) -> BoxFuture<'a, ()> {
///         Sendable::from_future(async move {
///             self.data.insert(key.to_string(), value);
///         })
///     }
/// }
///
/// // Implement for !Send futures (e.g., Wasm or single-threaded runtime)
/// impl Database<Local> for InMemoryDb {
///     fn get<'a>(&'a self, key: &'a str) -> LocalBoxFuture<'a, Option<String>> {
///         Local::from_future(async move { self.data.get(key).cloned() })
///     }
///
///     fn set<'a>(&'a mut self, key: &'a str, value: String) -> LocalBoxFuture<'a, ()> {
///         Local::from_future(async move {
///             self.data.insert(key.to_string(), value);
///         })
///     }
/// }
/// ```
///
/// # Using with structs
///
/// For cleaner ergonomics, use a struct to carry the type parameter:
///
/// ```rust
/// use std::marker::PhantomData;
/// use future_form::{FutureForm, Sendable};
/// use futures::future::BoxFuture;
///
/// trait Database<K: FutureForm> {
///     fn get<'a>(&'a self, key: &'a str) -> K::Future<'a, Option<String>>;
/// }
///
/// struct InMemoryDb {
///     data: std::collections::HashMap<String, String>,
/// }
///
/// impl Database<Sendable> for InMemoryDb {
///     fn get<'a>(&'a self, key: &'a str) -> BoxFuture<'a, Option<String>> {
///         Sendable::from_future(async move { self.data.get(key).cloned() })
///     }
/// }
///
/// // Repository struct carries the FutureForm parameter
/// struct Repository<K: FutureForm> {
///     db: InMemoryDb,
///     _marker: PhantomData<K>,
/// }
///
/// impl<K: FutureForm> Repository<K>
/// where
///     InMemoryDb: Database<K>
/// {
///     fn new(db: InMemoryDb) -> Self {
///         Self {
///             db,
///             _marker: PhantomData,
///         }
///     }
///
///     async fn fetch_user(&self, user_id: &str) -> Option<String> {
///         Database::<K>::get(&self.db, user_id).await
///     }
/// }
/// ```
pub trait FutureForm {
    /// An abstraction over future types.
    ///
    /// This is especially useful for abstracting over `Send` and `!Send` futures.
    type Future<'a, T: 'a>: Future<Output = T> + 'a;

    /// Create this form's future type from a raw future.
    ///
    /// # Example
    ///
    /// ```rust
    /// use future_form::{FutureForm, Sendable, Local};
    /// use futures::future::{BoxFuture, LocalBoxFuture};
    ///
    /// fn sendable_example() -> BoxFuture<'static, u32> {
    ///     Sendable::from_future(async { 42 })
    /// }
    ///
    /// fn local_example() -> LocalBoxFuture<'static, u32> {
    ///     Local::from_future(async { 42 })
    /// }
    /// ```
    fn from_future<'a, T, F>(f: F) -> Self::Future<'a, T>
    where
        T: 'a,
        F: Future<Output = T> + 'a,
        Self::Future<'a, T>: FromFuture<'a, T, F>,
    {
        FromFuture::from_future(f)
    }

    /// Create this form's future type from an already-computed value.
    ///
    /// This is useful for sync operations that need to return a future type,
    /// avoiding the need to capture values in an async block.
    ///
    /// # Example
    ///
    /// ```rust
    /// use future_form::{FutureForm, Sendable, Local};
    /// use futures::future::{BoxFuture, LocalBoxFuture};
    ///
    /// fn sendable_ready() -> BoxFuture<'static, u32> {
    ///     Sendable::ready(42)
    /// }
    ///
    /// fn local_ready() -> LocalBoxFuture<'static, u32> {
    ///     Local::ready(42)
    /// }
    /// ```
    fn ready<'a, T>(value: T) -> Self::Future<'a, T>
    where
        T: 'a,
        Self::Future<'a, T>: FromReady<'a, T>;
}

/// Abstraction over [`Send`] futures.
///
/// Use this when your async code needs to work with multi-threaded runtimes
/// like `tokio` or `async-std` that require futures to be `Send`.
///
/// # Example
///
/// ```rust
/// use future_form::{FutureForm, Sendable};
/// use futures::future::BoxFuture;
///
/// trait Cache<K: FutureForm> {
///     fn fetch<'a>(&'a self, key: &'a str) -> K::Future<'a, Option<String>>;
/// }
///
/// struct RedisCache;
///
/// // Implement for Send futures - can be used with tokio
/// impl Cache<Sendable> for RedisCache {
///     fn fetch<'a>(&'a self, key: &'a str) -> BoxFuture<'a, Option<String>> {
///         Sendable::from_future(async move {
///             // Simulate fetching from Redis
///             Some(format!("value-{}", key))
///         })
///     }
/// }
/// ```
#[derive(Debug, Clone, Copy)]
pub enum Sendable {}
impl FutureForm for Sendable {
    type Future<'a, T: 'a> = BoxFuture<'a, T>;

    fn ready<'a, T>(value: T) -> Self::Future<'a, T>
    where
        T: 'a,
        Self::Future<'a, T>: FromReady<'a, T>,
    {
        FromReady::from_ready(value)
    }
}

/// Abstraction over [`!Send`][Send] futures.
///
/// Use this when your async code runs in single-threaded environments like
/// Wasm, browser contexts, or single-threaded executors that don't require
/// futures to be `Send`.
///
/// # Example
///
/// ```rust
/// use future_form::{FutureForm, Local};
/// use futures::future::LocalBoxFuture;
///
/// trait Cache<K: FutureForm> {
///     fn fetch<'a>(&'a self, key: &'a str) -> K::Future<'a, Option<String>>;
/// }
///
/// struct BrowserCache;
///
/// // Implement for !Send futures - can be used in Wasm
/// impl Cache<Local> for BrowserCache {
///     fn fetch<'a>(&'a self, key: &'a str) -> LocalBoxFuture<'a, Option<String>> {
///         Local::from_future(async move {
///             // Simulate fetching from browser storage
///             Some(format!("value-{}", key))
///         })
///     }
/// }
/// ```
#[derive(Debug, Clone, Copy)]
pub enum Local {}
impl FutureForm for Local {
    type Future<'a, T: 'a> = LocalBoxFuture<'a, T>;

    fn ready<'a, T>(value: T) -> Self::Future<'a, T>
    where
        T: 'a,
        Self::Future<'a, T>: FromReady<'a, T>,
    {
        FromReady::from_ready(value)
    }
}

/// A trait for constructing [`FutureForm`]-specific types from raw futures.
///
/// This abstracts over the wrapping operation, allowing generic code to construct
/// the appropriate future type without knowing the concrete form.
///
/// Typically you'll use [`FutureForm::from_future`] instead of calling this directly.
///
/// # Example
///
/// ```rust
/// use future_form::{FutureForm, Sendable, Local};
/// use futures::future::{BoxFuture, LocalBoxFuture};
///
/// trait Counter<K: FutureForm> {
///     fn next(&self) -> K::Future<'_, u32>;
/// }
///
/// struct Memory { val: u32 }
///
/// impl Counter<Sendable> for Memory {
///     fn next(&self) -> BoxFuture<'_, u32> {
///         let val = self.val;
///         Sendable::from_future(async move { val + 1 })
///     }
/// }
///
/// impl Counter<Local> for Memory {
///     fn next(&self) -> LocalBoxFuture<'_, u32> {
///         let val = self.val;
///         Local::from_future(async move { val + 1 })
///     }
/// }
/// ```
pub trait FromFuture<'a, T, F>
where
    T: 'a,
    F: Future<Output = T> + 'a,
{
    /// Create this type from a future.
    fn from_future(f: F) -> Self;
}

impl<'a, T, F> FromFuture<'a, T, F> for BoxFuture<'a, T>
where
    T: 'a,
    F: Future<Output = T> + Send + 'a,
{
    fn from_future(f: F) -> Self {
        Box::pin(f)
    }
}

impl<'a, T, F> FromFuture<'a, T, F> for LocalBoxFuture<'a, T>
where
    T: 'a,
    F: Future<Output = T> + 'a,
{
    fn from_future(f: F) -> Self {
        Box::pin(f)
    }
}

/// A trait for constructing [`FutureForm`]-specific types from ready values.
///
/// This abstracts over the wrapping operation for values that are already computed,
/// avoiding the overhead and complexity of capturing values in async blocks.
///
/// Typically you'll use [`FutureForm::ready`] instead of calling this directly.
pub trait FromReady<'a, T>
where
    T: 'a,
{
    /// Create this type from a ready value.
    fn from_ready(value: T) -> Self;
}

impl<'a, T> FromReady<'a, T> for BoxFuture<'a, T>
where
    T: Send + 'a,
{
    fn from_ready(value: T) -> Self {
        Box::pin(core::future::ready(value))
    }
}

impl<'a, T> FromReady<'a, T> for LocalBoxFuture<'a, T>
where
    T: 'a,
{
    fn from_ready(value: T) -> Self {
        Box::pin(core::future::ready(value))
    }
}