Skip to main content

bb_ops/syscalls/lifecycle/
mod.rs

1//! Lifecycle + bootstrap ops.
2//!
3//! - `LifecyclePhase(phase: int) → Trigger` - fires when
4//!   `Engine::fire_lifecycle(phase)` is called.
5//! - `BootstrapDispatch() → cmd` - mints a CommandId.
6//! - `BootstrapOutput(cmd) → Trigger` - awaits completion of the
7//!   matching CommandId.
8
9use bb_ir::proto::onnx::NodeProto;
10use bb_runtime::atomic::DispatchResult;
11use bb_runtime::bus::OpError;
12use bb_runtime::ids::CommandId;
13use bb_runtime::runtime::RuntimeResourceRef;
14use bb_runtime::slot_value::SlotValue;
15use bb_runtime::syscall::values::{CommandIdValue, TriggerValue};
16
17const DOMAIN: &str = "ai.bytesandbrains.syscall";
18
19/// Marker struct for dispatch_table TypeId keying.
20pub struct LifecyclePhaseOp;
21
22/// `LifecyclePhase(phase: string) → Trigger`. Phase-gated firing is
23/// enforced by the engine: only ops enrolled in
24/// `Engine.lifecycle_table[phase]` are pushed onto the frontier when
25/// `fire_lifecycle(phase)` runs, so this body only needs to emit the
26/// trigger when invoked. `Node` is the named consumer
27/// of `Engine::register_lifecycle_op`, parsing each node's `phase`
28/// attribute at install time.
29pub fn invoke_lifecycle_phase(
30    _node: &NodeProto,
31    _inputs: &[(&str, &dyn SlotValue)],
32    _ctx: &mut RuntimeResourceRef<'_>,
33) -> Result<DispatchResult, OpError> {
34    Ok(DispatchResult::Immediate(vec![(
35        "trigger".to_string(),
36        Box::new(TriggerValue),
37    )]))
38}
39
40/// Marker struct for dispatch_table TypeId keying.
41pub struct BootstrapDispatchOp;
42
43/// `BootstrapDispatch() → cmd`.
44pub fn invoke_bootstrap_dispatch(
45    _node: &NodeProto,
46    _inputs: &[(&str, &dyn SlotValue)],
47    ctx: &mut RuntimeResourceRef<'_>,
48) -> Result<DispatchResult, OpError> {
49    let cmd = ctx.allocate_command_id();
50    Ok(DispatchResult::Immediate(vec![(
51        "cmd".to_string(),
52        Box::new(CommandIdValue(bb_runtime::ids::CommandId::from(
53            cmd.as_u64(),
54        ))),
55    )]))
56}
57
58/// Marker struct for dispatch_table TypeId keying.
59pub struct BootstrapOutputOp;
60
61/// `BootstrapOutput(cmd) → Trigger`. Awaits the matching
62/// `BootstrapDispatch`'s `CommandId`. Reads the upstream `cmd`
63/// input (a `CommandIdValue`) and returns
64/// `DispatchResult::Async(cmd_id)` - the engine parks the op in
65/// `pending_async[cmd_id]` until the host completes the command
66/// via the ingress queue.
67pub fn invoke_bootstrap_output(
68    _node: &NodeProto,
69    inputs: &[(&str, &dyn SlotValue)],
70    _ctx: &mut RuntimeResourceRef<'_>,
71) -> Result<DispatchResult, OpError> {
72    let cmd_handle = inputs
73        .iter()
74        .find(|(name, _)| *name == "cmd")
75        .map(|(_, h)| *h)
76        .ok_or_else(|| OpError {
77            detail: "BootstrapOutput: missing `cmd` input".into(),
78            ..Default::default()
79        })?;
80    let cmd = cmd_handle
81        .as_any()
82        .downcast_ref::<CommandIdValue>()
83        .ok_or_else(|| OpError {
84            detail: "BootstrapOutput: `cmd` input is not a CommandIdValue".into(),
85            ..Default::default()
86        })?;
87    Ok(DispatchResult::Async(CommandId::new(cmd.0.as_u64())))
88}
89
90#[cfg(test)]
91#[path = "tests.rs"]
92mod tests;
93
94/// Linker-anchor - see `bb_ops::link_force` for details.
95pub fn link_force() {
96    use std::hint::black_box;
97    black_box(invoke_lifecycle_phase as usize);
98    black_box(invoke_bootstrap_dispatch as usize);
99    black_box(invoke_bootstrap_output as usize);
100}
101
102use bb_runtime::registry::OpRegistration as _BbOpsSyscallReg;
103
104inventory::submit! {
105    _BbOpsSyscallReg {
106        domain: DOMAIN,
107        op_type: "LifecyclePhase",
108        invoke: invoke_lifecycle_phase,
109        kind: bb_runtime::registry::RegistrationKind::Syscall,
110    }
111}
112
113inventory::submit! {
114    _BbOpsSyscallReg {
115        domain: DOMAIN,
116        op_type: "BootstrapDispatch",
117        invoke: invoke_bootstrap_dispatch,
118        kind: bb_runtime::registry::RegistrationKind::Syscall,
119    }
120}
121
122inventory::submit! {
123    _BbOpsSyscallReg {
124        domain: DOMAIN,
125        op_type: "BootstrapOutput",
126        invoke: invoke_bootstrap_output,
127        kind: bb_runtime::registry::RegistrationKind::Syscall,
128    }
129}