Skip to main content

bb_ops/syscalls/peers/
insert_many.rs

1//! `AddressBook::InsertMany(peer, addresses)` — custom op registered
2//! via `bb::register_op!` that pushes a full address bag into the
3//! engine's [`bb_runtime::framework::AddressBook`] from the data
4//! plane.
5//!
6//! Routes through `AddressBook::add_peer` for a new peer (entry
7//! created with `ref_count = 1`) and serially through
8//! `register_address` for a known peer (dedupe-append, no
9//! `ref_count` change — same semantics as `AddressBook::Insert`, just
10//! batched). Carriers are `TYPE_PEER_ID` and `TYPE_ADDRESS_VEC`.
11
12use bb_ir::proto::onnx::NodeProto;
13use bb_runtime::atomic::DispatchResult;
14use bb_runtime::bus::{OpError, OpErrorKind};
15use bb_runtime::framework::Address;
16use bb_runtime::ids::PeerId;
17use bb_runtime::runtime::RuntimeResourceRef;
18use bb_runtime::slot_value::SlotValue;
19use bb_runtime::syscall::values::{AddressVecValue, PeerIdValue};
20
21/// `(domain, op_type)` registration key.
22pub const DOMAIN: &str = "ai.bytesandbrains.address_book";
23/// Op type name.
24pub const OP_TYPE: &str = "InsertMany";
25
26/// Invoke fn — merge the address bag into the AddressBook.
27///
28/// New peer → `add_peer` with the full vec (entry created with
29/// `ref_count = 1`). Known peer → one `register_address` per address
30/// (idempotent append, no `ref_count` change). An empty input vec
31/// surfaces as `OpError` — graph-level intent to insert zero
32/// addresses is a wiring mistake.
33pub fn invoke(
34    _node: &NodeProto,
35    inputs: &[(&str, &dyn SlotValue)],
36    ctx: &mut RuntimeResourceRef<'_>,
37) -> Result<DispatchResult, OpError> {
38    let peer = downcast_peer(inputs)?;
39    let addresses = downcast_addresses(inputs)?;
40    if addresses.is_empty() {
41        return Err(OpError {
42            kind: OpErrorKind::ExecutionFailed,
43            reason: "address_book_insert_many_empty",
44            detail: "AddressBook::InsertMany: input `addresses` is empty".into(),
45        });
46    }
47    let result = if ctx.peers.addresses.lookup(peer).is_some() {
48        let mut last = Ok(());
49        for addr in addresses {
50            last = ctx.peers.addresses.register_address(peer, addr);
51            if last.is_err() {
52                break;
53            }
54        }
55        last
56    } else {
57        ctx.peers.addresses.add_peer(peer, addresses)
58    };
59    match result {
60        Ok(()) => Ok(DispatchResult::Immediate(Vec::new())),
61        Err(e) => Err(OpError {
62            kind: OpErrorKind::ExecutionFailed,
63            reason: "address_book_insert_many_failed",
64            detail: format!("AddressBook::InsertMany: {e}"),
65        }),
66    }
67}
68
69fn downcast_peer(inputs: &[(&str, &dyn SlotValue)]) -> Result<PeerId, OpError> {
70    let (_, value) = inputs
71        .iter()
72        .find(|(n, _)| *n == "peer")
73        .ok_or_else(|| OpError {
74            kind: OpErrorKind::MissingSlot,
75            reason: "missing_peer",
76            detail: "AddressBook::InsertMany: required input `peer` is absent".into(),
77        })?;
78    value
79        .as_any()
80        .downcast_ref::<PeerIdValue>()
81        .map(|p| p.0)
82        .ok_or_else(|| OpError {
83            kind: OpErrorKind::TypeMismatch,
84            reason: "expected_peer_id",
85            detail: "AddressBook::InsertMany: input `peer` is not a PeerId".into(),
86        })
87}
88
89fn downcast_addresses(inputs: &[(&str, &dyn SlotValue)]) -> Result<Vec<Address>, OpError> {
90    let (_, value) = inputs
91        .iter()
92        .find(|(n, _)| *n == "addresses")
93        .ok_or_else(|| OpError {
94            kind: OpErrorKind::MissingSlot,
95            reason: "missing_addresses",
96            detail: "AddressBook::InsertMany: required input `addresses` is absent".into(),
97        })?;
98    value
99        .as_any()
100        .downcast_ref::<AddressVecValue>()
101        .map(|a| a.0.clone())
102        .ok_or_else(|| OpError {
103            kind: OpErrorKind::TypeMismatch,
104            reason: "expected_address_vec",
105            detail: "AddressBook::InsertMany: input `addresses` is not an AddressVec".into(),
106        })
107}
108
109
110bb_derive::register_op! {
111    domain: "ai.bytesandbrains.address_book",
112    op_type: "InsertMany",
113    invoke: invoke,
114}