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