sim_codec/implementation/
domain.rs1use std::sync::Arc;
10
11use sim_kernel::{
12 AbiVersion, CodecId, DefaultFactory, Dependency, Error, Export, Factory, Lib, LibManifest,
13 LibTarget, Linker, LoadCx, Result, ShapeRef, Symbol, Version,
14};
15
16use crate::{CodecDefaultDecode, CodecRuntime, Decoder, Encoder, Input, codec_value};
17
18pub fn domain_input_text(codec: CodecId, input: Input) -> Result<String> {
21 match input {
22 Input::Text(text) => Ok(text),
23 Input::Bytes(bytes) => String::from_utf8(bytes).map_err(|err| Error::CodecError {
24 codec,
25 message: format!("codec input is not valid UTF-8: {err}"),
26 }),
27 }
28}
29
30pub fn resolve_expr_shape(linker: &Linker, primary: &Symbol) -> Result<ShapeRef> {
35 let nil = DefaultFactory.nil()?;
36 Ok(linker
37 .registry()
38 .shape_by_symbol(primary)
39 .or_else(|| {
40 linker
41 .registry()
42 .shape_by_symbol(&Symbol::qualified("core", "Expr"))
43 })
44 .or_else(|| {
45 linker
46 .registry()
47 .shape_by_symbol(&Symbol::qualified("core", "Any"))
48 })
49 .cloned()
50 .unwrap_or(nil))
51}
52
53pub fn resolve_options_shape(linker: &Linker) -> Result<ShapeRef> {
56 let nil = DefaultFactory.nil()?;
57 Ok(linker
58 .registry()
59 .shape_by_symbol(&Symbol::qualified("core", "EncodeOptions"))
60 .or_else(|| {
61 linker
62 .registry()
63 .shape_by_symbol(&Symbol::qualified("core", "Any"))
64 })
65 .cloned()
66 .unwrap_or(nil))
67}
68
69pub struct DomainCodecLib {
72 symbol: Symbol,
73 codec_id: CodecId,
74 decoder: Arc<dyn Decoder>,
75 encoder: Arc<dyn Encoder>,
76 expr_shape_symbol: Symbol,
77 shapes: Vec<(Symbol, ShapeRef)>,
78}
79
80impl DomainCodecLib {
81 pub fn new(
85 symbol: Symbol,
86 codec_id: CodecId,
87 decoder: Arc<dyn Decoder>,
88 encoder: Arc<dyn Encoder>,
89 expr_shape_symbol: Symbol,
90 ) -> Self {
91 Self {
92 symbol,
93 codec_id,
94 decoder,
95 encoder,
96 expr_shape_symbol,
97 shapes: Vec::new(),
98 }
99 }
100
101 pub fn with_shapes(mut self, shapes: Vec<(Symbol, ShapeRef)>) -> Self {
104 self.shapes = shapes;
105 self
106 }
107}
108
109impl Lib for DomainCodecLib {
110 fn manifest(&self) -> LibManifest {
111 let mut exports: Vec<Export> = self
112 .shapes
113 .iter()
114 .map(|(symbol, _)| Export::Shape {
115 symbol: symbol.clone(),
116 shape_id: None,
117 })
118 .collect();
119 exports.push(Export::Codec {
120 symbol: self.symbol.clone(),
121 codec_id: Some(self.codec_id),
122 });
123 LibManifest {
124 id: self.symbol.clone(),
125 version: Version(env!("CARGO_PKG_VERSION").to_owned()),
126 abi: AbiVersion { major: 0, minor: 1 },
127 target: LibTarget::HostRegistered,
128 requires: Vec::<Dependency>::new(),
129 capabilities: Vec::new(),
130 exports,
131 }
132 }
133
134 fn load(&self, _cx: &mut LoadCx, linker: &mut Linker<'_>) -> Result<()> {
135 for (symbol, shape) in &self.shapes {
136 linker.shape_value(symbol.clone(), shape.clone())?;
137 }
138 let nil = DefaultFactory.nil()?;
139 let expr_shape = self
140 .shapes
141 .iter()
142 .find(|(symbol, _)| symbol == &self.expr_shape_symbol)
143 .map(|(_, shape)| shape.clone())
144 .or_else(|| {
145 linker
146 .registry()
147 .shape_by_symbol(&self.expr_shape_symbol)
148 .cloned()
149 })
150 .or_else(|| {
151 linker
152 .registry()
153 .shape_by_symbol(&Symbol::qualified("core", "Expr"))
154 .cloned()
155 })
156 .or_else(|| {
157 linker
158 .registry()
159 .shape_by_symbol(&Symbol::qualified("core", "Any"))
160 .cloned()
161 })
162 .unwrap_or_else(|| nil.clone());
163 linker.codec_value(
164 self.symbol.clone(),
165 codec_value(CodecRuntime {
166 id: self.codec_id,
167 symbol: self.symbol.clone(),
168 decoder: Some(self.decoder.clone()),
169 located_decoder: None,
170 tree_decoder: None,
171 encoder: Some(self.encoder.clone()),
172 located_encoder: None,
173 tree_encoder: None,
174 expr_shape,
175 options_shape: nil,
176 default_decode: CodecDefaultDecode::Datum,
177 }),
178 )?;
179 Ok(())
180 }
181}