1use std::sync::Arc;
11
12use sim_codec::{
13 Decoder, DomainCodecLib, Encoder, Input, Output, ReadCx, decode_portable, domain_input_text,
14 encode_portable,
15};
16use sim_kernel::{CodecId, Error, Lib, LibManifest, Linker, LoadCx, Result, Symbol, WriteCx};
17use sim_shape::shape_value;
18
19use crate::model::validate_intent;
20use crate::shapes::{intent_shape_specs, intent_shape_symbol};
21
22pub fn intent_codec_symbol() -> Symbol {
24 Symbol::qualified("codec", "intent")
25}
26
27pub struct IntentCodec;
29
30impl Decoder for IntentCodec {
31 fn decode(&self, cx: &mut ReadCx<'_>, input: Input) -> Result<sim_kernel::Expr> {
32 let source = domain_input_text(cx.codec, input)?;
33 let expr = decode_portable(cx.codec, &source)?;
34 validate(cx.codec, &expr)?;
35 Ok(expr)
36 }
37}
38
39impl Encoder for IntentCodec {
40 fn encode(&self, cx: &mut WriteCx<'_>, expr: &sim_kernel::Expr) -> Result<Output> {
41 validate(cx.codec, expr)?;
42 Ok(Output::Text(encode_portable(cx.codec, expr)?))
43 }
44}
45
46fn validate(codec: CodecId, expr: &sim_kernel::Expr) -> Result<()> {
47 validate_intent(expr).map_err(|error| Error::CodecError {
48 codec,
49 message: format!("malformed intent at {error}"),
50 })
51}
52
53pub struct IntentCodecLib {
55 symbol: Symbol,
56 codec_id: CodecId,
57}
58
59impl IntentCodecLib {
60 pub fn new(codec_id: CodecId) -> Self {
62 Self {
63 symbol: intent_codec_symbol(),
64 codec_id,
65 }
66 }
67
68 fn domain_lib(&self) -> DomainCodecLib {
69 let shapes = intent_shape_specs()
70 .into_iter()
71 .map(|(symbol, shape)| (symbol.clone(), shape_value(symbol, shape)))
72 .collect();
73 DomainCodecLib::new(
74 self.symbol.clone(),
75 self.codec_id,
76 Arc::new(IntentCodec),
77 Arc::new(IntentCodec),
78 intent_shape_symbol(),
79 )
80 .with_shapes(shapes)
81 }
82}
83
84impl Lib for IntentCodecLib {
85 fn manifest(&self) -> LibManifest {
86 self.domain_lib().manifest()
87 }
88
89 fn load(&self, cx: &mut LoadCx, linker: &mut Linker<'_>) -> Result<()> {
90 self.domain_lib().load(cx, linker)
91 }
92}