Skip to main content

FfiNode

Trait FfiNode 

Source
pub trait FfiNode:
    Send
    + Sync
    + 'static {
    // Required methods
    fn node_type(&self) -> RString;
    fn process(&self, input: RVec<u8>) -> FfiFuture<RResult<RVec<u8>, RString>>;

    // Provided methods
    fn process_multi(
        &self,
        input: RVec<u8>,
    ) -> FfiFuture<RResult<RVec<RVec<u8>>, RString>> { ... }
    fn initialize(
        &self,
        _session_id: RString,
        _node_id: RString,
    ) -> FfiFuture<RResult<(), RString>> { ... }
}
Expand description

FFI-safe node.

process returns an FfiFuture — an ABI-stable future the host can .await directly. Plugin-side async runtimes (or none) work as long as the future polls to completion without referencing runtime-specific globals; in practice, plugins that call back into host services do so by polling synchronous state from the async block.

§Forward compatibility (multi-output extension)

process is marked #[sabi(last_prefix_field)] — that’s the cut between the original FFI surface (1.x) and any methods added in minor versions. Methods added below it must carry a default impl so older plugins (whose vtables only expose process) continue to load. Hosts compiled against the newer ABI then transparently fall back to the default whenever a plugin omits the new method.

process_multi is the multi-output sibling of process: a node’s process_streaming callback can fire N times per input (think SileroVAD emitting Json(event) plus the audio passthrough), and the single-output process would silently drop everything but the first emission. process_multi returns the full RVec so the host can dispatch each blob into the streaming callback chain.

The default impl wraps process as a 1-element RVec so plugins that only implement single-output stay correct (just lossy when the underlying node was actually multi-output — same behaviour as before this method existed).

Required Methods§

Source

fn node_type(&self) -> RString

Source

fn process(&self, input: RVec<u8>) -> FfiFuture<RResult<RVec<u8>, RString>>

Provided Methods§

Source

fn process_multi( &self, input: RVec<u8>, ) -> FfiFuture<RResult<RVec<RVec<u8>>, RString>>

Multi-output process. Returns ALL emissions from one input as a flat RVec<RVec<u8>> (each inner vec is one rmp-serde RuntimeData blob, in emission order).

Default impl: delegate to process and wrap its single output as a 1-element vec. Plugins that haven’t been rebuilt against the multi-output ABI keep working — just without multi-output semantics. Plugins that override this method get full N-output fidelity through the LoadableNodeAdapter host wiring.

Source

fn initialize( &self, _session_id: RString, _node_id: RString, ) -> FfiFuture<RResult<(), RString>>

One-time, per-session initialization hook for lazy-load plugins.

Forwarded from the host’s AsyncStreamingNode::initialize() once per session, before the first process call. Plugins that do all their work eagerly inside FfiNodeFactory::create() (e.g. audio2face’s Audio2FaceLipSyncNode::load, live2d-render’s WgpuBackend::new) can leave this defaulted. Plugins with a non-trivial init (e.g. llama-cpp spawning a worker thread that loads a multi-GB GGUF) must override it — without forwarding, the worker is never spawned and process returns “worker not running”.

session_id and node_id are forwarded as RStrings so the plugin can log / tag work with them. emit_progress is NOT forwarded today — progress events emitted from inside a loadable plugin’s initialize() are silently dropped. Plugin authors who need progress visibility should wrap heavy init in the host (e.g. via WarmSessionPool::prewarm which fires its own progress before delegating).

Default impl: no-op. Older plugins not rebuilt against this method keep compiling, just without lazy-init semantics.

Implementors§

Source§

impl<_ErasedPtr> FfiNode for FfiNode_TO<_ErasedPtr>
where Self: Send + Sync + 'static, _ErasedPtr: AsPtr<PtrTarget = ()>,