1use std::sync::Arc;
8
9use sim_kernel::{
10 Cx, Datum, DefaultFactory, Factory, LocatedExpr, LocatedExprTree, ReadPolicy, Result, Symbol,
11 Term, Value, WriteCx,
12};
13
14use crate::{
15 CodecDefaultDecode, CodecRuntime, DecodeLimits, DecodePosition, DecodeTarget, Input, Output,
16 ReadCx, encode_value_expr,
17};
18
19#[derive(Clone, Debug, PartialEq, Eq)]
26pub enum DecodedForm {
27 Datum(Datum),
29 Term(Term),
31}
32
33pub fn codec_value(codec: CodecRuntime) -> Value {
35 DefaultFactory
36 .opaque(Arc::new(codec))
37 .expect("codec runtime should always be boxable")
38}
39
40pub fn decode_with_codec(
45 cx: &mut Cx,
46 symbol: &Symbol,
47 input: Input,
48 read_policy: ReadPolicy,
49) -> Result<sim_kernel::Expr> {
50 decode_with_codec_and_limits(cx, symbol, input, read_policy, DecodeLimits::default())
51}
52
53pub fn decode_with_codec_and_limits(
55 cx: &mut Cx,
56 symbol: &Symbol,
57 input: Input,
58 read_policy: ReadPolicy,
59 limits: DecodeLimits,
60) -> Result<sim_kernel::Expr> {
61 decode_expr_with_codec_and_limits(cx, symbol, input, read_policy, limits).map(|(expr, _)| expr)
62}
63
64pub fn decode_datum_with_codec(
67 cx: &mut Cx,
68 symbol: &Symbol,
69 input: Input,
70 read_policy: ReadPolicy,
71) -> Result<Datum> {
72 decode_datum_with_codec_and_limits(cx, symbol, input, read_policy, DecodeLimits::default())
73}
74
75pub fn decode_datum_with_codec_and_limits(
78 cx: &mut Cx,
79 symbol: &Symbol,
80 input: Input,
81 read_policy: ReadPolicy,
82 limits: DecodeLimits,
83) -> Result<Datum> {
84 let (expr, _) = decode_expr_with_codec_and_limits(cx, symbol, input, read_policy, limits)?;
85 Datum::try_from(expr)
86}
87
88pub fn decode_term_with_codec(
91 cx: &mut Cx,
92 symbol: &Symbol,
93 input: Input,
94 read_policy: ReadPolicy,
95) -> Result<Term> {
96 decode_term_with_codec_and_limits(cx, symbol, input, read_policy, DecodeLimits::default())
97}
98
99pub fn decode_term_with_codec_and_limits(
102 cx: &mut Cx,
103 symbol: &Symbol,
104 input: Input,
105 read_policy: ReadPolicy,
106 limits: DecodeLimits,
107) -> Result<Term> {
108 let (expr, default_decode) =
109 decode_expr_with_codec_and_limits(cx, symbol, input, read_policy, limits)?;
110 term_from_expr(default_decode, expr)
111}
112
113pub fn decode_default_with_codec(
119 cx: &mut Cx,
120 symbol: &Symbol,
121 input: Input,
122 read_policy: ReadPolicy,
123 position: DecodePosition,
124) -> Result<DecodedForm> {
125 decode_default_with_codec_and_limits(
126 cx,
127 symbol,
128 input,
129 read_policy,
130 position,
131 DecodeLimits::default(),
132 )
133}
134
135pub fn decode_default_with_codec_and_limits(
138 cx: &mut Cx,
139 symbol: &Symbol,
140 input: Input,
141 read_policy: ReadPolicy,
142 position: DecodePosition,
143 limits: DecodeLimits,
144) -> Result<DecodedForm> {
145 let (expr, default_decode) =
146 decode_expr_with_codec_and_limits(cx, symbol, input, read_policy, limits)?;
147 match default_decode.target_for(position) {
148 DecodeTarget::Datum => Datum::try_from(expr).map(DecodedForm::Datum),
149 DecodeTarget::Term => term_from_expr(default_decode, expr).map(DecodedForm::Term),
150 }
151}
152
153fn decode_expr_with_codec_and_limits(
154 cx: &mut Cx,
155 symbol: &Symbol,
156 input: Input,
157 read_policy: ReadPolicy,
158 limits: DecodeLimits,
159) -> Result<(sim_kernel::Expr, CodecDefaultDecode)> {
160 let value = cx.resolve_codec(symbol)?;
161 let codec =
162 value
163 .object()
164 .downcast_ref::<CodecRuntime>()
165 .ok_or(sim_kernel::Error::TypeMismatch {
166 expected: "codec",
167 found: "non-codec",
168 })?;
169 let mut read_cx = ReadCx {
170 cx,
171 codec: codec.id,
172 read_policy,
173 limits,
174 };
175 codec
176 .decode(&mut read_cx, input)
177 .map(|expr| (expr, codec.default_decode))
178}
179
180pub fn encode_with_codec(
185 cx: &mut Cx,
186 symbol: &Symbol,
187 expr: &sim_kernel::Expr,
188 options: sim_kernel::EncodeOptions,
189) -> Result<Output> {
190 let value = cx.resolve_codec(symbol)?;
191 let codec =
192 value
193 .object()
194 .downcast_ref::<CodecRuntime>()
195 .ok_or(sim_kernel::Error::TypeMismatch {
196 expected: "codec",
197 found: "non-codec",
198 })?;
199 let mut write_cx = WriteCx {
200 cx,
201 codec: codec.id,
202 options,
203 };
204 codec.encode(&mut write_cx, expr)
205}
206
207pub fn encode_datum_with_codec(
210 cx: &mut Cx,
211 symbol: &Symbol,
212 datum: &Datum,
213 options: sim_kernel::EncodeOptions,
214) -> Result<Output> {
215 encode_with_codec(cx, symbol, &sim_kernel::Expr::from(datum.clone()), options)
216}
217
218pub fn encode_term_with_codec(
220 cx: &mut Cx,
221 symbol: &Symbol,
222 term: &Term,
223 options: sim_kernel::EncodeOptions,
224) -> Result<Output> {
225 encode_with_codec(cx, symbol, &sim_kernel::Expr::from(term.clone()), options)
226}
227
228pub fn encode_value_with_codec(
231 cx: &mut Cx,
232 symbol: &Symbol,
233 value: &Value,
234 options: sim_kernel::EncodeOptions,
235) -> Result<Output> {
236 let codec_value = cx.resolve_codec(symbol)?;
237 let codec = codec_value.object().downcast_ref::<CodecRuntime>().ok_or(
238 sim_kernel::Error::TypeMismatch {
239 expected: "codec",
240 found: "non-codec",
241 },
242 )?;
243 let mut write_cx = WriteCx {
244 cx,
245 codec: codec.id,
246 options,
247 };
248 let expr = encode_value_expr(&mut write_cx, value)?;
249 codec.encode(&mut write_cx, &expr)
250}
251
252pub fn decode_located_with_codec(
255 cx: &mut Cx,
256 symbol: &Symbol,
257 input: Input,
258 read_policy: ReadPolicy,
259 source_id: impl Into<String>,
260) -> Result<LocatedExpr> {
261 decode_located_with_codec_and_limits(
262 cx,
263 symbol,
264 input,
265 read_policy,
266 source_id,
267 DecodeLimits::default(),
268 )
269}
270
271pub fn decode_located_with_codec_and_limits(
274 cx: &mut Cx,
275 symbol: &Symbol,
276 input: Input,
277 read_policy: ReadPolicy,
278 source_id: impl Into<String>,
279 limits: DecodeLimits,
280) -> Result<LocatedExpr> {
281 let value = cx.resolve_codec(symbol)?;
282 let codec =
283 value
284 .object()
285 .downcast_ref::<CodecRuntime>()
286 .ok_or(sim_kernel::Error::TypeMismatch {
287 expected: "codec",
288 found: "non-codec",
289 })?;
290 let mut read_cx = ReadCx {
291 cx,
292 codec: codec.id,
293 read_policy,
294 limits,
295 };
296 codec.decode_located(&mut read_cx, input, source_id.into())
297}
298
299pub fn encode_located_with_codec(
302 cx: &mut Cx,
303 symbol: &Symbol,
304 expr: &LocatedExpr,
305 options: sim_kernel::EncodeOptions,
306) -> Result<Output> {
307 let value = cx.resolve_codec(symbol)?;
308 let codec =
309 value
310 .object()
311 .downcast_ref::<CodecRuntime>()
312 .ok_or(sim_kernel::Error::TypeMismatch {
313 expected: "codec",
314 found: "non-codec",
315 })?;
316 let mut write_cx = WriteCx {
317 cx,
318 codec: codec.id,
319 options,
320 };
321 codec.encode_located(&mut write_cx, expr)
322}
323
324pub fn encode_tree_with_codec(
327 cx: &mut Cx,
328 symbol: &Symbol,
329 expr: &LocatedExprTree,
330 options: sim_kernel::EncodeOptions,
331) -> Result<Output> {
332 let value = cx
333 .registry()
334 .codec_by_symbol(symbol)
335 .cloned()
336 .ok_or_else(|| sim_kernel::Error::Eval(format!("unknown codec {}", symbol)))?;
337 let codec = value
338 .object()
339 .as_any()
340 .downcast_ref::<CodecRuntime>()
341 .ok_or_else(|| sim_kernel::Error::Eval(format!("{} is not a codec runtime", symbol)))?;
342 let mut write_cx = WriteCx {
343 cx,
344 codec: codec.id,
345 options,
346 };
347 codec.encode_tree(&mut write_cx, expr)
348}
349
350pub fn decode_tree_with_codec(
353 cx: &mut Cx,
354 symbol: &Symbol,
355 input: Input,
356 read_policy: ReadPolicy,
357 source_id: impl Into<String>,
358) -> Result<LocatedExprTree> {
359 decode_tree_with_codec_and_limits(
360 cx,
361 symbol,
362 input,
363 read_policy,
364 source_id,
365 DecodeLimits::default(),
366 )
367}
368
369pub fn decode_tree_with_codec_and_limits(
372 cx: &mut Cx,
373 symbol: &Symbol,
374 input: Input,
375 read_policy: ReadPolicy,
376 source_id: impl Into<String>,
377 limits: DecodeLimits,
378) -> Result<LocatedExprTree> {
379 let value = cx.resolve_codec(symbol)?;
380 let codec =
381 value
382 .object()
383 .downcast_ref::<CodecRuntime>()
384 .ok_or(sim_kernel::Error::TypeMismatch {
385 expected: "codec",
386 found: "non-codec",
387 })?;
388 let mut read_cx = ReadCx {
389 cx,
390 codec: codec.id,
391 read_policy,
392 limits,
393 };
394 codec.decode_tree(&mut read_cx, input, source_id.into())
395}
396
397fn term_from_expr(default_decode: CodecDefaultDecode, expr: sim_kernel::Expr) -> Result<Term> {
398 match default_decode {
399 CodecDefaultDecode::Datum => Term::lower(expr),
400 CodecDefaultDecode::TermInEvalDatumOtherwise => Term::lower(lower_eval_surface(expr)),
401 }
402}
403
404fn lower_eval_surface(expr: sim_kernel::Expr) -> sim_kernel::Expr {
405 use sim_kernel::Expr;
406
407 match expr {
408 Expr::List(items) if items.len() > 1 => {
409 let mut items = items
410 .into_iter()
411 .map(lower_eval_surface)
412 .collect::<Vec<_>>();
413 let operator = Box::new(items.remove(0));
414 Expr::Call {
415 operator,
416 args: items,
417 }
418 }
419 Expr::List(items) => Expr::List(items.into_iter().map(lower_eval_surface).collect()),
420 Expr::Vector(items) => Expr::Vector(items.into_iter().map(lower_eval_surface).collect()),
421 Expr::Map(entries) => Expr::Map(
422 entries
423 .into_iter()
424 .map(|(key, value)| (lower_eval_surface(key), lower_eval_surface(value)))
425 .collect(),
426 ),
427 Expr::Set(items) => Expr::Set(items.into_iter().map(lower_eval_surface).collect()),
428 Expr::Block(items) => Expr::Block(items.into_iter().map(lower_eval_surface).collect()),
429 Expr::Quote { mode, expr } => Expr::Quote { mode, expr },
430 Expr::Annotated { expr, annotations } => Expr::Annotated {
431 expr: Box::new(lower_eval_surface(*expr)),
432 annotations: annotations
433 .into_iter()
434 .map(|(name, value)| (name, lower_eval_surface(value)))
435 .collect(),
436 },
437 Expr::Extension { tag, payload } => Expr::Extension {
438 tag,
439 payload: Box::new(lower_eval_surface(*payload)),
440 },
441 other => other,
442 }
443}