rings_node/extension/ext/interpret.rs
1#![warn(missing_docs)]
2//! The imperative shell of an extension: [`Interpret`] runs a protocol's **own** effects.
3//!
4//! Each extension registers a `(Protocol, Interpret)` pair. The interpreter is the only
5//! place IO happens for that extension; it is handed a **namespace-scoped** capability
6//! ([`Scope`](super::Scope)) — overlay `send`, `did`, and self-`inject`, all confined to the
7//! interpreter's own namespace. An extension that owns OS resources (e.g. the relay's sockets)
8//! keeps them inside its interpreter, so the core never depends on transport internals.
9
10use bytes::Bytes;
11
12use super::Scope;
13use crate::error::Result;
14
15/// Runs the effects produced by a protocol's pure `step`. `run` returns the payloads to
16/// re-inject into the router; each is re-delivered to **this** protocol's own namespace with
17/// `from = this node` — the router sets the provenance, so a shell can forge neither a
18/// namespace nor a remote `from`. A hard failure is an `Err`. Defined per-effect outcomes (e.g.
19/// "addressed no live session") are the extension's own concern and surfaced however it likes
20/// (its own return shapes / tests), not a core enum.
21#[cfg_attr(feature = "browser", async_trait::async_trait(?Send))]
22#[cfg_attr(not(feature = "browser"), async_trait::async_trait)]
23pub trait Interpret {
24 /// The effect algebra this shell interprets — the same as its protocol's `Effect`.
25 type Effect;
26
27 /// Run one effect against the scoped capability, returning self-injected payloads (each
28 /// re-decoded by this same protocol).
29 async fn run(&self, scope: &Scope, effect: Self::Effect) -> Result<Vec<Bytes>>;
30}