sim_codec_binary/lib.rs
1//! Binary wire codec for the SIM runtime.
2//!
3//! This crate encodes and decodes kernel `Expr` values as a compact, tagged
4//! binary frame. A frame begins with a magic/version header and side tables
5//! (interned libs, symbols, and number domains), followed by a tag-prefixed
6//! body that walks the `Expr` graph; an optional flag carries source origins so
7//! that located expressions and `LocatedExprTree` values round-trip as well.
8//!
9//! The public surface is the [`BinaryCodec`] runtime object (registered via
10//! [`BinaryCodecLib`]) together with the free `encode_*` / `decode_*` frame
11//! functions and the frame value types ([`BinaryFrame`], [`BinaryTag`],
12//! [`FrameTables`], [`DecodeLimits`]). Decoding is bounded by [`DecodeLimits`]
13//! to fail closed on hostile or malformed input.
14//!
15//! # Examples
16//!
17//! Encode an [`Expr`] into a [`BinaryFrame`] and decode it straight back,
18//! recovering both the value and its interning side tables -- no runtime
19//! context is needed for the free frame functions:
20//!
21//! ```
22//! use sim_codec_binary::{BinaryFrame, decode_frame, encode_frame};
23//! use sim_kernel::{CodecId, Expr, Symbol};
24//!
25//! let expr = Expr::List(vec![
26//! Expr::Symbol(Symbol::qualified("math", "add")),
27//! Expr::Bool(true),
28//! ]);
29//!
30//! let BinaryFrame(bytes) = encode_frame(&expr)?;
31//! let (tables, back) = decode_frame(CodecId(1), &bytes)?;
32//!
33//! assert_eq!(back, expr);
34//! assert!(tables.symbols.contains(&Symbol::qualified("math", "add")));
35//! # Ok::<(), sim_kernel::Error>(())
36//! ```
37//!
38//! Arbitrary bytes are untrusted data, not executable input: a frame that does
39//! not start with the magic header fails closed rather than running anything.
40//!
41//! ```
42//! use sim_codec_binary::decode_frame;
43//! use sim_kernel::CodecId;
44//!
45//! assert!(decode_frame(CodecId(1), b"not a frame").is_err());
46//! ```
47//!
48//! Register the codec on a runtime and round-trip through the codec surface:
49//!
50//! ```
51//! use std::sync::Arc;
52//! use sim_codec::{Input, Output, decode_with_codec, encode_with_codec};
53//! use sim_codec_binary::BinaryCodecLib;
54//! use sim_kernel::{Cx, DefaultFactory, EagerPolicy, Expr, ReadPolicy, Symbol};
55//!
56//! let mut cx = Cx::new(Arc::new(EagerPolicy), Arc::new(DefaultFactory));
57//! sim_test_support::register_core_classes(&mut cx);
58//!
59//! let lib = BinaryCodecLib::new(cx.registry_mut().fresh_codec_id());
60//! cx.load_lib(&lib)?;
61//! let binary = Symbol::qualified("codec", "binary");
62//!
63//! let bytes = match encode_with_codec(&mut cx, &binary, &Expr::Bool(true), Default::default())? {
64//! Output::Bytes(bytes) => bytes,
65//! Output::Text(text) => text.into_bytes(),
66//! };
67//! let back = decode_with_codec(&mut cx, &binary, Input::Bytes(bytes), ReadPolicy::default())?;
68//! assert_eq!(back, Expr::Bool(true));
69//! # Ok::<(), sim_kernel::Error>(())
70//! ```
71//!
72//! [`Expr`]: sim_kernel::Expr
73
74#![forbid(unsafe_code)]
75#![deny(missing_docs)]
76
77mod codec;
78mod reader;
79mod tables;
80#[cfg(test)]
81mod tests;
82mod types;
83mod writer;
84
85pub(crate) use types::{FLAG_NONE, FLAG_ORIGIN, FLAG_TREE_ORIGIN, MAGIC, VERSION};
86
87pub use codec::{
88 BinaryCodec, BinaryCodecLib, decode_frame, decode_located_frame, decode_located_tree_frame,
89 decode_located_tree_frame_with_limits, encode_frame, encode_located_frame,
90 encode_located_tree_frame,
91};
92pub use types::{BinaryFrame, BinaryTag, DecodeLimits, FrameTables};