@grain/stdlib 0.5.2 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +59 -0
- package/array.gr +61 -1
- package/array.md +113 -0
- package/bigint.md +30 -30
- package/buffer.gr +24 -22
- package/char.gr +2 -2
- package/float32.md +3 -3
- package/float64.md +3 -3
- package/immutablemap.gr +493 -0
- package/immutablemap.md +479 -0
- package/immutablepriorityqueue.gr +360 -0
- package/immutablepriorityqueue.md +291 -0
- package/immutableset.gr +498 -0
- package/immutableset.md +449 -0
- package/list.gr +75 -2
- package/list.md +110 -0
- package/map.gr +1 -2
- package/marshal.gr +1058 -0
- package/marshal.md +76 -0
- package/number.gr +689 -23
- package/number.md +362 -27
- package/package.json +1 -1
- package/pervasives.gr +16 -5
- package/pervasives.md +28 -0
- package/priorityqueue.gr +261 -0
- package/priorityqueue.md +309 -0
- package/queue.gr +14 -1
- package/queue.md +16 -1
- package/regex.gr +90 -67
- package/runtime/bigint.gr +4 -4
- package/runtime/compare.gr +179 -0
- package/runtime/compare.md +6 -0
- package/runtime/equal.gr +3 -3
- package/runtime/exception.gr +9 -5
- package/runtime/exception.md +8 -2
- package/runtime/gc.gr +2 -1
- package/runtime/malloc.gr +1 -3
- package/runtime/numberUtils.gr +11 -11
- package/runtime/numbers.gr +423 -100
- package/runtime/numbers.md +50 -0
- package/runtime/string.gr +4 -2
- package/set.gr +26 -27
- package/stack.gr +12 -0
- package/stack.md +15 -0
- package/string.gr +409 -53
- package/string.md +164 -1
- package/sys/file.gr +4 -4
- package/sys/file.md +3 -3
- package/sys/process.gr +3 -3
- package/sys/process.md +3 -3
- package/sys/random.gr +2 -2
- package/sys/random.md +2 -2
- package/sys/time.gr +2 -2
- package/sys/time.md +2 -2
package/marshal.gr
ADDED
|
@@ -0,0 +1,1058 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module Marshal: Utilities for serializing and deserializing Grain data.
|
|
3
|
+
*
|
|
4
|
+
* @example import Marshal from "marshal"
|
|
5
|
+
*
|
|
6
|
+
* @since v0.5.3
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/*
|
|
10
|
+
SERIALIZED BINARY FORMAT
|
|
11
|
+
|
|
12
|
+
Grain stack-allocated values are serialized as-is. Heap-allocated values are
|
|
13
|
+
largely serialized the same as their in-memory representation, with the
|
|
14
|
+
exception that pointers are offsets into the byte sequence rather than
|
|
15
|
+
pointers into memory. Structures are kept 8-byte aligned to be consistent
|
|
16
|
+
with Grain's in-memory representation. The order in which these structures
|
|
17
|
+
appear in the byte sequence is not significant.
|
|
18
|
+
|
|
19
|
+
The first 32-bit value in the byte sequence is either a stack-allocated value
|
|
20
|
+
or a "pointer" to a heap-allocated value.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @section Values: Functions for marshaling and unmarshaling data.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import WasmI32, {
|
|
28
|
+
add as (+),
|
|
29
|
+
mul as (*),
|
|
30
|
+
and as (&),
|
|
31
|
+
eq as (==),
|
|
32
|
+
ne as (!=),
|
|
33
|
+
gtU as (>),
|
|
34
|
+
ltU as (<),
|
|
35
|
+
leU as (<=),
|
|
36
|
+
load,
|
|
37
|
+
store,
|
|
38
|
+
fromGrain,
|
|
39
|
+
toGrain,
|
|
40
|
+
} from "runtime/unsafe/wasmi32"
|
|
41
|
+
import WasmI64 from "runtime/unsafe/wasmi64"
|
|
42
|
+
import Memory from "runtime/unsafe/memory"
|
|
43
|
+
import Tags from "runtime/unsafe/tags"
|
|
44
|
+
import { allocateBytes, newInt32 } from "runtime/dataStructures"
|
|
45
|
+
import Map from "map"
|
|
46
|
+
import Set from "set"
|
|
47
|
+
import Option from "option"
|
|
48
|
+
|
|
49
|
+
@unsafe
|
|
50
|
+
let roundTo8 = n => {
|
|
51
|
+
n + 7n & 0xfffffff8n
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@unsafe
|
|
55
|
+
let isHeapPtr = value =>
|
|
56
|
+
(value & Tags._GRAIN_GENERIC_TAG_MASK) ==
|
|
57
|
+
Tags._GRAIN_GENERIC_HEAP_TAG_TYPE
|
|
58
|
+
|
|
59
|
+
@unsafe
|
|
60
|
+
let rec size = (value, acc, valuesSeen, toplevel) => {
|
|
61
|
+
if (isHeapPtr(value)) {
|
|
62
|
+
let asInt32 = toGrain(newInt32(value)): Int32
|
|
63
|
+
if (Set.contains(asInt32, valuesSeen)) {
|
|
64
|
+
// We've detected a cycle, and we'll refer to the existing instance
|
|
65
|
+
acc
|
|
66
|
+
} else {
|
|
67
|
+
Set.add(asInt32, valuesSeen)
|
|
68
|
+
|
|
69
|
+
let acc = if (toplevel) {
|
|
70
|
+
// We'll write a word (and 32 bits of padding) to indicate that this is a heap value
|
|
71
|
+
acc + 8n
|
|
72
|
+
} else {
|
|
73
|
+
acc
|
|
74
|
+
}
|
|
75
|
+
let heapPtr = value
|
|
76
|
+
match (load(heapPtr, 0n)) {
|
|
77
|
+
t when (
|
|
78
|
+
t == Tags._GRAIN_STRING_HEAP_TAG || t == Tags._GRAIN_BYTES_HEAP_TAG
|
|
79
|
+
) => {
|
|
80
|
+
acc + roundTo8(8n + load(heapPtr, 4n))
|
|
81
|
+
},
|
|
82
|
+
t when t == Tags._GRAIN_ADT_HEAP_TAG => {
|
|
83
|
+
let arity = load(heapPtr, 16n)
|
|
84
|
+
|
|
85
|
+
let mut acc = acc + roundTo8(20n + arity * 4n)
|
|
86
|
+
|
|
87
|
+
let a = arity * 4n
|
|
88
|
+
for (let mut i = 0n; i < a; i += 4n) {
|
|
89
|
+
acc = size(load(heapPtr + i, 20n), acc, valuesSeen, false)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
acc
|
|
93
|
+
},
|
|
94
|
+
t when t == Tags._GRAIN_RECORD_HEAP_TAG => {
|
|
95
|
+
let arity = load(heapPtr, 12n)
|
|
96
|
+
|
|
97
|
+
let mut acc = acc + roundTo8(16n + arity * 4n)
|
|
98
|
+
|
|
99
|
+
let a = arity * 4n
|
|
100
|
+
for (let mut i = 0n; i < a; i += 4n) {
|
|
101
|
+
acc = size(load(heapPtr + i, 16n), acc, valuesSeen, false)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
acc
|
|
105
|
+
},
|
|
106
|
+
t when t == Tags._GRAIN_ARRAY_HEAP_TAG => {
|
|
107
|
+
let arity = load(heapPtr, 4n)
|
|
108
|
+
|
|
109
|
+
let mut acc = acc + roundTo8(8n + arity * 4n)
|
|
110
|
+
|
|
111
|
+
let a = arity * 4n
|
|
112
|
+
for (let mut i = 0n; i < a; i += 4n) {
|
|
113
|
+
acc = size(load(heapPtr + i, 8n), acc, valuesSeen, false)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
acc
|
|
117
|
+
},
|
|
118
|
+
t when t == Tags._GRAIN_TUPLE_HEAP_TAG => {
|
|
119
|
+
let arity = load(heapPtr, 4n)
|
|
120
|
+
|
|
121
|
+
let mut acc = acc + roundTo8(8n + arity * 4n)
|
|
122
|
+
|
|
123
|
+
let l = arity * 4n
|
|
124
|
+
for (let mut i = 0n; i < l; i += 4n) {
|
|
125
|
+
acc = size(load(heapPtr + i, 8n), acc, valuesSeen, false)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
acc
|
|
129
|
+
},
|
|
130
|
+
t when t == Tags._GRAIN_LAMBDA_HEAP_TAG => {
|
|
131
|
+
let arity = load(heapPtr, 12n)
|
|
132
|
+
|
|
133
|
+
let mut acc = acc + roundTo8(16n + arity * 4n)
|
|
134
|
+
|
|
135
|
+
let a = arity * 4n
|
|
136
|
+
for (let mut i = 0n; i < a; i += 4n) {
|
|
137
|
+
acc = size(load(heapPtr + i, 16n), acc, valuesSeen, false)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
acc
|
|
141
|
+
},
|
|
142
|
+
t when t == Tags._GRAIN_BOXED_NUM_HEAP_TAG => {
|
|
143
|
+
let tag = load(heapPtr, 4n)
|
|
144
|
+
match (tag) {
|
|
145
|
+
t when (
|
|
146
|
+
t == Tags._GRAIN_INT32_BOXED_NUM_TAG ||
|
|
147
|
+
t == Tags._GRAIN_INT64_BOXED_NUM_TAG ||
|
|
148
|
+
t == Tags._GRAIN_FLOAT32_BOXED_NUM_TAG ||
|
|
149
|
+
t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG
|
|
150
|
+
) => {
|
|
151
|
+
// The 32-bit values only take 12 bytes of memory, but we report 16
|
|
152
|
+
// for alignment
|
|
153
|
+
acc + 16n
|
|
154
|
+
},
|
|
155
|
+
t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
|
|
156
|
+
acc + 16n + load(heapPtr, 8n) * 8n
|
|
157
|
+
},
|
|
158
|
+
t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
|
|
159
|
+
acc +
|
|
160
|
+
16n +
|
|
161
|
+
size(load(value, 8n), 0n, valuesSeen, false) +
|
|
162
|
+
size(load(value, 12n), 0n, valuesSeen, false)
|
|
163
|
+
},
|
|
164
|
+
_ => {
|
|
165
|
+
fail "Unknown number type"
|
|
166
|
+
},
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
_ => {
|
|
170
|
+
fail "Unknown heap type"
|
|
171
|
+
},
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
} else {
|
|
175
|
+
// Handle non-heap values: booleans, chars, void, etc.
|
|
176
|
+
if (toplevel) {
|
|
177
|
+
acc + 4n
|
|
178
|
+
} else {
|
|
179
|
+
acc
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
@unsafe
|
|
185
|
+
let size = value => {
|
|
186
|
+
size(value, 0n, Set.make(), true)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
@unsafe
|
|
190
|
+
let rec marshalHeap = (heapPtr, buf, offset, valuesSeen) => {
|
|
191
|
+
let asInt32 = toGrain(newInt32(heapPtr)): Int32
|
|
192
|
+
let offsetAsInt32 = toGrain(newInt32(offset)): Int32
|
|
193
|
+
Map.set(asInt32, offsetAsInt32, valuesSeen)
|
|
194
|
+
|
|
195
|
+
match (load(heapPtr, 0n)) {
|
|
196
|
+
t when (
|
|
197
|
+
t == Tags._GRAIN_STRING_HEAP_TAG || t == Tags._GRAIN_BYTES_HEAP_TAG
|
|
198
|
+
) => {
|
|
199
|
+
let size = 8n + load(heapPtr, 4n)
|
|
200
|
+
Memory.copy(buf + offset, heapPtr, size)
|
|
201
|
+
roundTo8(offset + size)
|
|
202
|
+
},
|
|
203
|
+
t when t == Tags._GRAIN_ADT_HEAP_TAG => {
|
|
204
|
+
Memory.copy(buf + offset, heapPtr, 20n)
|
|
205
|
+
|
|
206
|
+
let arity = load(heapPtr, 16n)
|
|
207
|
+
|
|
208
|
+
let mut payloadOffset = roundTo8(offset + 20n + arity * 4n)
|
|
209
|
+
|
|
210
|
+
let a = arity * 4n
|
|
211
|
+
for (let mut i = 0n; i < a; i += 4n) {
|
|
212
|
+
let value = load(heapPtr + i, 20n)
|
|
213
|
+
if (isHeapPtr(value)) {
|
|
214
|
+
let asInt32 = toGrain(newInt32(value)): Int32
|
|
215
|
+
match (Map.get(asInt32, valuesSeen)) {
|
|
216
|
+
Some(value) => {
|
|
217
|
+
let ptr = load(fromGrain(value), 8n)
|
|
218
|
+
store(buf, ptr, offset + i + 20n)
|
|
219
|
+
},
|
|
220
|
+
None => {
|
|
221
|
+
store(buf, payloadOffset, offset + i + 20n)
|
|
222
|
+
payloadOffset = marshalHeap(value, buf, payloadOffset, valuesSeen)
|
|
223
|
+
},
|
|
224
|
+
}
|
|
225
|
+
} else {
|
|
226
|
+
store(buf, value, offset + i + 20n)
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
payloadOffset
|
|
231
|
+
},
|
|
232
|
+
t when t == Tags._GRAIN_RECORD_HEAP_TAG => {
|
|
233
|
+
Memory.copy(buf + offset, heapPtr, 16n)
|
|
234
|
+
|
|
235
|
+
let arity = load(heapPtr, 12n)
|
|
236
|
+
|
|
237
|
+
let mut payloadOffset = roundTo8(offset + 16n + arity * 4n)
|
|
238
|
+
|
|
239
|
+
let a = arity * 4n
|
|
240
|
+
for (let mut i = 0n; i < a; i += 4n) {
|
|
241
|
+
let value = load(heapPtr + i, 16n)
|
|
242
|
+
if (isHeapPtr(value)) {
|
|
243
|
+
let asInt32 = toGrain(newInt32(value)): Int32
|
|
244
|
+
match (Map.get(asInt32, valuesSeen)) {
|
|
245
|
+
Some(value) => {
|
|
246
|
+
let ptr = load(fromGrain(value), 8n)
|
|
247
|
+
store(buf, ptr, offset + i + 16n)
|
|
248
|
+
},
|
|
249
|
+
None => {
|
|
250
|
+
store(buf, payloadOffset, offset + i + 16n)
|
|
251
|
+
payloadOffset = marshalHeap(value, buf, payloadOffset, valuesSeen)
|
|
252
|
+
},
|
|
253
|
+
}
|
|
254
|
+
} else {
|
|
255
|
+
store(buf, value, offset + i + 16n)
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
payloadOffset
|
|
260
|
+
},
|
|
261
|
+
t when t == Tags._GRAIN_ARRAY_HEAP_TAG => {
|
|
262
|
+
Memory.copy(buf + offset, heapPtr, 8n)
|
|
263
|
+
|
|
264
|
+
let arity = load(heapPtr, 4n)
|
|
265
|
+
|
|
266
|
+
let mut payloadOffset = roundTo8(offset + 8n + arity * 4n)
|
|
267
|
+
|
|
268
|
+
let a = arity * 4n
|
|
269
|
+
for (let mut i = 0n; i < a; i += 4n) {
|
|
270
|
+
let value = load(heapPtr + i, 8n)
|
|
271
|
+
if (isHeapPtr(value)) {
|
|
272
|
+
let asInt32 = toGrain(newInt32(value)): Int32
|
|
273
|
+
match (Map.get(asInt32, valuesSeen)) {
|
|
274
|
+
Some(value) => {
|
|
275
|
+
let ptr = load(fromGrain(value), 8n)
|
|
276
|
+
store(buf, ptr, offset + i + 8n)
|
|
277
|
+
},
|
|
278
|
+
None => {
|
|
279
|
+
store(buf, payloadOffset, offset + i + 8n)
|
|
280
|
+
payloadOffset = marshalHeap(value, buf, payloadOffset, valuesSeen)
|
|
281
|
+
},
|
|
282
|
+
}
|
|
283
|
+
} else {
|
|
284
|
+
store(buf, value, offset + i + 8n)
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
payloadOffset
|
|
289
|
+
},
|
|
290
|
+
t when t == Tags._GRAIN_TUPLE_HEAP_TAG => {
|
|
291
|
+
Memory.copy(buf + offset, heapPtr, 8n)
|
|
292
|
+
|
|
293
|
+
let arity = load(heapPtr, 4n)
|
|
294
|
+
|
|
295
|
+
let mut payloadOffset = roundTo8(offset + 8n + arity * 4n)
|
|
296
|
+
|
|
297
|
+
let a = arity * 4n
|
|
298
|
+
for (let mut i = 0n; i < a; i += 4n) {
|
|
299
|
+
let value = load(heapPtr + i, 8n)
|
|
300
|
+
if (isHeapPtr(value)) {
|
|
301
|
+
let asInt32 = toGrain(newInt32(value)): Int32
|
|
302
|
+
match (Map.get(asInt32, valuesSeen)) {
|
|
303
|
+
Some(value) => {
|
|
304
|
+
let ptr = load(fromGrain(value), 8n)
|
|
305
|
+
store(buf, ptr, offset + i + 8n)
|
|
306
|
+
},
|
|
307
|
+
None => {
|
|
308
|
+
store(buf, payloadOffset, offset + i + 8n)
|
|
309
|
+
payloadOffset = marshalHeap(value, buf, payloadOffset, valuesSeen)
|
|
310
|
+
},
|
|
311
|
+
}
|
|
312
|
+
} else {
|
|
313
|
+
store(buf, value, offset + i + 8n)
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
payloadOffset
|
|
318
|
+
},
|
|
319
|
+
t when t == Tags._GRAIN_LAMBDA_HEAP_TAG => {
|
|
320
|
+
Memory.copy(buf + offset, heapPtr, 16n)
|
|
321
|
+
|
|
322
|
+
let arity = load(heapPtr, 12n)
|
|
323
|
+
|
|
324
|
+
let mut payloadOffset = roundTo8(offset + 16n + arity * 4n)
|
|
325
|
+
|
|
326
|
+
let a = arity * 4n
|
|
327
|
+
for (let mut i = 0n; i < a; i += 4n) {
|
|
328
|
+
let value = load(heapPtr + i, 16n)
|
|
329
|
+
if (isHeapPtr(value)) {
|
|
330
|
+
let asInt32 = toGrain(newInt32(value)): Int32
|
|
331
|
+
match (Map.get(asInt32, valuesSeen)) {
|
|
332
|
+
Some(value) => {
|
|
333
|
+
let ptr = load(fromGrain(value), 8n)
|
|
334
|
+
store(buf, ptr, offset + i + 16n)
|
|
335
|
+
},
|
|
336
|
+
None => {
|
|
337
|
+
store(buf, payloadOffset, offset + i + 16n)
|
|
338
|
+
payloadOffset = marshalHeap(value, buf, payloadOffset, valuesSeen)
|
|
339
|
+
},
|
|
340
|
+
}
|
|
341
|
+
} else {
|
|
342
|
+
store(buf, value, offset + i + 16n)
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
payloadOffset
|
|
347
|
+
},
|
|
348
|
+
t when t == Tags._GRAIN_BOXED_NUM_HEAP_TAG => {
|
|
349
|
+
let tag = load(heapPtr, 4n)
|
|
350
|
+
match (tag) {
|
|
351
|
+
t when t == Tags._GRAIN_INT32_BOXED_NUM_TAG => {
|
|
352
|
+
Memory.copy(buf + offset, heapPtr, 12n)
|
|
353
|
+
offset + 16n
|
|
354
|
+
},
|
|
355
|
+
t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
|
|
356
|
+
Memory.copy(buf + offset, heapPtr, 16n)
|
|
357
|
+
offset + 16n
|
|
358
|
+
},
|
|
359
|
+
t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
|
|
360
|
+
let size = 16n + load(heapPtr, 8n) * 8n
|
|
361
|
+
Memory.copy(buf + offset, heapPtr, size)
|
|
362
|
+
offset + size
|
|
363
|
+
},
|
|
364
|
+
t when t == Tags._GRAIN_FLOAT32_BOXED_NUM_TAG => {
|
|
365
|
+
Memory.copy(buf + offset, heapPtr, 12n)
|
|
366
|
+
offset + 16n
|
|
367
|
+
},
|
|
368
|
+
t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
|
|
369
|
+
Memory.copy(buf + offset, heapPtr, 16n)
|
|
370
|
+
offset + 16n
|
|
371
|
+
},
|
|
372
|
+
t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
|
|
373
|
+
Memory.copy(buf + offset, heapPtr, 8n)
|
|
374
|
+
let mut payloadOffset = offset + 16n
|
|
375
|
+
store(buf, payloadOffset, offset + 8n)
|
|
376
|
+
payloadOffset = marshalHeap(
|
|
377
|
+
load(heapPtr, 8n),
|
|
378
|
+
buf,
|
|
379
|
+
payloadOffset,
|
|
380
|
+
valuesSeen
|
|
381
|
+
)
|
|
382
|
+
store(buf, payloadOffset, offset + 12n)
|
|
383
|
+
payloadOffset = marshalHeap(
|
|
384
|
+
load(heapPtr, 12n),
|
|
385
|
+
buf,
|
|
386
|
+
payloadOffset,
|
|
387
|
+
valuesSeen
|
|
388
|
+
)
|
|
389
|
+
payloadOffset
|
|
390
|
+
},
|
|
391
|
+
_ => {
|
|
392
|
+
fail "Unknown number type"
|
|
393
|
+
},
|
|
394
|
+
}
|
|
395
|
+
},
|
|
396
|
+
_ => {
|
|
397
|
+
fail "Unknown heap type"
|
|
398
|
+
},
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
@unsafe
|
|
403
|
+
let marshal = (value, buf) => {
|
|
404
|
+
if (isHeapPtr(value)) {
|
|
405
|
+
store(buf, 8n, 0n)
|
|
406
|
+
marshalHeap(value, buf, 8n, Map.make())
|
|
407
|
+
} else {
|
|
408
|
+
// Handle non-heap values: booleans, numbers, chars, void, etc.
|
|
409
|
+
store(buf, value, 0n)
|
|
410
|
+
4n
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Serialize a value into a byte-based representation suitable for transmission
|
|
416
|
+
* across a network or disk storage. The byte-based representation can be
|
|
417
|
+
* deserialized at a later time to restore the value.
|
|
418
|
+
*
|
|
419
|
+
* @param value: The value to serialize
|
|
420
|
+
* @returns A byte-based representation of the value
|
|
421
|
+
*
|
|
422
|
+
* @since v0.5.3
|
|
423
|
+
*/
|
|
424
|
+
@unsafe
|
|
425
|
+
export let marshal = value => {
|
|
426
|
+
let valuePtr = fromGrain(value)
|
|
427
|
+
let buf = allocateBytes(size(valuePtr))
|
|
428
|
+
marshal(valuePtr, buf + 8n)
|
|
429
|
+
toGrain(buf): Bytes
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
@unsafe
|
|
433
|
+
let reportError = (message, offset) => {
|
|
434
|
+
Some(message ++ " at offset " ++ toString(toGrain(newInt32(offset))))
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// When Grain has exception handling, validation could potentially occur during
|
|
438
|
+
// unmarshaling.
|
|
439
|
+
|
|
440
|
+
@unsafe
|
|
441
|
+
let validateStack = (value, offset) => {
|
|
442
|
+
match (value) {
|
|
443
|
+
_ when (
|
|
444
|
+
value == fromGrain(true) ||
|
|
445
|
+
value == fromGrain(false) ||
|
|
446
|
+
value == fromGrain(void) ||
|
|
447
|
+
(value & Tags._GRAIN_NUMBER_TAG_MASK) == Tags._GRAIN_NUMBER_TAG_TYPE ||
|
|
448
|
+
(value & Tags._GRAIN_GENERIC_TAG_MASK) == Tags._GRAIN_CHAR_TAG_TYPE
|
|
449
|
+
) =>
|
|
450
|
+
None,
|
|
451
|
+
_ => reportError("Unknown value", offset),
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
@unsafe
|
|
456
|
+
let rec validateHeap = (buf, bufSize, offset, valuesChecked) => {
|
|
457
|
+
let offsetAsInt32 = toGrain(newInt32(offset)): Int32
|
|
458
|
+
Set.add(offsetAsInt32, valuesChecked)
|
|
459
|
+
|
|
460
|
+
let valuePtr = buf + offset
|
|
461
|
+
match (load(valuePtr, 0n)) {
|
|
462
|
+
t when (
|
|
463
|
+
t == Tags._GRAIN_STRING_HEAP_TAG || t == Tags._GRAIN_BYTES_HEAP_TAG
|
|
464
|
+
) => {
|
|
465
|
+
let size = 8n + load(valuePtr, 4n)
|
|
466
|
+
if (offset + size > bufSize) {
|
|
467
|
+
reportError("String/Bytes length exceeds buffer size", offset)
|
|
468
|
+
} else {
|
|
469
|
+
None
|
|
470
|
+
}
|
|
471
|
+
},
|
|
472
|
+
t when t == Tags._GRAIN_ADT_HEAP_TAG => {
|
|
473
|
+
let arity = load(valuePtr, 16n)
|
|
474
|
+
let size = 20n + arity * 4n
|
|
475
|
+
|
|
476
|
+
let mut error = if (offset + size > bufSize) {
|
|
477
|
+
reportError("Enum payload size exceeds buffer size", offset)
|
|
478
|
+
} else {
|
|
479
|
+
None
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
let a = arity * 4n
|
|
483
|
+
for (let mut i = 0n; i < a; i += 4n) {
|
|
484
|
+
if (Option.isSome(error)) break
|
|
485
|
+
|
|
486
|
+
let value = load(valuePtr + i, 20n)
|
|
487
|
+
if (isHeapPtr(value)) {
|
|
488
|
+
let asInt32 = toGrain(newInt32(value)): Int32
|
|
489
|
+
if (Set.contains(asInt32, valuesChecked)) {
|
|
490
|
+
continue
|
|
491
|
+
}
|
|
492
|
+
error = Option.or(
|
|
493
|
+
error,
|
|
494
|
+
validateHeap(buf, bufSize, value, valuesChecked)
|
|
495
|
+
)
|
|
496
|
+
} else {
|
|
497
|
+
error = Option.or(error, validateStack(value, offset))
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
error
|
|
502
|
+
},
|
|
503
|
+
t when t == Tags._GRAIN_RECORD_HEAP_TAG => {
|
|
504
|
+
let arity = load(valuePtr, 12n)
|
|
505
|
+
let size = 16n + arity * 4n
|
|
506
|
+
|
|
507
|
+
let mut error = if (offset + size > bufSize) {
|
|
508
|
+
reportError("Record payload size exceeds buffer size", offset)
|
|
509
|
+
} else {
|
|
510
|
+
None
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
let a = arity * 4n
|
|
514
|
+
for (let mut i = 0n; i < a; i += 4n) {
|
|
515
|
+
if (Option.isSome(error)) break
|
|
516
|
+
|
|
517
|
+
let value = load(valuePtr + i, 16n)
|
|
518
|
+
if (isHeapPtr(value)) {
|
|
519
|
+
let asInt32 = toGrain(newInt32(value)): Int32
|
|
520
|
+
if (Set.contains(asInt32, valuesChecked)) {
|
|
521
|
+
continue
|
|
522
|
+
}
|
|
523
|
+
error = Option.or(
|
|
524
|
+
error,
|
|
525
|
+
validateHeap(buf, bufSize, value, valuesChecked)
|
|
526
|
+
)
|
|
527
|
+
} else {
|
|
528
|
+
error = Option.or(error, validateStack(value, offset))
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
error
|
|
533
|
+
},
|
|
534
|
+
t when t == Tags._GRAIN_ARRAY_HEAP_TAG => {
|
|
535
|
+
let arity = load(valuePtr, 4n)
|
|
536
|
+
let size = 8n + arity * 4n
|
|
537
|
+
|
|
538
|
+
let mut error = if (offset + size > bufSize) {
|
|
539
|
+
reportError("Array payload size exceeds buffer size", offset)
|
|
540
|
+
} else {
|
|
541
|
+
None
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
let a = arity * 4n
|
|
545
|
+
for (let mut i = 0n; i < a; i += 4n) {
|
|
546
|
+
if (Option.isSome(error)) break
|
|
547
|
+
|
|
548
|
+
let value = load(valuePtr + i, 8n)
|
|
549
|
+
if (isHeapPtr(value)) {
|
|
550
|
+
let asInt32 = toGrain(newInt32(value)): Int32
|
|
551
|
+
if (Set.contains(asInt32, valuesChecked)) {
|
|
552
|
+
continue
|
|
553
|
+
}
|
|
554
|
+
error = Option.or(
|
|
555
|
+
error,
|
|
556
|
+
validateHeap(buf, bufSize, value, valuesChecked)
|
|
557
|
+
)
|
|
558
|
+
} else {
|
|
559
|
+
error = Option.or(error, validateStack(value, offset))
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
error
|
|
564
|
+
},
|
|
565
|
+
t when t == Tags._GRAIN_TUPLE_HEAP_TAG => {
|
|
566
|
+
let arity = load(valuePtr, 4n)
|
|
567
|
+
let size = 8n + arity * 4n
|
|
568
|
+
|
|
569
|
+
let mut error = if (offset + size > bufSize) {
|
|
570
|
+
reportError("Tuple payload size exceeds buffer size", offset)
|
|
571
|
+
} else {
|
|
572
|
+
None
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
let a = arity * 4n
|
|
576
|
+
for (let mut i = 0n; i < a; i += 4n) {
|
|
577
|
+
if (Option.isSome(error)) break
|
|
578
|
+
|
|
579
|
+
let value = load(valuePtr + i, 8n)
|
|
580
|
+
if (isHeapPtr(value)) {
|
|
581
|
+
let asInt32 = toGrain(newInt32(value)): Int32
|
|
582
|
+
if (Set.contains(asInt32, valuesChecked)) {
|
|
583
|
+
continue
|
|
584
|
+
}
|
|
585
|
+
error = Option.or(
|
|
586
|
+
error,
|
|
587
|
+
validateHeap(buf, bufSize, value, valuesChecked)
|
|
588
|
+
)
|
|
589
|
+
} else {
|
|
590
|
+
error = Option.or(error, validateStack(value, offset))
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
error
|
|
595
|
+
},
|
|
596
|
+
t when t == Tags._GRAIN_LAMBDA_HEAP_TAG => {
|
|
597
|
+
let arity = load(valuePtr, 12n)
|
|
598
|
+
let size = 16n + arity * 4n
|
|
599
|
+
|
|
600
|
+
let mut error = if (offset + size > bufSize) {
|
|
601
|
+
reportError("Closure payload size exceeds buffer size", offset)
|
|
602
|
+
} else {
|
|
603
|
+
None
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
let a = arity * 4n
|
|
607
|
+
for (let mut i = 0n; i < a; i += 4n) {
|
|
608
|
+
if (Option.isSome(error)) break
|
|
609
|
+
|
|
610
|
+
let value = load(valuePtr + i, 16n)
|
|
611
|
+
if (isHeapPtr(value)) {
|
|
612
|
+
let asInt32 = toGrain(newInt32(value)): Int32
|
|
613
|
+
if (Set.contains(asInt32, valuesChecked)) {
|
|
614
|
+
continue
|
|
615
|
+
}
|
|
616
|
+
error = Option.or(
|
|
617
|
+
error,
|
|
618
|
+
validateHeap(buf, bufSize, value, valuesChecked)
|
|
619
|
+
)
|
|
620
|
+
} else {
|
|
621
|
+
error = Option.or(error, validateStack(value, offset))
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
error
|
|
626
|
+
},
|
|
627
|
+
t when t == Tags._GRAIN_BOXED_NUM_HEAP_TAG => {
|
|
628
|
+
let tag = load(valuePtr, 4n)
|
|
629
|
+
match (tag) {
|
|
630
|
+
t when t == Tags._GRAIN_INT32_BOXED_NUM_TAG => {
|
|
631
|
+
if (offset + 12n > bufSize) {
|
|
632
|
+
reportError(
|
|
633
|
+
"Not enough bytes remaining in buffer for Int32/Number",
|
|
634
|
+
offset
|
|
635
|
+
)
|
|
636
|
+
} else {
|
|
637
|
+
None
|
|
638
|
+
}
|
|
639
|
+
},
|
|
640
|
+
t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
|
|
641
|
+
if (offset + 16n > bufSize) {
|
|
642
|
+
reportError(
|
|
643
|
+
"Not enough bytes remaining in buffer for Int64/Number",
|
|
644
|
+
offset
|
|
645
|
+
)
|
|
646
|
+
} else {
|
|
647
|
+
None
|
|
648
|
+
}
|
|
649
|
+
},
|
|
650
|
+
t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
|
|
651
|
+
let size = 16n + load(valuePtr, 8n) * 8n
|
|
652
|
+
if (offset + size > bufSize) {
|
|
653
|
+
reportError("BigInt/Number payload size exeeds buffer size", offset)
|
|
654
|
+
} else {
|
|
655
|
+
None
|
|
656
|
+
}
|
|
657
|
+
},
|
|
658
|
+
t when t == Tags._GRAIN_FLOAT32_BOXED_NUM_TAG => {
|
|
659
|
+
if (offset + 12n > bufSize) {
|
|
660
|
+
reportError(
|
|
661
|
+
"Not enough bytes remaining in buffer for Float32/Number",
|
|
662
|
+
offset
|
|
663
|
+
)
|
|
664
|
+
} else {
|
|
665
|
+
None
|
|
666
|
+
}
|
|
667
|
+
},
|
|
668
|
+
t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
|
|
669
|
+
if (offset + 16n > bufSize) {
|
|
670
|
+
reportError(
|
|
671
|
+
"Not enough bytes remaining in buffer for Float64/Number",
|
|
672
|
+
offset
|
|
673
|
+
)
|
|
674
|
+
} else {
|
|
675
|
+
None
|
|
676
|
+
}
|
|
677
|
+
},
|
|
678
|
+
t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
|
|
679
|
+
if (offset + 16n > bufSize) {
|
|
680
|
+
reportError(
|
|
681
|
+
"Not enough bytes remaining in buffer for Rational/Number",
|
|
682
|
+
offset
|
|
683
|
+
)
|
|
684
|
+
} else {
|
|
685
|
+
let numeratorOffset = load(valuePtr, 8n)
|
|
686
|
+
let denominatorOffset = load(valuePtr, 12n)
|
|
687
|
+
let error = Option.or(
|
|
688
|
+
validateHeap(buf, bufSize, numeratorOffset, valuesChecked),
|
|
689
|
+
validateHeap(buf, bufSize, denominatorOffset, valuesChecked)
|
|
690
|
+
)
|
|
691
|
+
if (Option.isNone(error)) {
|
|
692
|
+
let numeratorError = if (
|
|
693
|
+
load(buf, numeratorOffset) != Tags._GRAIN_BOXED_NUM_HEAP_TAG &&
|
|
694
|
+
load(buf, numeratorOffset + 4n) !=
|
|
695
|
+
Tags._GRAIN_BIGINT_BOXED_NUM_TAG
|
|
696
|
+
) {
|
|
697
|
+
reportError(
|
|
698
|
+
"Rational/Number numerator was not in the expected format",
|
|
699
|
+
offset
|
|
700
|
+
)
|
|
701
|
+
} else {
|
|
702
|
+
None
|
|
703
|
+
}
|
|
704
|
+
let denominatorError = if (
|
|
705
|
+
load(buf, denominatorOffset) !=
|
|
706
|
+
Tags._GRAIN_BOXED_NUM_HEAP_TAG &&
|
|
707
|
+
load(buf, denominatorOffset + 4n) !=
|
|
708
|
+
Tags._GRAIN_BIGINT_BOXED_NUM_TAG
|
|
709
|
+
) {
|
|
710
|
+
reportError(
|
|
711
|
+
"Rational/Number denominator was not in the expected format",
|
|
712
|
+
offset
|
|
713
|
+
)
|
|
714
|
+
} else {
|
|
715
|
+
None
|
|
716
|
+
}
|
|
717
|
+
Option.or(numeratorError, denominatorError)
|
|
718
|
+
} else {
|
|
719
|
+
error
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
},
|
|
723
|
+
_ => {
|
|
724
|
+
None
|
|
725
|
+
},
|
|
726
|
+
}
|
|
727
|
+
},
|
|
728
|
+
_ => {
|
|
729
|
+
None
|
|
730
|
+
},
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
@unsafe
|
|
735
|
+
let validate = (buf, bufSize) => {
|
|
736
|
+
if (bufSize < 4n) {
|
|
737
|
+
reportError("No bytes remaining in buffer", 0n)
|
|
738
|
+
} else {
|
|
739
|
+
let value = load(buf, 0n)
|
|
740
|
+
if (isHeapPtr(value)) {
|
|
741
|
+
validateHeap(buf, bufSize, value, Set.make())
|
|
742
|
+
} else {
|
|
743
|
+
// Handle non-heap values: booleans, chars, void, etc.
|
|
744
|
+
match (value) {
|
|
745
|
+
_ when (
|
|
746
|
+
value == fromGrain(true) ||
|
|
747
|
+
value == fromGrain(false) ||
|
|
748
|
+
value == fromGrain(void) ||
|
|
749
|
+
(value & Tags._GRAIN_NUMBER_TAG_MASK) ==
|
|
750
|
+
Tags._GRAIN_NUMBER_TAG_TYPE ||
|
|
751
|
+
(value & Tags._GRAIN_GENERIC_TAG_MASK) == Tags._GRAIN_CHAR_TAG_TYPE
|
|
752
|
+
) =>
|
|
753
|
+
None,
|
|
754
|
+
_ => reportError("Unknown value", 0n),
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
@unsafe
|
|
761
|
+
let rec unmarshalHeap = (buf, offset, valuesUnmarshaled) => {
|
|
762
|
+
let offsetAsInt32 = toGrain(newInt32(offset)): Int32
|
|
763
|
+
|
|
764
|
+
let valuePtr = buf + offset
|
|
765
|
+
match (load(valuePtr, 0n)) {
|
|
766
|
+
t when (
|
|
767
|
+
t == Tags._GRAIN_STRING_HEAP_TAG || t == Tags._GRAIN_BYTES_HEAP_TAG
|
|
768
|
+
) => {
|
|
769
|
+
let size = 8n + load(valuePtr, 4n)
|
|
770
|
+
let value = Memory.malloc(size)
|
|
771
|
+
Memory.copy(value, valuePtr, size)
|
|
772
|
+
|
|
773
|
+
let asInt32 = toGrain(newInt32(value)): Int32
|
|
774
|
+
Map.set(offsetAsInt32, asInt32, valuesUnmarshaled)
|
|
775
|
+
|
|
776
|
+
value
|
|
777
|
+
},
|
|
778
|
+
t when t == Tags._GRAIN_ADT_HEAP_TAG => {
|
|
779
|
+
let arity = load(valuePtr, 16n)
|
|
780
|
+
let size = 20n + arity * 4n
|
|
781
|
+
|
|
782
|
+
let value = Memory.malloc(size)
|
|
783
|
+
Memory.copy(value, valuePtr, 20n)
|
|
784
|
+
|
|
785
|
+
let asInt32 = toGrain(newInt32(value)): Int32
|
|
786
|
+
Map.set(offsetAsInt32, asInt32, valuesUnmarshaled)
|
|
787
|
+
|
|
788
|
+
let a = arity * 4n
|
|
789
|
+
for (let mut i = 0n; i < a; i += 4n) {
|
|
790
|
+
let subvalue = load(valuePtr + i, 20n)
|
|
791
|
+
if (isHeapPtr(subvalue)) {
|
|
792
|
+
let asInt32 = toGrain(newInt32(subvalue)): Int32
|
|
793
|
+
match (Map.get(asInt32, valuesUnmarshaled)) {
|
|
794
|
+
Some(ptr) => {
|
|
795
|
+
let ptr = load(fromGrain(ptr), 8n)
|
|
796
|
+
store(value + i, Memory.incRef(ptr), 20n)
|
|
797
|
+
},
|
|
798
|
+
None => {
|
|
799
|
+
store(
|
|
800
|
+
value + i,
|
|
801
|
+
unmarshalHeap(buf, subvalue, valuesUnmarshaled),
|
|
802
|
+
20n
|
|
803
|
+
)
|
|
804
|
+
},
|
|
805
|
+
}
|
|
806
|
+
} else {
|
|
807
|
+
store(value + i, subvalue, 20n)
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
value
|
|
812
|
+
},
|
|
813
|
+
t when t == Tags._GRAIN_RECORD_HEAP_TAG => {
|
|
814
|
+
let arity = load(valuePtr, 12n)
|
|
815
|
+
let size = 16n + arity * 4n
|
|
816
|
+
|
|
817
|
+
let value = Memory.malloc(size)
|
|
818
|
+
Memory.copy(value, valuePtr, 16n)
|
|
819
|
+
|
|
820
|
+
let asInt32 = toGrain(newInt32(value)): Int32
|
|
821
|
+
Map.set(offsetAsInt32, asInt32, valuesUnmarshaled)
|
|
822
|
+
|
|
823
|
+
let a = arity * 4n
|
|
824
|
+
for (let mut i = 0n; i < a; i += 4n) {
|
|
825
|
+
let subvalue = load(valuePtr + i, 16n)
|
|
826
|
+
if (isHeapPtr(subvalue)) {
|
|
827
|
+
let asInt32 = toGrain(newInt32(subvalue)): Int32
|
|
828
|
+
match (Map.get(asInt32, valuesUnmarshaled)) {
|
|
829
|
+
Some(ptr) => {
|
|
830
|
+
let ptr = load(fromGrain(ptr), 8n)
|
|
831
|
+
store(value + i, Memory.incRef(ptr), 16n)
|
|
832
|
+
},
|
|
833
|
+
None => {
|
|
834
|
+
store(
|
|
835
|
+
value + i,
|
|
836
|
+
unmarshalHeap(buf, subvalue, valuesUnmarshaled),
|
|
837
|
+
16n
|
|
838
|
+
)
|
|
839
|
+
},
|
|
840
|
+
}
|
|
841
|
+
} else {
|
|
842
|
+
store(value + i, subvalue, 16n)
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
value
|
|
847
|
+
},
|
|
848
|
+
t when t == Tags._GRAIN_ARRAY_HEAP_TAG => {
|
|
849
|
+
let arity = load(valuePtr, 4n)
|
|
850
|
+
let size = 8n + arity * 4n
|
|
851
|
+
|
|
852
|
+
let value = Memory.malloc(size)
|
|
853
|
+
Memory.copy(value, valuePtr, 8n)
|
|
854
|
+
|
|
855
|
+
let asInt32 = toGrain(newInt32(value)): Int32
|
|
856
|
+
Map.set(offsetAsInt32, asInt32, valuesUnmarshaled)
|
|
857
|
+
|
|
858
|
+
let a = arity * 4n
|
|
859
|
+
for (let mut i = 0n; i < a; i += 4n) {
|
|
860
|
+
let subvalue = load(valuePtr + i, 8n)
|
|
861
|
+
if (isHeapPtr(subvalue)) {
|
|
862
|
+
let asInt32 = toGrain(newInt32(subvalue)): Int32
|
|
863
|
+
match (Map.get(asInt32, valuesUnmarshaled)) {
|
|
864
|
+
Some(ptr) => {
|
|
865
|
+
let ptr = load(fromGrain(ptr), 8n)
|
|
866
|
+
store(value + i, Memory.incRef(ptr), 8n)
|
|
867
|
+
},
|
|
868
|
+
None => {
|
|
869
|
+
store(
|
|
870
|
+
value + i,
|
|
871
|
+
unmarshalHeap(buf, subvalue, valuesUnmarshaled),
|
|
872
|
+
8n
|
|
873
|
+
)
|
|
874
|
+
},
|
|
875
|
+
}
|
|
876
|
+
} else {
|
|
877
|
+
store(value + i, subvalue, 8n)
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
value
|
|
882
|
+
},
|
|
883
|
+
t when t == Tags._GRAIN_TUPLE_HEAP_TAG => {
|
|
884
|
+
let arity = load(valuePtr, 4n)
|
|
885
|
+
let size = 8n + arity * 4n
|
|
886
|
+
|
|
887
|
+
let value = Memory.malloc(size)
|
|
888
|
+
Memory.copy(value, valuePtr, 8n)
|
|
889
|
+
|
|
890
|
+
let asInt32 = toGrain(newInt32(value)): Int32
|
|
891
|
+
Map.set(offsetAsInt32, asInt32, valuesUnmarshaled)
|
|
892
|
+
|
|
893
|
+
let a = arity * 4n
|
|
894
|
+
for (let mut i = 0n; i < a; i += 4n) {
|
|
895
|
+
let subvalue = load(valuePtr + i, 8n)
|
|
896
|
+
if (isHeapPtr(subvalue)) {
|
|
897
|
+
let asInt32 = toGrain(newInt32(subvalue)): Int32
|
|
898
|
+
match (Map.get(asInt32, valuesUnmarshaled)) {
|
|
899
|
+
Some(ptr) => {
|
|
900
|
+
let ptr = load(fromGrain(ptr), 8n)
|
|
901
|
+
store(value + i, Memory.incRef(ptr), 8n)
|
|
902
|
+
},
|
|
903
|
+
None => {
|
|
904
|
+
store(
|
|
905
|
+
value + i,
|
|
906
|
+
unmarshalHeap(buf, subvalue, valuesUnmarshaled),
|
|
907
|
+
8n
|
|
908
|
+
)
|
|
909
|
+
},
|
|
910
|
+
}
|
|
911
|
+
} else {
|
|
912
|
+
store(value + i, subvalue, 8n)
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
value
|
|
917
|
+
},
|
|
918
|
+
t when t == Tags._GRAIN_LAMBDA_HEAP_TAG => {
|
|
919
|
+
let arity = load(valuePtr, 12n)
|
|
920
|
+
let size = 16n + arity * 4n
|
|
921
|
+
|
|
922
|
+
let value = Memory.malloc(size)
|
|
923
|
+
Memory.copy(value, valuePtr, 16n)
|
|
924
|
+
|
|
925
|
+
let asInt32 = toGrain(newInt32(value)): Int32
|
|
926
|
+
Map.set(offsetAsInt32, asInt32, valuesUnmarshaled)
|
|
927
|
+
|
|
928
|
+
let a = arity * 4n
|
|
929
|
+
for (let mut i = 0n; i < a; i += 4n) {
|
|
930
|
+
let subvalue = load(valuePtr + i, 16n)
|
|
931
|
+
if (isHeapPtr(subvalue)) {
|
|
932
|
+
let asInt32 = toGrain(newInt32(subvalue)): Int32
|
|
933
|
+
match (Map.get(asInt32, valuesUnmarshaled)) {
|
|
934
|
+
Some(ptr) => {
|
|
935
|
+
let ptr = load(fromGrain(ptr), 8n)
|
|
936
|
+
store(value + i, Memory.incRef(ptr), 16n)
|
|
937
|
+
},
|
|
938
|
+
None => {
|
|
939
|
+
store(
|
|
940
|
+
value + i,
|
|
941
|
+
unmarshalHeap(buf, subvalue, valuesUnmarshaled),
|
|
942
|
+
16n
|
|
943
|
+
)
|
|
944
|
+
},
|
|
945
|
+
}
|
|
946
|
+
} else {
|
|
947
|
+
store(value + i, subvalue, 16n)
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
value
|
|
952
|
+
},
|
|
953
|
+
t when t == Tags._GRAIN_BOXED_NUM_HEAP_TAG => {
|
|
954
|
+
let tag = load(valuePtr, 4n)
|
|
955
|
+
match (tag) {
|
|
956
|
+
t when t == Tags._GRAIN_INT32_BOXED_NUM_TAG => {
|
|
957
|
+
let value = Memory.malloc(12n)
|
|
958
|
+
Memory.copy(value, valuePtr, 12n)
|
|
959
|
+
|
|
960
|
+
let asInt32 = toGrain(newInt32(value)): Int32
|
|
961
|
+
Map.set(offsetAsInt32, asInt32, valuesUnmarshaled)
|
|
962
|
+
|
|
963
|
+
value
|
|
964
|
+
},
|
|
965
|
+
t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
|
|
966
|
+
let value = Memory.malloc(16n)
|
|
967
|
+
Memory.copy(value, valuePtr, 16n)
|
|
968
|
+
|
|
969
|
+
let asInt32 = toGrain(newInt32(value)): Int32
|
|
970
|
+
Map.set(offsetAsInt32, asInt32, valuesUnmarshaled)
|
|
971
|
+
|
|
972
|
+
value
|
|
973
|
+
},
|
|
974
|
+
t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
|
|
975
|
+
let size = 16n + load(valuePtr, 8n) * 8n
|
|
976
|
+
let value = Memory.malloc(size)
|
|
977
|
+
Memory.copy(value, valuePtr, size)
|
|
978
|
+
|
|
979
|
+
let asInt32 = toGrain(newInt32(value)): Int32
|
|
980
|
+
Map.set(offsetAsInt32, asInt32, valuesUnmarshaled)
|
|
981
|
+
|
|
982
|
+
value
|
|
983
|
+
},
|
|
984
|
+
t when t == Tags._GRAIN_FLOAT32_BOXED_NUM_TAG => {
|
|
985
|
+
let value = Memory.malloc(12n)
|
|
986
|
+
Memory.copy(value, valuePtr, 12n)
|
|
987
|
+
|
|
988
|
+
let asInt32 = toGrain(newInt32(value)): Int32
|
|
989
|
+
Map.set(offsetAsInt32, asInt32, valuesUnmarshaled)
|
|
990
|
+
|
|
991
|
+
value
|
|
992
|
+
},
|
|
993
|
+
t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
|
|
994
|
+
let value = Memory.malloc(16n)
|
|
995
|
+
Memory.copy(value, valuePtr, 16n)
|
|
996
|
+
|
|
997
|
+
let asInt32 = toGrain(newInt32(value)): Int32
|
|
998
|
+
Map.set(offsetAsInt32, asInt32, valuesUnmarshaled)
|
|
999
|
+
|
|
1000
|
+
value
|
|
1001
|
+
},
|
|
1002
|
+
t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
|
|
1003
|
+
let value = Memory.malloc(16n)
|
|
1004
|
+
Memory.copy(value, valuePtr, 8n)
|
|
1005
|
+
|
|
1006
|
+
let asInt32 = toGrain(newInt32(value)): Int32
|
|
1007
|
+
Map.set(offsetAsInt32, asInt32, valuesUnmarshaled)
|
|
1008
|
+
|
|
1009
|
+
let num = unmarshalHeap(buf, load(valuePtr, 8n), valuesUnmarshaled)
|
|
1010
|
+
store(value, num, 8n)
|
|
1011
|
+
let denom = unmarshalHeap(buf, load(valuePtr, 12n), valuesUnmarshaled)
|
|
1012
|
+
store(value, denom, 12n)
|
|
1013
|
+
value
|
|
1014
|
+
},
|
|
1015
|
+
_ => {
|
|
1016
|
+
fail "Unknown number type"
|
|
1017
|
+
},
|
|
1018
|
+
}
|
|
1019
|
+
},
|
|
1020
|
+
_ => {
|
|
1021
|
+
fail "Unknown heap type"
|
|
1022
|
+
},
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
@unsafe
|
|
1027
|
+
let unmarshal = buf => {
|
|
1028
|
+
let value = load(buf, 0n)
|
|
1029
|
+
if (isHeapPtr(value)) {
|
|
1030
|
+
unmarshalHeap(buf, value, Map.make())
|
|
1031
|
+
} else {
|
|
1032
|
+
// Non-heap values: booleans, numbers, chars, void, etc.
|
|
1033
|
+
value
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
/**
|
|
1038
|
+
* Deserialize the byte-based representation of a value back into an in-memory
|
|
1039
|
+
* value. This operation is not type-safe, and it is recommended that a type
|
|
1040
|
+
* annotation is used to declare the type of the unmarshaled value. While
|
|
1041
|
+
* attempts to unmarshal bad data will fail, this operation is still generally
|
|
1042
|
+
* unsafe and great care should be taken to ensure that the data being
|
|
1043
|
+
* unmarshaled corresponds to the expected type.
|
|
1044
|
+
*
|
|
1045
|
+
* @param bytes: The data to deserialize
|
|
1046
|
+
* @returns An in-memory value
|
|
1047
|
+
*
|
|
1048
|
+
* @since v0.5.3
|
|
1049
|
+
*/
|
|
1050
|
+
@unsafe
|
|
1051
|
+
export let unmarshal = (bytes: Bytes) => {
|
|
1052
|
+
let buf = fromGrain(bytes) + 8n
|
|
1053
|
+
let bufSize = load(fromGrain(bytes), 4n)
|
|
1054
|
+
match (validate(buf, bufSize)) {
|
|
1055
|
+
Some(error) => Err(error),
|
|
1056
|
+
None => Ok(toGrain(unmarshal(buf))),
|
|
1057
|
+
}
|
|
1058
|
+
}
|