1use std::collections::BTreeMap;
2
3use crate::{
4 error::Result,
5 id::{
6 ClassId, CodecId, FunctionId, LibId, MacroId, NumberDomainId, RuntimeId, ShapeId, SiteId,
7 Symbol,
8 },
9 library::{Export, ExportKind, ExportRecord, ExportState, Registry},
10 number_domain::{
11 NumberBinaryOp, NumberReductionOp, NumberUnaryOp, ValueNumberBinaryOp,
12 ValueNumberReductionOp, ValueNumberUnaryOp, ValuePromotionRule,
13 },
14 value::Value,
15};
16
17#[derive(Default)]
18pub(crate) struct PendingExports {
19 pub(crate) exports: Vec<Export>,
20 pub(crate) export_records: Vec<ExportRecord>,
21 pub(crate) class_value_cache: Vec<(ClassId, Value)>,
22 pub(crate) function_value_cache: Vec<(FunctionId, Value)>,
23 pub(crate) macro_value_cache: Vec<(MacroId, Value)>,
24 pub(crate) shape_value_cache: Vec<(ShapeId, Value)>,
25 pub(crate) codec_value_cache: Vec<(CodecId, Value)>,
26 pub(crate) number_domain_value_cache: Vec<(NumberDomainId, Value)>,
27 pub(crate) site_value_cache: Vec<(SiteId, Value)>,
28 pub(crate) values: Vec<(Symbol, Value)>,
29 pub(crate) promotion_rules: Vec<crate::number_domain::PromotionRule>,
30 pub(crate) value_promotion_rules: Vec<ValuePromotionRule>,
31 pub(crate) number_unary_ops: Vec<NumberUnaryOp>,
32 pub(crate) number_reduction_ops: Vec<NumberReductionOp>,
33 pub(crate) number_binary_ops: Vec<NumberBinaryOp>,
34 pub(crate) value_number_unary_ops: Vec<ValueNumberUnaryOp>,
35 pub(crate) value_number_reduction_ops: Vec<ValueNumberReductionOp>,
36 pub(crate) value_number_binary_ops: Vec<ValueNumberBinaryOp>,
37}
38
39pub struct LoadTransaction {
46 pub(crate) lib_id: LibId,
47 pub(crate) manifest: crate::library::LibManifest,
48 pub(crate) trusted: bool,
49 pub(crate) registry: Registry,
50 pub(crate) pending: PendingExports,
51 pub(crate) stable_exports: BTreeMap<(ExportKind, Symbol), RuntimeId>,
52}
53
54pub struct Linker<'a> {
61 registry: &'a mut Registry,
62 lib: LibId,
63 pending: &'a mut PendingExports,
64 stable_exports: &'a BTreeMap<(ExportKind, Symbol), RuntimeId>,
65}
66
67impl<'a> Linker<'a> {
68 pub(crate) fn new(
69 registry: &'a mut Registry,
70 lib: LibId,
71 pending: &'a mut PendingExports,
72 stable_exports: &'a BTreeMap<(ExportKind, Symbol), RuntimeId>,
73 ) -> Self {
74 Self {
75 registry,
76 lib,
77 pending,
78 stable_exports,
79 }
80 }
81
82 fn stable_id(&self, kind: ExportKind, symbol: &Symbol) -> Option<RuntimeId> {
83 self.stable_exports.get(&(kind, symbol.clone())).copied()
84 }
85
86 pub fn lib_id(&self) -> LibId {
88 self.lib
89 }
90
91 pub fn registry(&self) -> &Registry {
93 self.registry
94 }
95
96 pub fn class(&mut self, symbol: Symbol) -> Result<ClassId> {
98 let id = match self.stable_id(ExportKind::named(ExportKind::CLASS), &symbol) {
99 Some(RuntimeId::Class(id)) => {
100 self.registry.reserve_class_id(id)?;
101 id
102 }
103 _ => self.registry.try_fresh_class_id()?,
104 };
105 self.pending.exports.push(Export::Class {
106 symbol,
107 class_id: Some(id),
108 });
109 Ok(id)
110 }
111
112 pub fn class_with_id(&mut self, symbol: Symbol, id: ClassId) -> Result<ClassId> {
115 self.registry.reserve_class_id(id)?;
116 self.pending.exports.push(Export::Class {
117 symbol,
118 class_id: Some(id),
119 });
120 Ok(id)
121 }
122
123 pub fn class_value(&mut self, symbol: Symbol, value: Value) -> Result<ClassId> {
125 let id = self.class(symbol)?;
126 self.bind_class_value(id, value)?;
127 Ok(id)
128 }
129
130 pub fn bind_class_value(&mut self, id: ClassId, value: Value) -> Result<()> {
132 self.pending.class_value_cache.push((id, value));
133 Ok(())
134 }
135
136 pub fn function(&mut self, symbol: Symbol) -> Result<FunctionId> {
138 let id = match self.stable_id(ExportKind::named(ExportKind::FUNCTION), &symbol) {
139 Some(RuntimeId::Function(id)) => {
140 self.registry.reserve_function_id(id)?;
141 id
142 }
143 _ => self.registry.try_fresh_function_id()?,
144 };
145 self.pending.exports.push(Export::Function {
146 symbol,
147 function_id: Some(id),
148 });
149 Ok(id)
150 }
151
152 pub fn function_value(&mut self, symbol: Symbol, value: Value) -> Result<FunctionId> {
154 let id = self.function(symbol)?;
155 self.bind_function_value(id, value)?;
156 Ok(id)
157 }
158
159 pub fn bind_function_value(&mut self, id: FunctionId, value: Value) -> Result<()> {
161 self.pending.function_value_cache.push((id, value));
162 Ok(())
163 }
164
165 pub fn macro_export(&mut self, symbol: Symbol) -> Result<MacroId> {
167 let id = match self.stable_id(ExportKind::named(ExportKind::MACRO), &symbol) {
168 Some(RuntimeId::Macro(id)) => {
169 self.registry.reserve_macro_id(id)?;
170 id
171 }
172 _ => self.registry.try_fresh_macro_id()?,
173 };
174 self.pending.exports.push(Export::Macro {
175 symbol,
176 macro_id: Some(id),
177 });
178 Ok(id)
179 }
180
181 pub fn macro_value(&mut self, symbol: Symbol, value: Value) -> Result<MacroId> {
183 let id = self.macro_export(symbol)?;
184 self.pending.macro_value_cache.push((id, value));
185 Ok(id)
186 }
187
188 pub fn shape(&mut self, symbol: Symbol) -> Result<ShapeId> {
190 let id = match self.stable_id(ExportKind::named(ExportKind::SHAPE), &symbol) {
191 Some(RuntimeId::Shape(id)) => {
192 self.registry.reserve_shape_id(id)?;
193 id
194 }
195 _ => self.registry.try_fresh_shape_id()?,
196 };
197 self.pending.exports.push(Export::Shape {
198 symbol,
199 shape_id: Some(id),
200 });
201 Ok(id)
202 }
203
204 pub fn shape_value(&mut self, symbol: Symbol, value: Value) -> Result<ShapeId> {
206 let id = self.shape(symbol)?;
207 self.pending.shape_value_cache.push((id, value));
208 Ok(id)
209 }
210
211 pub fn codec(&mut self, symbol: Symbol) -> Result<CodecId> {
213 let id = match self.stable_id(ExportKind::named(ExportKind::CODEC), &symbol) {
214 Some(RuntimeId::Codec(id)) => {
215 self.registry.reserve_codec_id(id)?;
216 id
217 }
218 _ => self.registry.try_fresh_codec_id()?,
219 };
220 self.pending.exports.push(Export::Codec {
221 symbol,
222 codec_id: Some(id),
223 });
224 Ok(id)
225 }
226
227 pub fn codec_value(&mut self, symbol: Symbol, value: Value) -> Result<CodecId> {
229 let id = self.codec(symbol)?;
230 self.pending.codec_value_cache.push((id, value));
231 Ok(id)
232 }
233
234 pub fn number_domain(&mut self, symbol: Symbol) -> Result<NumberDomainId> {
236 let id = match self.stable_id(ExportKind::named(ExportKind::NUMBER_DOMAIN), &symbol) {
237 Some(RuntimeId::NumberDomain(id)) => {
238 self.registry.reserve_number_domain_id(id)?;
239 id
240 }
241 _ => self.registry.try_fresh_number_domain_id()?,
242 };
243 self.pending.exports.push(Export::NumberDomain {
244 symbol,
245 number_domain_id: Some(id),
246 });
247 Ok(id)
248 }
249
250 pub fn number_domain_value(&mut self, symbol: Symbol, value: Value) -> Result<NumberDomainId> {
252 let id = self.number_domain(symbol)?;
253 self.pending.number_domain_value_cache.push((id, value));
254 Ok(id)
255 }
256
257 pub fn site_value(&mut self, symbol: Symbol, value: Value) -> Result<RuntimeId> {
262 let site_id = match self.stable_id(ExportKind::named(ExportKind::SITE), &symbol) {
263 Some(RuntimeId::Site(id)) => {
264 self.registry.reserve_site_id(id)?;
265 id
266 }
267 _ => self.registry.try_fresh_site_id()?,
268 };
269 let runtime_id = RuntimeId::Site(site_id);
270 self.pending.exports.push(Export::Site {
271 symbol,
272 runtime_id: Some(runtime_id),
273 });
274 self.pending.site_value_cache.push((site_id, value));
275 Ok(runtime_id)
276 }
277
278 pub fn value_export(&mut self, symbol: Symbol) -> Result<()> {
280 self.pending.exports.push(Export::Value { symbol });
281 Ok(())
282 }
283
284 pub fn declare_export(&mut self, kind: ExportKind, symbol: Symbol) -> Result<()> {
286 self.pending.export_records.push(ExportRecord {
287 kind,
288 symbol,
289 state: ExportState::Declared,
290 });
291 Ok(())
292 }
293
294 pub fn unsupported_export(
297 &mut self,
298 kind: ExportKind,
299 symbol: Symbol,
300 reason: impl Into<String>,
301 ) -> Result<()> {
302 self.pending.export_records.push(ExportRecord {
303 kind,
304 symbol,
305 state: ExportState::Unsupported {
306 reason: reason.into(),
307 },
308 });
309 Ok(())
310 }
311
312 pub fn invalid_export(
314 &mut self,
315 kind: ExportKind,
316 symbol: Symbol,
317 error: impl Into<String>,
318 ) -> Result<()> {
319 self.pending.export_records.push(ExportRecord {
320 kind,
321 symbol,
322 state: ExportState::Invalid {
323 error: error.into(),
324 },
325 });
326 Ok(())
327 }
328
329 pub fn value(&mut self, symbol: Symbol, value: Value) -> Result<()> {
331 self.value_export(symbol.clone())?;
332 self.pending.values.push((symbol, value));
333 Ok(())
334 }
335
336 pub fn number_binary_op(&mut self, op: NumberBinaryOp) {
338 self.pending.number_binary_ops.push(op);
339 }
340
341 pub fn value_number_binary_op(&mut self, op: ValueNumberBinaryOp) {
343 self.pending.value_number_binary_ops.push(op);
344 }
345
346 pub fn number_unary_op(&mut self, op: NumberUnaryOp) {
348 self.pending.number_unary_ops.push(op);
349 }
350
351 pub fn value_number_unary_op(&mut self, op: ValueNumberUnaryOp) {
353 self.pending.value_number_unary_ops.push(op);
354 }
355
356 pub fn number_reduction_op(&mut self, op: NumberReductionOp) {
358 self.pending.number_reduction_ops.push(op);
359 }
360
361 pub fn value_number_reduction_op(&mut self, op: ValueNumberReductionOp) {
363 self.pending.value_number_reduction_ops.push(op);
364 }
365
366 pub fn promotion_rule(&mut self, rule: crate::number_domain::PromotionRule) {
368 self.pending.promotion_rules.push(rule);
369 }
370
371 pub fn value_promotion_rule(&mut self, rule: ValuePromotionRule) {
373 self.pending.value_promotion_rules.push(rule);
374 }
375}
376
377impl LoadTransaction {
378 pub fn linker(&mut self) -> Linker<'_> {
380 Linker::new(
381 &mut self.registry,
382 self.lib_id,
383 &mut self.pending,
384 &self.stable_exports,
385 )
386 }
387}