Skip to main content

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}