Skip to main content

bb_ops/syscalls/composite/
bundle.rs

1//! `composite.Bundle` - pack N typed slot values into one
2//! [`CompositeValue`].
3//!
4//! Variable-arity input convention: the DSL recorder names the i'th
5//! payload `child_{i}` (positional naming because input ordering carries
6//! the semantics, not the names). The op clones each input via
7//! `SlotValue::clone_boxed` into the envelope, preserving the concrete
8//! carrier type for in-process Unbundle. Wire-boundary encoding is
9//! deferred to `CompositeValue::to_wire_bytes`.
10
11use bb_ir::proto::onnx::NodeProto;
12use bb_runtime::atomic::DispatchResult;
13use bb_runtime::bus::{OpError, OpErrorKind};
14use bb_runtime::runtime::RuntimeResourceRef;
15use bb_runtime::slot_value::SlotValue;
16use bb_runtime::syscall::values::CompositeValue;
17
18/// `(domain, op_type)` registration key. Shared with `TYPE_COMPOSITE`'s
19/// canonical denotation root.
20pub const DOMAIN: &str = "ai.bytesandbrains.composite";
21/// Op type name.
22pub const OP_TYPE: &str = "Bundle";
23/// Output port carrying the assembled [`CompositeValue`].
24pub const PORT_BUNDLE: &str = "bundle";
25
26/// Invoke fn - clone each `child_{i}` input into the envelope via
27/// `SlotValue::clone_boxed` and emit a single `CompositeValue` on the
28/// `bundle` output port. Bind-site port ordering survives because the
29/// DSL recorder stamps inputs in positional order; the op preserves
30/// that order in the resulting `Vec`.
31pub fn invoke(
32    _node: &NodeProto,
33    inputs: &[(&str, &dyn SlotValue)],
34    _ctx: &mut RuntimeResourceRef<'_>,
35) -> Result<DispatchResult, OpError> {
36    if inputs.is_empty() {
37        return Err(OpError {
38            kind: OpErrorKind::MissingSlot,
39            reason: "bundle_no_children",
40            detail: "composite.Bundle: at least one child input required".into(),
41        });
42    }
43    let mut children: Vec<Box<dyn SlotValue>> = Vec::with_capacity(inputs.len());
44    for (_slot_name, value) in inputs {
45        children.push(value.clone_boxed());
46    }
47    Ok(DispatchResult::Immediate(vec![(
48        PORT_BUNDLE.to_string(),
49        Box::new(CompositeValue { children }) as Box<dyn SlotValue>,
50    )]))
51}
52
53
54bb_derive::register_op! {
55    domain: "ai.bytesandbrains.composite",
56    op_type: "Bundle",
57    invoke: invoke,
58}