sim_lib_bridge/
materialize.rs1use sim_codec_bridge::{BridgePacket, BridgePart};
2use sim_kernel::{CapabilityName, Cx, Error, Expr, Result, Symbol};
3
4use crate::report::BridgeObligation;
5use crate::rx::effective_caps;
6
7#[derive(Clone, Debug, PartialEq)]
9pub struct GivenMaterialization {
10 pub id: Symbol,
12 pub payload: Expr,
14 pub remaining_budget: usize,
16}
17
18pub fn bridge_given_materialize_capability() -> CapabilityName {
20 CapabilityName::new("bridge/given.materialize")
21}
22
23pub fn bridge_fetch_capability() -> CapabilityName {
25 CapabilityName::new("bridge/fetch")
26}
27
28pub fn materialize_given(
30 cx: &mut Cx,
31 packet: &BridgePacket,
32 id: &Symbol,
33 budget: usize,
34) -> Result<GivenMaterialization> {
35 if budget == 0 {
36 return Err(Error::Eval(
37 "BRIDGE Given materialization budget exhausted".to_owned(),
38 ));
39 }
40 let caps = effective_caps(cx, packet)?;
41 if !caps.contains(&bridge_given_materialize_capability()) {
42 return Err(Error::CapabilityDenied {
43 capability: bridge_given_materialize_capability(),
44 });
45 }
46 let part = part_by_id(packet, id).ok_or_else(|| {
47 Error::Eval(format!(
48 "BRIDGE Given materialization missing part {}",
49 id.as_qualified_str()
50 ))
51 })?;
52 if part.kind != Symbol::qualified("bridge", "Given") {
53 return Err(Error::Eval(format!(
54 "BRIDGE materialization expects bridge/Given, found {}",
55 part.kind
56 )));
57 }
58 Ok(GivenMaterialization {
59 id: part.id.clone(),
60 payload: part.payload.clone(),
61 remaining_budget: budget - 1,
62 })
63}
64
65pub fn fetch_obligation(path: impl Into<String>, expected: impl Into<String>) -> BridgeObligation {
67 BridgeObligation::new(
68 path,
69 "typed context expansion requires Fetch",
70 expected,
71 "missing context",
72 vec![
73 "send Fetch packet".to_owned(),
74 "remove context reference".to_owned(),
75 ],
76 )
77}
78
79fn part_by_id<'a>(packet: &'a BridgePacket, id: &Symbol) -> Option<&'a BridgePart> {
80 packet.body.iter().find(|part| &part.id == id)
81}