Expand description
Guest-side library for writing cuttlefish proc-blocks.
A block is a state machine that the host drives. It never calls the host and
waits; it returns a Command saying what it wants, and the host — having
done that thing — steps it again with an Event. See cuttlefish_abi
for why control is inverted, and what that buys: chiefly that cancellation
needs no cooperation from the guest, because the host simply stops stepping.
This crate exists so block authors do not hand-write that inversion.
Implement Block, call export_block!, and the macro emits the raw wasm
exports the host expects.
§Writing a block
use cuttlefish_sdk::{Block, Command, Event};
#[derive(Default)]
struct Shout;
impl Block for Shout {
fn start(&mut self, input: serde_json::Value) -> Command {
match input.get("path").and_then(|v| v.as_str()) {
Some(path) => Command::Open { path: path.to_string() },
None => Command::Fail {
code: "schema_validation_failed".into(),
message: "input needs a string `path`".into(),
},
}
}
fn step(&mut self, event: Event) -> Command {
match event {
Event::Opened { handle, len, .. } => Command::Slice { handle, offset: 0, len },
Event::Sliced { text, .. } => Command::Done {
result: serde_json::json!({ "shouted": text.to_uppercase() }),
},
other => Command::Fail {
code: "unexpected_event".into(),
message: format!("{other:?}"),
},
}
}
}
// A real block adds this to emit the wasm exports:
// cuttlefish_sdk::export_block!(Shout);Because a block is an ordinary Rust type, it can be unit-tested natively with
no wasm involved: construct it, call start, then feed it the events its
commands would produce. Only the boundary itself needs a wasm harness.
§Memory ownership across the boundary
Values handed to the host are leaked on purpose. The host reads them immediately after the call returns, and the entire instance is destroyed when the job ends, so there is nothing to reclaim and no cross-language allocator coordination to get wrong.
Do not “fix” this by freeing. The host would then read freed memory, and on wasm that is a silent wrong answer rather than a segfault — the linear memory is still perfectly valid to read, it just no longer holds what anyone thinks.
Macros§
- export_
block - Emit the wasm exports for a
Blockimplementation.
Structs§
- Desc
- How a guest hands a (pointer, length) pair back to the host.
- Signature
- What a block accepts and produces.
Enums§
- Command
- What a guest asks the host to do, returned from its
init/stepexports. - Event
- What the host feeds back into the guest’s
stepexport after carrying out aCommand. - Image
Operation - One transformation
Command::ImageOpcan apply. - Media
Kind - What kind of thing a handle refers to, reported by
Event::Opened. - Token
Action - A guest’s verdict on each streamed token, returned from its
on_tokenexport. - Ty
- The shape of a value flowing through a pipeline.
Traits§
- Block
- What a proc-block author implements.
Type Aliases§
- Handle
- A job-scoped reference to something the host holds open for a guest.