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