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_eval_expr_with_codec(
127 cx: &mut Cx,
128 symbol: &Symbol,
129 input: Input,
130 read_policy: ReadPolicy,
131) -> Result<sim_kernel::Expr> {
132 decode_eval_expr_with_codec_and_limits(cx, symbol, input, read_policy, DecodeLimits::default())
133}
134
135pub fn decode_eval_expr_with_codec_and_limits(
137 cx: &mut Cx,
138 symbol: &Symbol,
139 input: Input,
140 read_policy: ReadPolicy,
141 limits: DecodeLimits,
142) -> Result<sim_kernel::Expr> {
143 let (expr, default_decode) =
144 decode_expr_with_codec_and_limits(cx, symbol, input, read_policy, limits)?;
145 Ok(match default_decode {
146 CodecDefaultDecode::Datum => expr,
147 CodecDefaultDecode::TermInEvalDatumOtherwise => lower_eval_surface(expr),
148 })
149}
150
151pub fn decode_default_with_codec(
157 cx: &mut Cx,
158 symbol: &Symbol,
159 input: Input,
160 read_policy: ReadPolicy,
161 position: DecodePosition,
162) -> Result<DecodedForm> {
163 decode_default_with_codec_and_limits(
164 cx,
165 symbol,
166 input,
167 read_policy,
168 position,
169 DecodeLimits::default(),
170 )
171}
172
173pub fn decode_default_with_codec_and_limits(
176 cx: &mut Cx,
177 symbol: &Symbol,
178 input: Input,
179 read_policy: ReadPolicy,
180 position: DecodePosition,
181 limits: DecodeLimits,
182) -> Result<DecodedForm> {
183 let (expr, default_decode) =
184 decode_expr_with_codec_and_limits(cx, symbol, input, read_policy, limits)?;
185 match default_decode.target_for(position) {
186 DecodeTarget::Datum => Datum::try_from(expr).map(DecodedForm::Datum),
187 DecodeTarget::Term => term_from_expr(default_decode, expr).map(DecodedForm::Term),
188 }
189}
190
191fn decode_expr_with_codec_and_limits(
192 cx: &mut Cx,
193 symbol: &Symbol,
194 input: Input,
195 read_policy: ReadPolicy,
196 limits: DecodeLimits,
197) -> Result<(sim_kernel::Expr, CodecDefaultDecode)> {
198 let value = cx.resolve_codec(symbol)?;
199 let codec =
200 value
201 .object()
202 .downcast_ref::<CodecRuntime>()
203 .ok_or(sim_kernel::Error::TypeMismatch {
204 expected: "codec",
205 found: "non-codec",
206 })?;
207 let mut read_cx = ReadCx {
208 cx,
209 codec: codec.id,
210 read_policy,
211 limits,
212 };
213 codec
214 .decode(&mut read_cx, input)
215 .map(|expr| (expr, codec.default_decode))
216}
217
218pub fn encode_with_codec(
223 cx: &mut Cx,
224 symbol: &Symbol,
225 expr: &sim_kernel::Expr,
226 options: sim_kernel::EncodeOptions,
227) -> Result<Output> {
228 let value = cx.resolve_codec(symbol)?;
229 let codec =
230 value
231 .object()
232 .downcast_ref::<CodecRuntime>()
233 .ok_or(sim_kernel::Error::TypeMismatch {
234 expected: "codec",
235 found: "non-codec",
236 })?;
237 let mut write_cx = WriteCx {
238 cx,
239 codec: codec.id,
240 options,
241 };
242 codec.encode(&mut write_cx, expr)
243}
244
245pub fn encode_datum_with_codec(
248 cx: &mut Cx,
249 symbol: &Symbol,
250 datum: &Datum,
251 options: sim_kernel::EncodeOptions,
252) -> Result<Output> {
253 encode_with_codec(cx, symbol, &sim_kernel::Expr::from(datum.clone()), options)
254}
255
256pub fn encode_term_with_codec(
258 cx: &mut Cx,
259 symbol: &Symbol,
260 term: &Term,
261 options: sim_kernel::EncodeOptions,
262) -> Result<Output> {
263 encode_with_codec(cx, symbol, &sim_kernel::Expr::from(term.clone()), options)
264}
265
266pub fn encode_value_with_codec(
269 cx: &mut Cx,
270 symbol: &Symbol,
271 value: &Value,
272 options: sim_kernel::EncodeOptions,
273) -> Result<Output> {
274 let codec_value = cx.resolve_codec(symbol)?;
275 let codec = codec_value.object().downcast_ref::<CodecRuntime>().ok_or(
276 sim_kernel::Error::TypeMismatch {
277 expected: "codec",
278 found: "non-codec",
279 },
280 )?;
281 let mut write_cx = WriteCx {
282 cx,
283 codec: codec.id,
284 options,
285 };
286 let expr = encode_value_expr(&mut write_cx, value)?;
287 codec.encode(&mut write_cx, &expr)
288}
289
290pub fn decode_located_with_codec(
293 cx: &mut Cx,
294 symbol: &Symbol,
295 input: Input,
296 read_policy: ReadPolicy,
297 source_id: impl Into<String>,
298) -> Result<LocatedExpr> {
299 decode_located_with_codec_and_limits(
300 cx,
301 symbol,
302 input,
303 read_policy,
304 source_id,
305 DecodeLimits::default(),
306 )
307}
308
309pub fn decode_located_with_codec_and_limits(
312 cx: &mut Cx,
313 symbol: &Symbol,
314 input: Input,
315 read_policy: ReadPolicy,
316 source_id: impl Into<String>,
317 limits: DecodeLimits,
318) -> Result<LocatedExpr> {
319 let value = cx.resolve_codec(symbol)?;
320 let codec =
321 value
322 .object()
323 .downcast_ref::<CodecRuntime>()
324 .ok_or(sim_kernel::Error::TypeMismatch {
325 expected: "codec",
326 found: "non-codec",
327 })?;
328 let mut read_cx = ReadCx {
329 cx,
330 codec: codec.id,
331 read_policy,
332 limits,
333 };
334 codec.decode_located(&mut read_cx, input, source_id.into())
335}
336
337pub fn encode_located_with_codec(
340 cx: &mut Cx,
341 symbol: &Symbol,
342 expr: &LocatedExpr,
343 options: sim_kernel::EncodeOptions,
344) -> Result<Output> {
345 let value = cx.resolve_codec(symbol)?;
346 let codec =
347 value
348 .object()
349 .downcast_ref::<CodecRuntime>()
350 .ok_or(sim_kernel::Error::TypeMismatch {
351 expected: "codec",
352 found: "non-codec",
353 })?;
354 let mut write_cx = WriteCx {
355 cx,
356 codec: codec.id,
357 options,
358 };
359 codec.encode_located(&mut write_cx, expr)
360}
361
362pub fn encode_tree_with_codec(
365 cx: &mut Cx,
366 symbol: &Symbol,
367 expr: &LocatedExprTree,
368 options: sim_kernel::EncodeOptions,
369) -> Result<Output> {
370 let value = cx
371 .registry()
372 .codec_by_symbol(symbol)
373 .cloned()
374 .ok_or_else(|| sim_kernel::Error::Eval(format!("unknown codec {}", symbol)))?;
375 let codec = value
376 .object()
377 .as_any()
378 .downcast_ref::<CodecRuntime>()
379 .ok_or_else(|| sim_kernel::Error::Eval(format!("{} is not a codec runtime", symbol)))?;
380 let mut write_cx = WriteCx {
381 cx,
382 codec: codec.id,
383 options,
384 };
385 codec.encode_tree(&mut write_cx, expr)
386}
387
388pub fn decode_tree_with_codec(
391 cx: &mut Cx,
392 symbol: &Symbol,
393 input: Input,
394 read_policy: ReadPolicy,
395 source_id: impl Into<String>,
396) -> Result<LocatedExprTree> {
397 decode_tree_with_codec_and_limits(
398 cx,
399 symbol,
400 input,
401 read_policy,
402 source_id,
403 DecodeLimits::default(),
404 )
405}
406
407pub fn decode_tree_with_codec_and_limits(
410 cx: &mut Cx,
411 symbol: &Symbol,
412 input: Input,
413 read_policy: ReadPolicy,
414 source_id: impl Into<String>,
415 limits: DecodeLimits,
416) -> Result<LocatedExprTree> {
417 let value = cx.resolve_codec(symbol)?;
418 let codec =
419 value
420 .object()
421 .downcast_ref::<CodecRuntime>()
422 .ok_or(sim_kernel::Error::TypeMismatch {
423 expected: "codec",
424 found: "non-codec",
425 })?;
426 let mut read_cx = ReadCx {
427 cx,
428 codec: codec.id,
429 read_policy,
430 limits,
431 };
432 codec.decode_tree(&mut read_cx, input, source_id.into())
433}
434
435fn term_from_expr(default_decode: CodecDefaultDecode, expr: sim_kernel::Expr) -> Result<Term> {
436 match default_decode {
437 CodecDefaultDecode::Datum => Term::lower(expr),
438 CodecDefaultDecode::TermInEvalDatumOtherwise => Term::lower(lower_eval_surface(expr)),
439 }
440}
441
442fn lower_eval_surface(expr: sim_kernel::Expr) -> sim_kernel::Expr {
443 use sim_kernel::Expr;
444
445 match expr {
446 Expr::List(items) if items.len() > 1 => {
447 let mut items = items
448 .into_iter()
449 .map(lower_eval_surface)
450 .collect::<Vec<_>>();
451 let operator = Box::new(items.remove(0));
452 Expr::Call {
453 operator,
454 args: items,
455 }
456 }
457 Expr::List(items) => Expr::List(items.into_iter().map(lower_eval_surface).collect()),
458 Expr::Vector(items) => Expr::Vector(items.into_iter().map(lower_eval_surface).collect()),
459 Expr::Map(entries) => Expr::Map(
460 entries
461 .into_iter()
462 .map(|(key, value)| (lower_eval_surface(key), lower_eval_surface(value)))
463 .collect(),
464 ),
465 Expr::Set(items) => Expr::Set(items.into_iter().map(lower_eval_surface).collect()),
466 Expr::Block(items) => Expr::Block(items.into_iter().map(lower_eval_surface).collect()),
467 Expr::Quote { mode, expr } => Expr::Quote { mode, expr },
468 Expr::Annotated { expr, annotations } => Expr::Annotated {
469 expr: Box::new(lower_eval_surface(*expr)),
470 annotations: annotations
471 .into_iter()
472 .map(|(name, value)| (name, lower_eval_surface(value)))
473 .collect(),
474 },
475 Expr::Extension { tag, payload } => Expr::Extension {
476 tag,
477 payload: Box::new(lower_eval_surface(*payload)),
478 },
479 other => other,
480 }
481}