# Extending `FutureForm` The `FutureForm` trait is open for extension. This document sketches out possible implementations beyond the built-in `Sendable` and `Local`. ## The Constraint ```rust,ignore pub trait FutureForm { type Future<'a, T: 'a>: Future + 'a; } ``` Any implementation must provide a `Future` type that: 1. Works for *any* output type `T` 2. Works for *any* lifetime `'a` 3. Implements `Future` This rules out concrete async block types (which have fixed output types), but allows any generic future wrapper. ## Traced Futures (Hypothetical) A `FutureForm` that logs every poll — useful for debugging or instrumentation: ```rust,ignore use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; use futures::future::BoxFuture; pub struct Traced; pub struct TracedFuture<'a, T> { inner: BoxFuture<'a, T>, name: &'static str, } impl<'a, T> Future for TracedFuture<'a, T> { type Output = T; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this = self.as_mut().get_mut(); eprintln!("[trace] polling {}", this.name); Pin::new(&mut this.inner).poll(cx) } } impl FutureForm for Traced { type Future<'a, T: 'a> = TracedFuture<'a, T>; } ``` This pattern extends to metrics collection, cancellation tokens, or any wrapper that needs to observe or modify future behavior. ## Result-Wrapped Futures For operations that might fail at construction time: ```rust,ignore use std::future::{Future, Ready, ready}; use std::pin::Pin; use std::task::{Context, Poll}; use futures::future::BoxFuture; /// Futures that capture a construction-time error. pub struct Fallible; pub enum FallibleFuture<'a, T> { Ok(BoxFuture<'a, T>), Err(Ready), // For error cases with default/error value } impl<'a, T> Future for FallibleFuture<'a, T> { type Output = T; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { match self.get_mut() { Self::Ok(f) => Pin::new(f).poll(cx), Self::Err(f) => Pin::new(f).poll(cx), } } } impl FutureForm for Fallible { type Future<'a, T: 'a> = FallibleFuture<'a, T>; } ``` ## Static Dispatch (Limited) True static dispatch without boxing is possible but limited. The future type must be nameable and generic: ```rust,ignore use std::future::Ready; /// For operations that complete immediately. pub struct Immediate; impl FutureForm for Immediate { type Future<'a, T: 'a> = Ready; } ``` Usage: ```rust,ignore impl MyTrait for MyType { fn get_value(&self) -> Ready { std::future::ready(42) } } ``` This works for `Ready`, `Pending`, or any nameable future type, but *not* for async blocks (whose types are anonymous and unnameable). ## Why Not Fully Unboxed? You might want: ```rust,ignore impl FutureForm for Unboxed { type Future<'a, T: 'a> = impl Future; // Not valid } ``` This doesn't work because: 1. Associated types can't use `impl Trait` 2. Async blocks have anonymous, unnameable types 3. Each async block creates a *different* type, but `FutureForm::Future` must be a single type The boxing in `Sendable`/`Local` is precisely what enables type erasure across different async implementations. ## The `FromFuture` Trait The crate provides a `FromFuture` trait that abstracts over lifting a future into a kind's future type: ```rust,ignore pub trait FromFuture<'a, T, F> where T: 'a, F: Future + 'a, { fn from_future(f: F) -> Self; } ``` This is implemented for `BoxFuture` (requiring `F: Send`) and `LocalBoxFuture` (no `Send` requirement). Custom future types can implement this trait to enable uniform construction. Usage is uniform across all forms via `FutureForm::from_future`: ```rust,ignore impl Counter for Memory { fn next(&self) -> BoxFuture<'_, u32> { Sendable::from_future(async { self.val + 1 }) } } impl Counter for Memory { fn next(&self) -> LocalBoxFuture<'_, u32> { Local::from_future(async { self.val + 1 }) } } ``` ## Using Custom Kinds with `#[future_form]` The `#[future_form]` macro supports custom `FutureForm` types alongside the built-in `Sendable` and `Local`: ```rust,ignore #[future_form(Sendable, Local, Traced)] impl MyTrait for MyType { fn operation(&self) -> K::Future<'_, u32> { K::from_future(async { self.value }) } } ``` For custom types, the macro replaces `K::Future<'a, T>` with `CustomType::Future<'a, T>` (the associated type) rather than a concrete type like `BoxFuture`. > **Note:** Custom types must implement `FromFuture` for the `from_future` pattern to work. Types like `Immediate` that use non-boxed futures (e.g., `Ready`) require different construction patterns.