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