Skip to main content

sim_codec_lisp/implementation/
runtime.rs

1//! Runtime wiring for the Lisp codec: the `Lib` implementation that builds the
2//! manifest and registers the codec's decoder and encoder with the linker.
3
4use std::sync::Arc;
5
6use sim_codec::{CodecDefaultDecode, CodecRuntime, codec_value};
7use sim_kernel::{
8    AbiVersion, DefaultFactory, Dependency, Export, Lib, LibManifest, LibTarget, Linker, Result,
9    Symbol, Version,
10};
11
12use super::{
13    LispProcMacroDecoder, LispProcMacroEncoder,
14    cli::{LispCliEntrypoint, cli_main_symbol},
15};
16
17/// [`Lib`] that registers the Lisp codec with the runtime.
18///
19/// Its manifest exports the `codec/lisp` codec, and loading wires the
20/// [`LispProcMacroDecoder`] and [`LispProcMacroEncoder`] into the linker as the
21/// codec's decode and encode surfaces.
22pub struct LispCodecLib {
23    symbol: Symbol,
24    codec_id: sim_kernel::CodecId,
25}
26
27impl LispCodecLib {
28    /// Creates the codec lib bound to the runtime-assigned `id` for `codec/lisp`.
29    pub fn new(id: sim_kernel::CodecId) -> Result<Self> {
30        Ok(Self {
31            symbol: Symbol::qualified("codec", "lisp"),
32            codec_id: id,
33        })
34    }
35}
36
37impl Lib for LispCodecLib {
38    fn manifest(&self) -> LibManifest {
39        LibManifest {
40            id: self.symbol.clone(),
41            version: Version(env!("CARGO_PKG_VERSION").to_owned()),
42            abi: AbiVersion { major: 0, minor: 1 },
43            target: LibTarget::HostRegistered,
44            requires: Vec::<Dependency>::new(),
45            capabilities: Vec::new(),
46            exports: vec![
47                Export::Codec {
48                    symbol: self.symbol.clone(),
49                    codec_id: Some(self.codec_id),
50                },
51                Export::Function {
52                    symbol: cli_main_symbol(),
53                    function_id: None,
54                },
55            ],
56        }
57    }
58
59    fn load(&self, cx: &mut sim_kernel::LoadCx, linker: &mut Linker) -> Result<()> {
60        let _factory = DefaultFactory;
61        let expr_shape =
62            sim_codec::resolve_expr_shape(linker, &Symbol::qualified("codec", "LispSurface"))?;
63        let options_shape = sim_codec::resolve_options_shape(linker)?;
64        linker.codec_value(
65            self.symbol.clone(),
66            codec_value(CodecRuntime {
67                id: self.codec_id,
68                symbol: self.symbol.clone(),
69                decoder: Some(Arc::new(LispProcMacroDecoder)),
70                located_decoder: Some(Arc::new(LispProcMacroDecoder)),
71                tree_decoder: Some(Arc::new(LispProcMacroDecoder)),
72                encoder: Some(Arc::new(LispProcMacroEncoder)),
73                located_encoder: None,
74                tree_encoder: Some(Arc::new(LispProcMacroEncoder)),
75                expr_shape,
76                options_shape,
77                default_decode: CodecDefaultDecode::TermInEvalDatumOtherwise,
78            }),
79        )?;
80        linker.function_value(
81            cli_main_symbol(),
82            cx.factory().opaque(Arc::new(LispCliEntrypoint))?,
83        )?;
84        Ok(())
85    }
86}