Skip to main content

monoloop_loop/transaction/lifecycle/
delivery.rs

1//! Host-side adapters that drain v2 mailboxes outside the runtime core (M1).
2//!
3//! The core runtime MUST NOT invoke these adapters. They exist so existing hosts
4//! that still speak [`CompletionCallback`] / [`TransactionEventSink`] can be
5//! bridged during migration without putting arbitrary futures on the runtime
6//! executor.
7
8use monoloop_contracts::{
9    CompletionCallback, CompletionDeliveryError, TransactionCompletionReceiver, TransactionEvent,
10    TransactionEventReceiver, TransactionEventSink,
11};
12use std::sync::Arc;
13
14/// Invoke a legacy completion callback after the runtime publishes once.
15///
16/// Runs on the **caller**/host task — never on the runtime-owned executor.
17pub async fn adapt_completion_callback(
18    receiver: TransactionCompletionReceiver,
19    callback: Box<dyn CompletionCallback>,
20) -> Result<(), CompletionDeliveryError> {
21    match receiver.recv().await {
22        Ok(completion) => {
23            // Map v2 completion into the legacy TransactionEnd shape for hosts
24            // that have not migrated yet.
25            let end = monoloop_contracts::TransactionEnd {
26                transaction_id: completion.end.transaction_id,
27                session_id: completion.end.session_id,
28                channel_id: completion.end.channel_id,
29                kind: completion.end.kind,
30                prior_terminal_cause: None,
31                event_delivery: match completion.terminal_event_delivery {
32                    monoloop_contracts::TerminalEventDelivery::Published => {
33                        monoloop_contracts::EventDeliveryOutcome::Accepted
34                    }
35                    monoloop_contracts::TerminalEventDelivery::NotAttempted
36                    | monoloop_contracts::TerminalEventDelivery::QueueClosed
37                    | monoloop_contracts::TerminalEventDelivery::DeadlineExceeded
38                    | monoloop_contracts::TerminalEventDelivery::LimitExceeded => {
39                        monoloop_contracts::EventDeliveryOutcome::Failed
40                    }
41                },
42                emitted_events: completion.end.emitted_events,
43                usage: completion.end.usage,
44                diagnostics: completion.end.diagnostics,
45            };
46            callback.call(end).await
47        }
48        Err(_) => Err(CompletionDeliveryError::Failed),
49    }
50}
51
52/// Forward mailbox events to a legacy sink until the sender is dropped.
53///
54/// Runs on the **caller**/host task — never on the runtime-owned executor.
55pub async fn adapt_event_sink(
56    mut receiver: TransactionEventReceiver,
57    sink: Arc<dyn TransactionEventSink>,
58) {
59    while let Some(event) = receiver.recv().await {
60        let _ = forward_one(&sink, event).await;
61    }
62}
63
64async fn forward_one(
65    sink: &Arc<dyn TransactionEventSink>,
66    event: TransactionEvent,
67) -> Result<(), monoloop_contracts::EventDeliveryError> {
68    sink.deliver(event).await
69}