asimov_patterns/execute.rs
1// This is free and unencumbered software released into the public domain.
2
3//! The asynchronous execution interface shared by all program patterns.
4//!
5//! [`Execute`] separates running an already configured operation from selecting
6//! its role, input, and options. Pattern traits in [`crate::programs`] extend
7//! this interface without adding methods or prescribing an executor.
8
9use alloc::boxed::Box;
10use async_trait::async_trait;
11use core::result::Result;
12
13/// An asynchronously executable operation yielding `T` or its associated [`Error`](Self::Error).
14///
15/// Inputs and configuration are supplied by the implementation, typically at
16/// construction time. The mutable receiver permits execution to advance input
17/// streams or update internal state; it does not promise that another call will
18/// replay the same input. Implementations should document reuse, buffering,
19/// cancellation, and the meaning of successful completion.
20/// If `T` is a live stream, `Ok(T)` can mean successful startup rather than
21/// completed execution; subsequent failures must be exposed by that result.
22/// Each implementation chooses one error type for its result type `T`. Callers
23/// can constrain it with `Execute<T, Error = E>` or use the corresponding
24/// pattern trait's inherited associated type, such as `Emitter<T, Error = E>`.
25///
26/// This trait uses [`#[async_trait]`](macro@async_trait) with `Send` futures.
27/// Implementors use the same attribute on their `impl`; each call returns a
28/// boxed future whose lifetime is tied to the mutable receiver. The trait
29/// itself does not require `Send` or `Sync` as supertraits, select an
30/// asynchronous runtime, or require an operating-system process.
31///
32/// # Example
33///
34/// An in-process emitter can use the same interface as a process-backed one:
35///
36/// ```
37/// use asimov_patterns::{Emitter, Execute};
38/// use async_trait::async_trait;
39/// use core::convert::Infallible;
40///
41/// struct EmptyEmitter;
42///
43/// #[async_trait]
44/// impl Execute<Vec<u8>> for EmptyEmitter {
45/// type Error = Infallible;
46///
47/// async fn execute(&mut self) -> Result<Vec<u8>, Self::Error> {
48/// // An empty N-Triples document represents an empty RDF graph.
49/// Ok(Vec::new())
50/// }
51/// }
52///
53/// impl Emitter<Vec<u8>> for EmptyEmitter {}
54///
55/// // Associated errors can be constrained on generic bounds and trait objects.
56/// async fn emit(
57/// emitter: &mut (impl Emitter<Vec<u8>, Error = Infallible> + ?Sized),
58/// ) -> Result<Vec<u8>, Infallible> {
59/// emitter.execute().await
60/// }
61///
62/// let mut emitter = EmptyEmitter;
63/// let emitter: &mut dyn Emitter<Vec<u8>, Error = Infallible> = &mut emitter;
64/// let operation = emit(emitter);
65/// ```
66#[async_trait]
67pub trait Execute<T> {
68 /// The implementation-specific error returned directly by execution.
69 ///
70 /// This need not be a subprocess error or implement `core::error::Error`.
71 /// Errors carried inside a streaming result `T` are specified separately by
72 /// that result's type and documented by the implementation.
73 type Error;
74
75 /// Executes the operation using its current input and configuration.
76 ///
77 /// For a process-backed implementation reporting completed results, success
78 /// requires a normal zero exit status and successful required I/O transfers.
79 /// A streaming implementation must also expose eventual completion or
80 /// failure; receiving some output is not proof of success. An error does
81 /// not imply that external side effects have been rolled back.
82 ///
83 /// # Errors
84 ///
85 /// Returns the implementation-defined [`Error`](Self::Error). Implementations document
86 /// which failures are returned directly and which are delivered through `T`,
87 /// including launch, transport, program, and decoding failures where applicable.
88 async fn execute(&mut self) -> Result<T, Self::Error>;
89}