mlua_swarm/worker/output.rs
1//! Output path.
2//!
3//! The worker → `SpawnerAdapter` → engine output path. All structuring is
4//! completed inside the `SpawnerAdapter`; by the time an event reaches the
5//! engine it is a Rust-typed `OutputEvent`. The wire form the worker uses
6//! (stdout / NDJSON / file path / IPC) is opaque to the engine.
7//!
8//! The `WorkerResult` type was folded into `OutputEvent::Final`.
9//!
10//! # Canonical type locations
11//!
12//! `OutputEvent` and `ContentRef` are canonical in [`crate::store::output`];
13//! this module is narrowed to re-exports plus the engine-specific
14//! `OutputSink` / `EngineSink`.
15
16use crate::core::errors::EngineError;
17use async_trait::async_trait;
18
19pub use crate::store::output::{ContentRef, OutputEvent};
20
21/// Sink used inside a worker function to emit events. The `InProcSpawner`
22/// injects one into `WorkerInvocation`. The `ProcessSpawner` / child-process
23/// pull path folds stdout / IPC into `OutputEvent` internally and calls
24/// `engine.submit_output` directly, so it does not go through `OutputSink`
25/// (it lands in the same engine state, but not via this trait).
26#[async_trait]
27pub trait OutputSink: Send + Sync {
28 /// Emits one `OutputEvent` (progress, final, etc.) into the engine's
29 /// output stream for this attempt.
30 async fn emit(&self, event: OutputEvent) -> Result<(), EngineError>;
31}
32
33/// Concrete `OutputSink` — the default implementation that closes over
34/// `engine`, `token`, `task_id`, and `attempt`, and calls
35/// `engine.submit_output` for every `emit`. Injected by the `InProcSpawner`
36/// into `WorkerInvocation`.
37#[derive(Clone)]
38pub struct EngineSink {
39 engine: crate::core::engine::Engine,
40 token: crate::types::CapToken,
41 task_id: crate::types::TaskId,
42 attempt: u32,
43}
44
45impl EngineSink {
46 /// Binds a sink to one attempt's identity so every `emit` call knows
47 /// where to route the event without the caller repeating the
48 /// coordinates each time.
49 pub fn new(
50 engine: crate::core::engine::Engine,
51 token: crate::types::CapToken,
52 task_id: crate::types::TaskId,
53 attempt: u32,
54 ) -> Self {
55 Self {
56 engine,
57 token,
58 task_id,
59 attempt,
60 }
61 }
62}
63
64#[async_trait]
65impl OutputSink for EngineSink {
66 async fn emit(&self, event: OutputEvent) -> Result<(), EngineError> {
67 self.engine
68 .submit_output(&self.token, &self.task_id, self.attempt, event)
69 .await
70 }
71}