sim_kernel/encode.rs
1//! The encode contract: turning objects back into forms at a known position.
2//!
3//! The kernel defines encode options, output positions, and the object-encoding
4//! contract; concrete codecs that render forms live in library crates.
5
6use crate::{
7 env::Cx,
8 error::Result,
9 expr::Expr,
10 id::{CodecId, Symbol},
11 object::ShapeRef,
12 value::Value,
13};
14
15/// The output position an encoder is targeting.
16///
17/// Encoders render differently depending on where the form will land; the
18/// kernel defines the positions, concrete codecs honor them.
19#[derive(Clone, Copy, Debug, PartialEq, Eq)]
20pub enum EncodePosition {
21 /// Output will be evaluated.
22 Eval,
23 /// Output sits inside a quotation.
24 Quote,
25 /// Output is plain data.
26 Data,
27 /// Output is a pattern.
28 Pattern,
29}
30
31/// How a constructed object is surfaced when encoded.
32#[derive(Clone, Copy, Debug, PartialEq, Eq)]
33pub enum ConstructorSurface {
34 /// A bare constructor call.
35 BareCall,
36 /// A read-time construct form.
37 ReadConstruct,
38 /// Tagged data.
39 TaggedData,
40}
41
42/// Whether read-time construct forms may be emitted.
43#[derive(Clone, Copy, Debug, PartialEq, Eq)]
44pub enum ReadConstructEncodePolicy {
45 /// Forbid read-construct output.
46 Forbid,
47 /// Allow read-construct output.
48 Allow,
49}
50
51/// Whether read-eval output may be emitted.
52#[derive(Clone, Copy, Debug, PartialEq, Eq)]
53pub enum ReadEvalEncodePolicy {
54 /// Forbid read-eval output.
55 Forbid,
56 /// Allow broad read-eval output.
57 AllowBroad,
58}
59
60/// Whether output is canonicalized or preserves the original input form.
61#[derive(Clone, Copy, Debug, PartialEq, Eq)]
62pub enum CanonicalPolicy {
63 /// Emit a canonical form.
64 Canonical,
65 /// Preserve the input form as read.
66 PreserveInput,
67}
68
69/// The full set of options controlling an encode pass.
70#[derive(Clone, Debug, PartialEq, Eq)]
71pub struct EncodeOptions {
72 /// The target output position.
73 pub position: EncodePosition,
74 /// The canonicalization policy.
75 pub canonical: CanonicalPolicy,
76 /// Whether to preserve lossless source origin.
77 pub lossless_origin: bool,
78 /// The read-construct emission policy.
79 pub read_construct: ReadConstructEncodePolicy,
80 /// The read-eval emission policy.
81 pub read_eval: ReadEvalEncodePolicy,
82}
83
84impl Default for EncodeOptions {
85 fn default() -> Self {
86 Self {
87 position: EncodePosition::Data,
88 canonical: CanonicalPolicy::Canonical,
89 lossless_origin: false,
90 read_construct: ReadConstructEncodePolicy::Allow,
91 read_eval: ReadEvalEncodePolicy::Forbid,
92 }
93 }
94}
95
96/// The mutable context passed to an encoder while it renders a form.
97pub struct WriteCx<'a> {
98 /// The runtime context.
99 pub cx: &'a mut Cx,
100 /// The codec performing the encode.
101 pub codec: CodecId,
102 /// The active encode options.
103 pub options: EncodeOptions,
104}
105
106impl<'a> WriteCx<'a> {
107 /// Reborrows this context with the encode position overridden.
108 pub fn with_position<'b>(&'b mut self, position: EncodePosition) -> WriteCx<'b> {
109 let mut options = self.options.clone();
110 options.position = position;
111 WriteCx {
112 cx: &mut *self.cx,
113 codec: self.codec,
114 options,
115 }
116 }
117}
118
119/// How an object presents itself to a codec for encoding.
120///
121/// The kernel defines these encoding shapes; a codec turns the chosen shape
122/// into concrete output.
123#[derive(Clone, Debug, PartialEq, Eq)]
124pub enum ObjectEncoding {
125 /// Encode as a constructor call of `class` with argument expressions.
126 Constructor {
127 /// The constructing class.
128 class: Symbol,
129 /// The constructor argument expressions.
130 args: Vec<Expr>,
131 },
132 /// Encode as tagged data with named fields.
133 TaggedData {
134 /// The data tag.
135 tag: Symbol,
136 /// The named field expressions.
137 fields: Vec<(Symbol, Expr)>,
138 },
139 /// Encode as an opaque reference identified by a stable id.
140 Opaque {
141 /// The object's class.
142 class: Symbol,
143 /// A stable, codec-renderable identifier for the object.
144 stable_id: String,
145 },
146}
147
148/// Contract: an object that can describe its own encoding.
149///
150/// The kernel defines this trait; objects implement it to choose how codecs
151/// render them back into forms.
152pub trait ObjectEncode: Send + Sync {
153 /// Returns the [`ObjectEncoding`] this object should be rendered as.
154 fn object_encoding(&self, cx: &mut Cx) -> Result<ObjectEncoding>;
155}
156
157/// Contract: a read-time constructor that builds an object from read args.
158///
159/// The kernel defines the contract; libraries register concrete constructors
160/// that the reader invokes to build values from forms.
161pub trait ReadConstructor: Send + Sync {
162 /// The symbol naming this constructor.
163 fn symbol(&self) -> Symbol;
164 /// The shape the constructor's arguments must match.
165 fn args_shape(&self, cx: &mut Cx) -> Result<ShapeRef>;
166 /// Constructs the value from matched arguments at read time.
167 fn construct_read(&self, cx: &mut Cx, args: Vec<Value>) -> Result<Value>;
168}