Skip to main content

bb_runtime/engine/
dispatch_entry.rs

1//! Engine dispatch types
2//!
3//! `OpDispatch` is the install-time pre-stamped per-OpRef dispatch
4//! kind. Each `GraphSlot.op_dispatch[i]` carries one of these,
5//! resolved once by `Engine::resolve_dispatch` so runtime invoke is
6//! one indirect lookup with no HashMap probes on hot path.
7
8use std::rc::Rc;
9
10use crate::atomic::DispatchResult;
11use crate::bus::OpError;
12use crate::engine::invoke::ProtocolDispatchFn;
13use crate::ids::ComponentRef;
14use crate::runtime::RuntimeResourceRef;
15use crate::slot_value::SlotValue;
16use bb_ir::proto::onnx::NodeProto;
17
18/// Stateless syscall invoke fn pointer
19/// Same input/output shape as a role-trait `dispatch_atomic` call;
20/// returns `DispatchResult` for uniform handling by `invoke_one`.
21pub type StatelessInvokeFn = fn(
22    node: &NodeProto,
23    inputs: &[(&str, &dyn SlotValue)],
24    ctx: &mut RuntimeResourceRef<'_>,
25) -> Result<DispatchResult, OpError>;
26
27/// Canonical key for a `FunctionProto` in `Node.model.functions[]`.
28/// Matches ONNX's `(domain, name, overload)` tuple - the linker
29/// dedupes on this key.
30pub type FunctionKey = (String, String, String);
31
32/// Per-OpRef dispatch decision, pre-stamped at install time by
33/// `Engine::resolve_dispatch`. Runtime invoke is one indirect probe
34/// against `GraphSlot.op_dispatch[idx]`. Four variants:
35///
36/// - `Stateless` - framework syscall.
37/// - `Atomic` - bound runtime's `dispatch_atomic`.
38/// - `FunctionCall` - splice into another installed function's body
39///   via shared `OpRef`s, with input/output rename for call-frame
40///   semantics. See `docs/ENGINE.md` §8.4.
41/// - `Unresolved` - sentinel for nodes whose dispatch couldn't be
42///   resolved at install. Build fails if any survive.
43#[derive(Clone, Debug)]
44pub enum OpDispatch {
45    /// Framework syscall.
46    Stateless(StatelessInvokeFn),
47
48    /// Bound runtime impl, routed via `components[component_ref]`.
49    /// `dispatch_fn` is the install-time-stamped downcast closure
50    /// from `Engine::role_dispatchers[component_type_id]`. Runtime
51    /// invoke calls the closure directly; resolve_dispatch only
52    /// stamps `Atomic` when the closure is available, otherwise it
53    /// stamps `Unresolved`. Test fixtures that bypass install
54    /// stamp the closure manually via `bind_slot_id` +
55    /// `register_<role>_dispatcher` before `resolve_dispatch`.
56    Atomic {
57        /// `ComponentRef` of the bound impl.
58        component_ref: ComponentRef,
59        /// Pre-stamped downcast closure that calls the concrete
60        /// `<Role>Runtime::dispatch_atomic` on the bound component.
61        dispatch_fn: ProtocolDispatchFn,
62    },
63
64    /// Function-call to another installed function. `target` keys
65    /// into `engine.graphs` (the symbol table); `input_rename` /
66    /// `output_rename` map caller-side ↔ formal value names.
67    FunctionCall {
68        /// `(domain, name, overload)` of the called function.
69        target: FunctionKey,
70        /// Pairs `(caller_value_name, formal_parameter_name)` zipped
71        /// from this call NodeProto's `input` against the target
72        /// function's `input` list.
73        input_rename: Rc<[(String, String)]>,
74        /// Pairs `(formal_output_name, caller_value_name)` zipped
75        /// from the target function's `output` against this call's
76        /// `output` list. Resolved into `output_forwarding` site-id
77        /// pairs at install time.
78        output_rename: Rc<[(String, String)]>,
79    },
80
81    /// Sentinel for unresolved dispatch - set by `from_function`
82    /// before resolve, replaced by `resolve_dispatch`. Build fails if
83    /// any survive past resolution.
84    Unresolved,
85}