Skip to main content

sim_codec_bridge/
canonical.rs

1use std::sync::Arc;
2
3use sim_codec::{
4    DecodeBudget, Decoder, DomainCodecLib, Encoder, Input, Output, ReadCx, domain_input_text,
5};
6use sim_kernel::{CodecId, Error, Expr, Lib, LibManifest, Linker, LoadCx, Result, Symbol, WriteCx};
7
8use crate::{
9    BridgeBook, decode_bridge_text_with_limits, encode_bridge_text, expr_to_packet, packet_to_expr,
10};
11
12/// The `codec:bridge` decoder/encoder.
13pub struct BridgeCodec;
14
15impl Decoder for BridgeCodec {
16    fn decode(&self, cx: &mut ReadCx<'_>, input: Input) -> Result<Expr> {
17        let source = domain_input_text(cx.codec, input)?;
18        let budget = DecodeBudget::new(cx.limits);
19        budget.check_input_bytes(cx.codec, source.len())?;
20        let packet =
21            decode_bridge_text_with_limits(&source, &BridgeBook::standard(), cx.codec, cx.limits)
22                .map_err(|err| Error::CodecError {
23                codec: cx.codec,
24                message: err.to_string(),
25            })?;
26        Ok(packet_to_expr(&packet))
27    }
28}
29
30impl Encoder for BridgeCodec {
31    fn encode(&self, cx: &mut WriteCx<'_>, expr: &Expr) -> Result<Output> {
32        let packet = expr_to_packet(expr).map_err(|err| Error::CodecError {
33            codec: cx.codec,
34            message: err.to_string(),
35        })?;
36        encode_bridge_text(&packet, &BridgeBook::standard())
37            .map(Output::Text)
38            .map_err(|err| Error::CodecError {
39                codec: cx.codec,
40                message: err.to_string(),
41            })
42    }
43}
44
45/// Host-registered lib that installs [`BridgeCodec`] as `codec:bridge`.
46pub struct BridgeCodecLib {
47    symbol: Symbol,
48    codec_id: CodecId,
49}
50
51impl BridgeCodecLib {
52    /// Creates a bridge codec lib for the given codec id.
53    pub fn new(id: CodecId) -> Self {
54        Self {
55            symbol: Symbol::qualified("codec", "bridge"),
56            codec_id: id,
57        }
58    }
59
60    fn domain_lib(&self) -> DomainCodecLib {
61        DomainCodecLib::new(
62            self.symbol.clone(),
63            self.codec_id,
64            Arc::new(BridgeCodec),
65            Arc::new(BridgeCodec),
66            crate::bridge_packet_shape_symbol(),
67        )
68    }
69}
70
71impl Lib for BridgeCodecLib {
72    fn manifest(&self) -> LibManifest {
73        self.domain_lib().manifest()
74    }
75
76    fn load(&self, cx: &mut LoadCx, linker: &mut Linker<'_>) -> Result<()> {
77        self.domain_lib().load(cx, linker)
78    }
79}