Skip to main content

sim_codec_uds/
codec.rs

1//! Runtime codec registration.
2
3use std::sync::Arc;
4
5use sim_codec::{DecodeBudget, Decoder, DomainCodecLib, Encoder, Input, Output, ReadCx};
6use sim_kernel::{CodecId, Cx, Expr, Lib, LibManifest, Linker, LoadCx, Result, Symbol, WriteCx};
7
8use crate::{
9    expr::{expr_to_frame, frame_to_expr},
10    frame::{decode_frame, encode_frame},
11};
12
13/// Decoder and encoder for the `codec/uds` byte surface.
14#[derive(Clone, Copy, Debug, Default)]
15pub struct UdsCodec;
16
17impl Decoder for UdsCodec {
18    fn decode(&self, cx: &mut ReadCx<'_>, input: Input) -> Result<Expr> {
19        let bytes = match input {
20            Input::Bytes(bytes) => bytes,
21            Input::Text(text) => text.into_bytes(),
22        };
23        let budget = DecodeBudget::new(cx.limits);
24        budget.check_input_bytes(cx.codec, bytes.len())?;
25        decode_frame(cx.codec, &bytes).map(|frame| frame_to_expr(&frame))
26    }
27}
28
29impl Encoder for UdsCodec {
30    fn encode(&self, cx: &mut WriteCx<'_>, expr: &Expr) -> Result<Output> {
31        let frame = expr_to_frame(cx.codec, expr)?;
32        Ok(Output::Bytes(encode_frame(&frame)))
33    }
34}
35
36/// Host-registered library that installs `codec/uds`.
37pub struct UdsCodecLib {
38    symbol: Symbol,
39    codec_id: CodecId,
40}
41
42impl UdsCodecLib {
43    /// Creates a UDS codec lib for the given runtime codec id.
44    pub fn new(id: CodecId) -> Self {
45        Self {
46            symbol: uds_codec_symbol(),
47            codec_id: id,
48        }
49    }
50
51    fn domain_lib(&self) -> DomainCodecLib {
52        DomainCodecLib::new(
53            self.symbol.clone(),
54            self.codec_id,
55            Arc::new(UdsCodec),
56            Arc::new(UdsCodec),
57            Symbol::qualified("codec", "UdsFrame"),
58        )
59    }
60}
61
62impl Lib for UdsCodecLib {
63    fn manifest(&self) -> LibManifest {
64        self.domain_lib().manifest()
65    }
66
67    fn load(&self, cx: &mut LoadCx, linker: &mut Linker<'_>) -> Result<()> {
68        self.domain_lib().load(cx, linker)
69    }
70}
71
72/// Returns the runtime symbol for the UDS codec.
73pub fn uds_codec_symbol() -> Symbol {
74    Symbol::qualified("codec", "uds")
75}
76
77/// Installs `codec/uds` into a context once.
78pub fn install_uds_codec_lib(cx: &mut Cx) -> Result<()> {
79    if cx.registry().lib(&uds_codec_symbol()).is_some() {
80        return Ok(());
81    }
82    let id = cx.registry_mut().fresh_codec_id();
83    cx.load_lib(&UdsCodecLib::new(id)).map(|_| ())
84}