vantage-diorama 0.4.1

Cached, composable, reactive surface for Vantage Vistas
Documentation
use std::future::Future;
use std::pin::Pin;

use vantage_core::Result;

use crate::dio::Dio;
use crate::ops::{ChangeEvent, QueryDescriptor, WriteOp};

/// Future returned by a Dio callback. Borrows from the supplied `&Dio`.
pub type DioCallbackFuture<'a> = Pin<Box<dyn Future<Output = Result<()>> + Send + 'a>>;

/// Callback shape: borrow `&Dio`, return a borrowed future. Box the
/// closure once at registration; the HRTB lets a single boxed closure
/// be invoked against any `&Dio` lifetime.
pub type DioCallback =
    Box<dyn for<'a> Fn(&'a Dio) -> DioCallbackFuture<'a> + Send + Sync + 'static>;

pub type DioWriteCallback =
    Box<dyn for<'a> Fn(&'a Dio, WriteOp) -> DioCallbackFuture<'a> + Send + Sync + 'static>;

pub type DioEventCallback =
    Box<dyn for<'a> Fn(&'a Dio, ChangeEvent) -> DioCallbackFuture<'a> + Send + Sync + 'static>;

pub type DioQueryCallback =
    Box<dyn for<'a> Fn(&'a Dio, QueryDescriptor) -> DioCallbackFuture<'a> + Send + Sync + 'static>;

/// The five callback slots a Lens may hold. Each is independently
/// optional; the Lens treats absent slots as "use the default path"
/// (read from cache, write to master, etc.).
#[derive(Default)]
pub struct LensCallbacks {
    pub on_start: Option<DioCallback>,
    pub on_refresh: Option<DioCallback>,
    pub on_write: Option<DioWriteCallback>,
    pub on_event: Option<DioEventCallback>,
    pub on_query: Option<DioQueryCallback>,
}

/// Wrap a user closure into a [`DioCallback`].
///
/// The canonical user pattern is `move |dio| { let dio = dio.clone();
/// async move { ... dio.cache().insert_values(...).await } }` —
/// cloning the Dio inside the closure produces a `'static` future,
/// which avoids the lifetime gymnastics of borrowing `&Dio` across an
/// await.
pub fn boxed_dio_callback<F, Fut>(f: F) -> DioCallback
where
    F: for<'a> Fn(&'a Dio) -> Fut + Send + Sync + 'static,
    Fut: Future<Output = Result<()>> + Send + 'static,
{
    Box::new(move |dio| Box::pin(f(dio)))
}

/// Wrap a user closure into a [`DioWriteCallback`].
pub fn boxed_dio_write_callback<F, Fut>(f: F) -> DioWriteCallback
where
    F: for<'a> Fn(&'a Dio, WriteOp) -> Fut + Send + Sync + 'static,
    Fut: Future<Output = Result<()>> + Send + 'static,
{
    Box::new(move |dio, op| Box::pin(f(dio, op)))
}

/// Wrap a user closure into a [`DioEventCallback`].
pub fn boxed_dio_event_callback<F, Fut>(f: F) -> DioEventCallback
where
    F: for<'a> Fn(&'a Dio, ChangeEvent) -> Fut + Send + Sync + 'static,
    Fut: Future<Output = Result<()>> + Send + 'static,
{
    Box::new(move |dio, ev| Box::pin(f(dio, ev)))
}

/// Wrap a user closure into a [`DioQueryCallback`].
pub fn boxed_dio_query_callback<F, Fut>(f: F) -> DioQueryCallback
where
    F: for<'a> Fn(&'a Dio, QueryDescriptor) -> Fut + Send + Sync + 'static,
    Fut: Future<Output = Result<()>> + Send + 'static,
{
    Box::new(move |dio, q| Box::pin(f(dio, q)))
}