Skip to main content

sim_lib_lang_clojure/
codec.rs

1use std::sync::Arc;
2
3use sim_codec::{
4    CodecDefaultDecode, CodecRuntime, Decoder, Input, LocatedDecoder, ReadCx, TreeDecoder,
5    codec_value,
6};
7use sim_kernel::{
8    AbiVersion, CodecId, DefaultFactory, Dependency, Export, Lib, LibManifest, LibTarget, Linker,
9    LocatedExpr, LocatedExprTree, Result, Symbol, Version,
10};
11
12use crate::{clojure_edn_reader_symbol, decode_clojure_edn_tree};
13
14/// Decoder that reads Clojure/EDN surface syntax into the shared [`Expr`](sim_kernel::Expr) graph.
15///
16/// Implements the kernel [`Decoder`], [`LocatedDecoder`], and [`TreeDecoder`]
17/// contracts; this profile only decodes (surface -> `Expr`) and registers no
18/// encoder. See the [crate] README for the language-profile role.
19pub struct ClojureEdnCodec;
20
21impl Decoder for ClojureEdnCodec {
22    fn decode(&self, cx: &mut ReadCx<'_>, input: Input) -> Result<sim_kernel::Expr> {
23        decode_clojure_edn_tree(cx, "clojure-edn", input).map(|tree| tree.expr)
24    }
25}
26
27impl LocatedDecoder for ClojureEdnCodec {
28    fn decode_located(
29        &self,
30        cx: &mut ReadCx<'_>,
31        input: Input,
32        source_id: String,
33    ) -> Result<LocatedExpr> {
34        decode_clojure_edn_tree(cx, source_id, input).map(|tree| tree.located())
35    }
36}
37
38impl TreeDecoder for ClojureEdnCodec {
39    fn decode_tree(
40        &self,
41        cx: &mut ReadCx<'_>,
42        input: Input,
43        source_id: String,
44    ) -> Result<LocatedExprTree> {
45        decode_clojure_edn_tree(cx, source_id, input)
46    }
47}
48
49/// Loadable [`Lib`] that registers the [`ClojureEdnCodec`] as a runtime codec object.
50///
51/// Exports a single [`Export::Codec`] under [`clojure_edn_reader_symbol`] and
52/// installs it via the [`Linker`] when loaded.
53///
54/// # Examples
55///
56/// Load the codec and decode a small EDN form into the shared `Expr` graph:
57///
58/// ```
59/// use std::sync::Arc;
60/// use sim_codec::{Input, decode_tree_with_codec};
61/// use sim_kernel::{
62///     CapabilitySet, Cx, DefaultFactory, Expr, NoopEvalPolicy, ReadPolicy, TrustLevel,
63/// };
64/// use sim_lib_lang_clojure::{ClojureEdnCodecLib, clojure_edn_reader_symbol};
65///
66/// let mut cx = Cx::new(Arc::new(NoopEvalPolicy), Arc::new(DefaultFactory));
67/// let codec_id = cx.registry_mut().fresh_codec_id();
68/// cx.load_lib(&ClojureEdnCodecLib::new(codec_id))?;
69///
70/// let policy = ReadPolicy {
71///     trust: TrustLevel::TrustedSource,
72///     capabilities: CapabilitySet::new(),
73/// };
74/// let tree = decode_tree_with_codec(
75///     &mut cx,
76///     &clojure_edn_reader_symbol(),
77///     Input::Text("[1 2 3]".to_owned()),
78///     policy,
79///     "doc.edn",
80/// )?;
81/// assert!(matches!(tree.expr, Expr::Vector(_)));
82/// # Ok::<(), sim_kernel::Error>(())
83/// ```
84pub struct ClojureEdnCodecLib {
85    symbol: Symbol,
86    codec_id: CodecId,
87}
88
89impl ClojureEdnCodecLib {
90    /// Builds the codec lib bound to the given runtime [`CodecId`].
91    pub fn new(id: CodecId) -> Self {
92        Self {
93            symbol: clojure_edn_reader_symbol(),
94            codec_id: id,
95        }
96    }
97}
98
99impl Lib for ClojureEdnCodecLib {
100    fn manifest(&self) -> LibManifest {
101        LibManifest {
102            id: self.symbol.clone(),
103            version: Version(env!("CARGO_PKG_VERSION").to_owned()),
104            abi: AbiVersion { major: 0, minor: 1 },
105            target: LibTarget::HostRegistered,
106            requires: Vec::<Dependency>::new(),
107            capabilities: Vec::new(),
108            exports: vec![Export::Codec {
109                symbol: self.symbol.clone(),
110                codec_id: Some(self.codec_id),
111            }],
112        }
113    }
114
115    fn load(&self, _cx: &mut sim_kernel::LoadCx, linker: &mut Linker<'_>) -> Result<()> {
116        let _factory = DefaultFactory;
117        let expr_shape = sim_codec::resolve_expr_shape(linker, &Symbol::qualified("core", "Expr"))?;
118        let options_shape = sim_codec::resolve_options_shape(linker)?;
119
120        linker.codec_value(
121            self.symbol.clone(),
122            codec_value(CodecRuntime {
123                id: self.codec_id,
124                symbol: self.symbol.clone(),
125                decoder: Some(Arc::new(ClojureEdnCodec)),
126                located_decoder: Some(Arc::new(ClojureEdnCodec)),
127                tree_decoder: Some(Arc::new(ClojureEdnCodec)),
128                encoder: None,
129                located_encoder: None,
130                tree_encoder: None,
131                expr_shape,
132                options_shape,
133                default_decode: CodecDefaultDecode::Datum,
134            }),
135        )?;
136        Ok(())
137    }
138}