1use std::sync::Arc;
2
3use sim_codec_bridge::{BridgeBook, BridgeFramePayload, expr_to_packet, packet_to_expr};
4use sim_kernel::{
5 AbiVersion, Args, Callable, Cx, Error, Export, Lib, LibManifest, LibTarget, Linker, LoadCx,
6 Object, ObjectCompat, Result, Symbol, Value, Version,
7};
8use sim_shape::{AnyShape, ListShape, Shape, shape_value};
9
10use crate::{ask_packet, bridge_brief, bridge_tx, receipt_packet_for_report, rx_check};
11
12pub struct BridgeLib;
14
15impl Lib for BridgeLib {
16 fn manifest(&self) -> LibManifest {
17 LibManifest {
18 id: manifest_name(),
19 version: Version(env!("CARGO_PKG_VERSION").to_owned()),
20 abi: AbiVersion { major: 0, minor: 1 },
21 target: LibTarget::HostRegistered,
22 requires: Vec::new(),
23 capabilities: Vec::new(),
24 exports: bridge_exports(),
25 }
26 }
27
28 fn load(&self, cx: &mut LoadCx, linker: &mut Linker<'_>) -> Result<()> {
29 for kind in BridgeFunctionKind::ALL {
30 let function = BridgeFunction::value(kind);
31 linker.function_value(function.symbol(), cx.factory().opaque(function)?)?;
32 }
33 Ok(())
34 }
35}
36
37pub fn install_bridge_lib(cx: &mut Cx) -> Result<()> {
39 cx.load_lib(&BridgeLib).map(|_| ())
40}
41
42pub fn manifest_name() -> Symbol {
44 Symbol::qualified("sim", "bridge")
45}
46
47pub fn bridge_tx_symbol() -> Symbol {
49 Symbol::qualified("bridge", "tx")
50}
51
52pub fn bridge_rx_symbol() -> Symbol {
54 Symbol::qualified("bridge", "rx")
55}
56
57pub fn bridge_report_symbol() -> Symbol {
59 Symbol::qualified("bridge", "report")
60}
61
62pub fn bridge_brief_symbol() -> Symbol {
64 Symbol::qualified("bridge", "brief")
65}
66
67pub fn bridge_ask_symbol() -> Symbol {
69 Symbol::qualified("bridge", "ask")
70}
71
72fn bridge_exports() -> Vec<Export> {
73 BridgeFunctionKind::ALL
74 .iter()
75 .map(|kind| Export::Function {
76 symbol: kind.symbol(),
77 function_id: None,
78 })
79 .collect()
80}
81
82#[derive(Clone, Copy, Debug, PartialEq, Eq)]
84pub enum BridgeFunctionKind {
85 Tx,
87 Rx,
89 Report,
91 Receipt,
93 Brief,
95 Ask,
97}
98
99impl BridgeFunctionKind {
100 pub const ALL: [Self; 6] = [
102 Self::Tx,
103 Self::Rx,
104 Self::Report,
105 Self::Receipt,
106 Self::Brief,
107 Self::Ask,
108 ];
109
110 pub fn symbol(self) -> Symbol {
112 match self {
113 Self::Tx => bridge_tx_symbol(),
114 Self::Rx => bridge_rx_symbol(),
115 Self::Report => bridge_report_symbol(),
116 Self::Receipt => crate::receipt_symbol(),
117 Self::Brief => bridge_brief_symbol(),
118 Self::Ask => bridge_ask_symbol(),
119 }
120 }
121}
122
123#[derive(Clone)]
125pub struct BridgeFunction {
126 kind: BridgeFunctionKind,
127}
128
129impl BridgeFunction {
130 pub fn new(kind: BridgeFunctionKind) -> Self {
132 Self { kind }
133 }
134
135 pub fn symbol(&self) -> Symbol {
137 self.kind.symbol()
138 }
139
140 pub fn value(kind: BridgeFunctionKind) -> Arc<Self> {
142 Arc::new(Self::new(kind))
143 }
144}
145
146impl Object for BridgeFunction {
147 fn display(&self, _cx: &mut Cx) -> Result<String> {
148 Ok(format!("#<function {}>", self.symbol()))
149 }
150
151 fn as_any(&self) -> &dyn std::any::Any {
152 self
153 }
154}
155
156impl ObjectCompat for BridgeFunction {
157 fn as_callable(&self) -> Option<&dyn Callable> {
158 Some(self)
159 }
160}
161
162impl Callable for BridgeFunction {
163 fn call(&self, cx: &mut Cx, args: Args) -> Result<Value> {
164 match self.kind {
165 BridgeFunctionKind::Tx => call_tx(cx, args),
166 BridgeFunctionKind::Rx => call_rx(cx, args),
167 BridgeFunctionKind::Report => call_report(cx, args),
168 BridgeFunctionKind::Receipt => call_receipt(cx, args),
169 BridgeFunctionKind::Brief => call_brief(cx, args),
170 BridgeFunctionKind::Ask => call_ask(cx, args),
171 }
172 }
173
174 fn browse_args_shape(&self, _cx: &mut Cx) -> Result<Option<sim_kernel::ShapeRef>> {
175 let shape: Arc<dyn Shape> = match self.kind {
176 BridgeFunctionKind::Tx | BridgeFunctionKind::Report => {
177 Arc::new(ListShape::new(vec![Arc::new(AnyShape)]))
178 }
179 BridgeFunctionKind::Rx => Arc::new(ListShape::new(vec![Arc::new(AnyShape)])),
180 BridgeFunctionKind::Receipt => Arc::new(ListShape::new(vec![Arc::new(AnyShape)])),
181 BridgeFunctionKind::Brief => Arc::new(ListShape::new(vec![
182 Arc::new(AnyShape),
183 Arc::new(AnyShape),
184 Arc::new(AnyShape),
185 ])),
186 BridgeFunctionKind::Ask => Arc::new(ListShape::new(vec![
187 Arc::new(AnyShape),
188 Arc::new(AnyShape),
189 Arc::new(AnyShape),
190 Arc::new(AnyShape),
191 ])),
192 };
193 Ok(Some(shape_value(
194 Symbol::qualified(self.symbol().to_string(), "args"),
195 shape,
196 )))
197 }
198
199 fn browse_result_shape(&self, _cx: &mut Cx) -> Result<Option<sim_kernel::ShapeRef>> {
200 Ok(Some(shape_value(
201 Symbol::qualified(self.symbol().to_string(), "result"),
202 Arc::new(AnyShape),
203 )))
204 }
205}
206
207fn call_tx(cx: &mut Cx, args: Args) -> Result<Value> {
208 let packet = packet_arg(cx, args, "bridge/tx expects one packet expression")?;
209 let request = bridge_tx(cx, &BridgeBook::standard(), &packet)?;
210 cx.factory().opaque(Arc::new(request))
211}
212
213fn call_rx(cx: &mut Cx, args: Args) -> Result<Value> {
214 let response = one_expr_arg(cx, args, "bridge/rx expects one model response expression")?;
215 let (packet, report) = crate::bridge_rx(cx, &BridgeBook::standard(), response, None)?;
216 cx.factory().expr(sim_kernel::Expr::Map(vec![
217 sim_value::build::entry("packet", packet_to_expr(&packet)),
218 sim_value::build::entry("report", report.to_expr()),
219 ]))
220}
221
222fn call_report(cx: &mut Cx, args: Args) -> Result<Value> {
223 let packet = packet_arg(cx, args, "bridge/report expects one packet expression")?;
224 let report = rx_check(cx, &BridgeBook::standard(), &packet, None)?;
225 cx.factory().expr(report.to_expr())
226}
227
228fn call_receipt(cx: &mut Cx, args: Args) -> Result<Value> {
229 let packet = packet_arg(cx, args, "bridge/receipt expects one packet expression")?;
230 let report = rx_check(cx, &BridgeBook::standard(), &packet, None)?;
231 let receipt = receipt_packet_for_report(&report, "sim")?;
232 cx.factory().expr(packet_to_expr(&receipt))
233}
234
235fn call_brief(cx: &mut Cx, args: Args) -> Result<Value> {
236 let mut exprs = expr_args(
237 cx,
238 args,
239 "bridge/brief expects target, frame, and return shape",
240 )?;
241 let [target, frame, return_shape] = take_three(&mut exprs)?;
242 let frame = BridgeFramePayload::from_expr(&frame)?;
243 let packet = bridge_brief(&target_name(&target)?, frame, return_shape)?;
244 cx.factory().expr(packet_to_expr(&packet))
245}
246
247fn call_ask(cx: &mut Cx, args: Args) -> Result<Value> {
248 let mut exprs = expr_args(
249 cx,
250 args,
251 "bridge/ask expects target, call, params, and return shape",
252 )?;
253 if exprs.len() != 4 {
254 return Err(Error::Eval(format!(
255 "bridge/ask expects 4 argument(s), found {}",
256 exprs.len()
257 )));
258 }
259 let return_shape = exprs.pop().expect("length checked");
260 let params = exprs.pop().expect("length checked");
261 let call = exprs.pop().expect("length checked");
262 let target = exprs.pop().expect("length checked");
263 let packet = ask_packet(
264 cx,
265 &call_name(&call)?,
266 call_params(¶ms)?,
267 return_shape,
268 &target_name(&target)?,
269 )?;
270 cx.factory().expr(packet_to_expr(&packet))
271}
272
273fn packet_arg(
274 cx: &mut Cx,
275 args: Args,
276 message: &'static str,
277) -> Result<sim_codec_bridge::BridgePacket> {
278 expr_to_packet(&one_expr_arg(cx, args, message)?)
279}
280
281fn expr_args(cx: &mut Cx, args: Args, message: &'static str) -> Result<Vec<sim_kernel::Expr>> {
282 let values = args.into_vec();
283 if values.is_empty() {
284 return Err(Error::Eval(message.to_owned()));
285 }
286 values
287 .into_iter()
288 .map(|value| value.object().as_expr(cx))
289 .collect()
290}
291
292fn one_expr_arg(cx: &mut Cx, args: Args, message: &'static str) -> Result<sim_kernel::Expr> {
293 let mut values = args.into_vec();
294 if values.len() != 1 {
295 return Err(Error::Eval(message.to_owned()));
296 }
297 values.remove(0).object().as_expr(cx)
298}
299
300fn take_three(exprs: &mut Vec<sim_kernel::Expr>) -> Result<[sim_kernel::Expr; 3]> {
301 let [target, frame, return_shape] =
302 std::mem::take(exprs).try_into().map_err(|values: Vec<_>| {
303 Error::Eval(format!(
304 "bridge/brief expects 3 argument(s), found {}",
305 values.len()
306 ))
307 })?;
308 Ok([target, frame, return_shape])
309}
310
311fn target_name(expr: &sim_kernel::Expr) -> Result<String> {
312 match expr {
313 sim_kernel::Expr::String(target) => Ok(target.clone()),
314 sim_kernel::Expr::Symbol(target) => Ok(target.as_qualified_str().to_owned()),
315 _ => Err(Error::Eval(
316 "bridge/brief target must be a string or symbol".to_owned(),
317 )),
318 }
319}
320
321fn call_name(expr: &sim_kernel::Expr) -> Result<String> {
322 match expr {
323 sim_kernel::Expr::String(name) => Ok(name.clone()),
324 sim_kernel::Expr::Symbol(name) => Ok(name.as_qualified_str()),
325 _ => Err(Error::Eval(
326 "bridge/ask call must be a string or symbol".to_owned(),
327 )),
328 }
329}
330
331fn call_params(expr: &sim_kernel::Expr) -> Result<Vec<(String, sim_kernel::Expr)>> {
332 let sim_kernel::Expr::Map(entries) = expr else {
333 return Err(Error::Eval("bridge/ask params must be a map".to_owned()));
334 };
335 entries
336 .iter()
337 .map(|(key, value)| {
338 let name = match key {
339 sim_kernel::Expr::String(name) => name.clone(),
340 sim_kernel::Expr::Symbol(name) => name.as_qualified_str(),
341 _ => {
342 return Err(Error::Eval(
343 "bridge/ask param keys must be strings or symbols".to_owned(),
344 ));
345 }
346 };
347 Ok((name, value.clone()))
348 })
349 .collect()
350}