saddle-runtime 0.3.24

Saddle managed asynchronous runtime and lifecycle
Documentation
//! Framework-component composition example, NOT an App/HTTP/DB acceptance.
use saddle_runtime::{
    profusegw::{
        ProfuseGwManagedDispatch, ProfuseGwProcessLease, ReservedDispatchOutcome,
        finish_profusegw_without_database,
    },
    request_task::{
        reserved::{
            ReservedBorrowedFuture, ReservedRequestFailure, ReservedTaskContext,
            dispatch_storage_bytes_for,
        },
        reserved_set::ReservedCollectionJoin,
    },
};
use std::{alloc::Layout, future::Future};
type Owner = saddle_runtime::profusegw::ReservedDispatchOwner<()>;

fn body(
    owner: &mut Owner,
    context: ReservedTaskContext,
) -> impl Future<Output = Result<u32, ReservedRequestFailure>> + Send + '_ {
    async move {
        let _current = context.view();
        assert!(owner.0.as_ref().unwrap().deadline_unix_ms() > 0);
        Ok(41)
    }
}
fn factory<'a>(
    owner: &'a mut Owner,
    context: ReservedTaskContext,
) -> ReservedBorrowedFuture<'a, u32> {
    Box::pin(body(owner, context))
}
fn returned_layout<I, R>(_: impl FnOnce(I) -> R) -> Layout {
    Layout::new::<R>()
}
fn body_layout() -> Layout {
    returned_layout(
        |(owner, context): (&'static mut Owner, ReservedTaskContext)| body(owner, context),
    )
}

/// The real Facade receives this lease from Runtime's existing process factory.
/// S must replace the isolated unit captures/body with its actual SC types and
/// indirect allocation list. Calling the layout witness never runs the body.
#[allow(dead_code)]
async fn consume(lease: &ProfuseGwProcessLease) -> Result<(), ()> {
    let storage = lease.try_reserved_task_storage().map_err(|_| ())?;
    let mut tasks = storage.normal::<Owner, u32>().map_err(|_| ())?;
    let outcome = lease.try_reserved_dispatch(
        saddle_core::request_context::ContextLabel::checked("component-example").unwrap(),
        None,
        body_layout(),
        &[],
        (),
        factory,
    );
    let (root, future, ticket) = match outcome {
        ReservedDispatchOutcome::Ready {
            root,
            future,
            ticket,
            ..
        } => (root, future, ticket),
        ReservedDispatchOutcome::Rejected {
            input: _,
            make: _,
            reason: _,
        } => return Err(()),
    };
    if let Err((future, ticket, _)) = tasks.spawn(future, ticket) {
        let recovered = ticket
            .withdraw(future)
            .map_err(|_| ())?
            .recover(Default::default())
            .map_err(|_| ())?;
        drop(root);
        if let Some(dispatch) = recovered.owner.0 {
            dispatch.cancel();
        }
        return Err(());
    }
    let Some(ReservedCollectionJoin::Matched(joined)) = tasks.join_next().await else {
        return Err(());
    };
    // If DB was entered, the original completion retained in Owner must finish
    // actual physical cleanup here first; this no-DB example cannot prove it.
    let recovered = joined.recover(Default::default()).map_err(|_| ())?;
    drop(root);
    let value = recovered.result.ok_or(())?.map_err(|_| ())?;
    let dispatch = recovered.owner.0.ok_or(())?;
    assert_eq!(
        finish_profusegw_without_database(dispatch, value).map_err(|_| ())?,
        41
    );
    drop((tasks, storage));
    Ok(())
}

fn main() {
    let bytes = dispatch_storage_bytes_for::<(), u32, _>(&factory, body_layout(), &[]).unwrap();
    println!("isolated declared task bytes={bytes}; formal migrated consumer NOT_ENABLED");
}