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}