@grain/stdlib 0.5.12 → 0.6.0

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.
Files changed (155) hide show
  1. package/CHANGELOG.md +200 -0
  2. package/LICENSE +1 -1
  3. package/README.md +25 -2
  4. package/array.gr +1512 -199
  5. package/array.md +2032 -94
  6. package/bigint.gr +239 -140
  7. package/bigint.md +450 -106
  8. package/buffer.gr +595 -102
  9. package/buffer.md +903 -145
  10. package/bytes.gr +401 -110
  11. package/bytes.md +551 -63
  12. package/char.gr +228 -49
  13. package/char.md +373 -7
  14. package/exception.gr +26 -12
  15. package/exception.md +29 -5
  16. package/float32.gr +130 -109
  17. package/float32.md +185 -57
  18. package/float64.gr +112 -99
  19. package/float64.md +185 -57
  20. package/hash.gr +47 -37
  21. package/hash.md +21 -3
  22. package/int16.gr +430 -0
  23. package/int16.md +618 -0
  24. package/int32.gr +200 -269
  25. package/int32.md +254 -289
  26. package/int64.gr +142 -225
  27. package/int64.md +254 -289
  28. package/int8.gr +511 -0
  29. package/int8.md +786 -0
  30. package/json.gr +2084 -0
  31. package/json.md +608 -0
  32. package/list.gr +120 -68
  33. package/list.md +125 -80
  34. package/map.gr +560 -57
  35. package/map.md +672 -56
  36. package/marshal.gr +239 -227
  37. package/marshal.md +36 -4
  38. package/number.gr +626 -676
  39. package/number.md +738 -153
  40. package/option.gr +33 -35
  41. package/option.md +58 -42
  42. package/package.json +2 -2
  43. package/path.gr +148 -187
  44. package/path.md +47 -96
  45. package/pervasives.gr +75 -416
  46. package/pervasives.md +85 -180
  47. package/priorityqueue.gr +433 -74
  48. package/priorityqueue.md +422 -54
  49. package/queue.gr +362 -80
  50. package/queue.md +433 -38
  51. package/random.gr +67 -75
  52. package/random.md +68 -40
  53. package/range.gr +135 -63
  54. package/range.md +198 -43
  55. package/rational.gr +284 -0
  56. package/rational.md +545 -0
  57. package/regex.gr +933 -1066
  58. package/regex.md +59 -60
  59. package/result.gr +23 -25
  60. package/result.md +54 -39
  61. package/runtime/atof/common.gr +78 -82
  62. package/runtime/atof/common.md +22 -10
  63. package/runtime/atof/decimal.gr +102 -127
  64. package/runtime/atof/decimal.md +28 -7
  65. package/runtime/atof/lemire.gr +56 -71
  66. package/runtime/atof/lemire.md +9 -1
  67. package/runtime/atof/parse.gr +83 -110
  68. package/runtime/atof/parse.md +12 -2
  69. package/runtime/atof/slow.gr +28 -35
  70. package/runtime/atof/slow.md +9 -1
  71. package/runtime/atof/table.gr +19 -18
  72. package/runtime/atof/table.md +10 -2
  73. package/runtime/atoi/parse.gr +153 -136
  74. package/runtime/atoi/parse.md +50 -1
  75. package/runtime/bigint.gr +410 -517
  76. package/runtime/bigint.md +71 -57
  77. package/runtime/compare.gr +176 -85
  78. package/runtime/compare.md +31 -1
  79. package/runtime/dataStructures.gr +144 -32
  80. package/runtime/dataStructures.md +267 -31
  81. package/runtime/debugPrint.gr +34 -15
  82. package/runtime/debugPrint.md +37 -5
  83. package/runtime/equal.gr +53 -52
  84. package/runtime/equal.md +30 -1
  85. package/runtime/exception.gr +38 -47
  86. package/runtime/exception.md +10 -8
  87. package/runtime/gc.gr +23 -152
  88. package/runtime/gc.md +13 -17
  89. package/runtime/malloc.gr +31 -31
  90. package/runtime/malloc.md +11 -3
  91. package/runtime/numberUtils.gr +191 -172
  92. package/runtime/numberUtils.md +17 -9
  93. package/runtime/numbers.gr +1695 -1021
  94. package/runtime/numbers.md +1098 -134
  95. package/runtime/string.gr +540 -242
  96. package/runtime/string.md +76 -6
  97. package/runtime/unsafe/constants.gr +30 -13
  98. package/runtime/unsafe/constants.md +80 -0
  99. package/runtime/unsafe/conv.gr +55 -28
  100. package/runtime/unsafe/conv.md +41 -9
  101. package/runtime/unsafe/memory.gr +10 -30
  102. package/runtime/unsafe/memory.md +15 -19
  103. package/runtime/unsafe/tags.gr +37 -21
  104. package/runtime/unsafe/tags.md +88 -8
  105. package/runtime/unsafe/wasmf32.gr +30 -36
  106. package/runtime/unsafe/wasmf32.md +64 -56
  107. package/runtime/unsafe/wasmf64.gr +30 -36
  108. package/runtime/unsafe/wasmf64.md +64 -56
  109. package/runtime/unsafe/wasmi32.gr +49 -66
  110. package/runtime/unsafe/wasmi32.md +102 -94
  111. package/runtime/unsafe/wasmi64.gr +52 -79
  112. package/runtime/unsafe/wasmi64.md +108 -100
  113. package/runtime/utils/printing.gr +13 -15
  114. package/runtime/utils/printing.md +11 -3
  115. package/runtime/wasi.gr +294 -295
  116. package/runtime/wasi.md +62 -42
  117. package/set.gr +574 -64
  118. package/set.md +634 -54
  119. package/stack.gr +181 -64
  120. package/stack.md +271 -42
  121. package/string.gr +453 -533
  122. package/string.md +241 -151
  123. package/uint16.gr +369 -0
  124. package/uint16.md +585 -0
  125. package/uint32.gr +470 -0
  126. package/uint32.md +737 -0
  127. package/uint64.gr +471 -0
  128. package/uint64.md +737 -0
  129. package/uint8.gr +369 -0
  130. package/uint8.md +585 -0
  131. package/uri.gr +1093 -0
  132. package/uri.md +477 -0
  133. package/{sys → wasi}/file.gr +914 -500
  134. package/{sys → wasi}/file.md +454 -50
  135. package/wasi/process.gr +292 -0
  136. package/{sys → wasi}/process.md +164 -6
  137. package/wasi/random.gr +77 -0
  138. package/wasi/random.md +80 -0
  139. package/{sys → wasi}/time.gr +15 -22
  140. package/{sys → wasi}/time.md +5 -5
  141. package/immutablearray.gr +0 -929
  142. package/immutablearray.md +0 -1038
  143. package/immutablemap.gr +0 -493
  144. package/immutablemap.md +0 -479
  145. package/immutablepriorityqueue.gr +0 -360
  146. package/immutablepriorityqueue.md +0 -291
  147. package/immutableset.gr +0 -498
  148. package/immutableset.md +0 -449
  149. package/runtime/debug.gr +0 -2
  150. package/runtime/debug.md +0 -6
  151. package/runtime/unsafe/errors.gr +0 -36
  152. package/runtime/unsafe/errors.md +0 -204
  153. package/sys/process.gr +0 -254
  154. package/sys/random.gr +0 -79
  155. package/sys/random.md +0 -66
package/marshal.gr CHANGED
@@ -1,10 +1,15 @@
1
1
  /**
2
- * @module Marshal: Utilities for serializing and deserializing Grain data.
2
+ * Utilities for serializing and deserializing Grain data.
3
3
  *
4
- * @example import Marshal from "marshal"
4
+ * @example from "marshal" include Marshal
5
+ *
6
+ * @example Marshal.marshal(1)
7
+ * @example Marshal.marshal("Hello World")
8
+ * @example Marshal.unmarshal(b"\x03\x00\x00\x00")
5
9
  *
6
10
  * @since v0.5.3
7
11
  */
12
+ module Marshal
8
13
 
9
14
  /*
10
15
  SERIALIZED BINARY FORMAT
@@ -20,16 +25,13 @@
20
25
  or a "pointer" to a heap-allocated value.
21
26
  */
22
27
 
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 (!=),
28
+ from "runtime/unsafe/wasmi32" include WasmI32
29
+ use WasmI32.{
30
+ (+),
31
+ (*),
32
+ (&),
33
+ (==),
34
+ (!=),
33
35
  gtU as (>),
34
36
  ltU as (<),
35
37
  leU as (<=),
@@ -37,14 +39,14 @@ import WasmI32, {
37
39
  store,
38
40
  fromGrain,
39
41
  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"
42
+ }
43
+ from "runtime/unsafe/wasmi64" include WasmI64
44
+ from "runtime/unsafe/memory" include Memory
45
+ from "runtime/unsafe/tags" include Tags
46
+ from "runtime/dataStructures" include DataStructures
47
+ use DataStructures.{ allocateBytes, newInt32 }
48
+ from "map" include Map
49
+ from "set" include Set
48
50
 
49
51
  @unsafe
50
52
  let roundTo8 = n => {
@@ -53,8 +55,7 @@ let roundTo8 = n => {
53
55
 
54
56
  @unsafe
55
57
  let isHeapPtr = value =>
56
- (value & Tags._GRAIN_GENERIC_TAG_MASK) ==
57
- Tags._GRAIN_GENERIC_HEAP_TAG_TYPE
58
+ (value & Tags._GRAIN_GENERIC_TAG_MASK) == Tags._GRAIN_GENERIC_HEAP_TAG_TYPE
58
59
 
59
60
  @unsafe
60
61
  let rec size = (value, acc, valuesSeen, toplevel) => {
@@ -74,9 +75,8 @@ let rec size = (value, acc, valuesSeen, toplevel) => {
74
75
  }
75
76
  let heapPtr = value
76
77
  match (load(heapPtr, 0n)) {
77
- t when (
78
- t == Tags._GRAIN_STRING_HEAP_TAG || t == Tags._GRAIN_BYTES_HEAP_TAG
79
- ) => {
78
+ t when t == Tags._GRAIN_STRING_HEAP_TAG ||
79
+ t == Tags._GRAIN_BYTES_HEAP_TAG => {
80
80
  acc + roundTo8(8n + load(heapPtr, 4n))
81
81
  },
82
82
  t when t == Tags._GRAIN_ADT_HEAP_TAG => {
@@ -142,14 +142,8 @@ let rec size = (value, acc, valuesSeen, toplevel) => {
142
142
  t when t == Tags._GRAIN_BOXED_NUM_HEAP_TAG => {
143
143
  let tag = load(heapPtr, 4n)
144
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
145
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG ||
146
+ t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
153
147
  acc + 16n
154
148
  },
155
149
  t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
@@ -166,6 +160,15 @@ let rec size = (value, acc, valuesSeen, toplevel) => {
166
160
  },
167
161
  }
168
162
  },
163
+ t when t == Tags._GRAIN_INT32_HEAP_TAG ||
164
+ t == Tags._GRAIN_FLOAT32_HEAP_TAG ||
165
+ t == Tags._GRAIN_UINT32_HEAP_TAG => {
166
+ acc + 8n
167
+ },
168
+ t when t == Tags._GRAIN_UINT64_HEAP_TAG => {
169
+ // 16 for alignment
170
+ acc + 16n
171
+ },
169
172
  _ => {
170
173
  fail "Unknown heap type"
171
174
  },
@@ -193,9 +196,7 @@ let rec marshalHeap = (heapPtr, buf, offset, valuesSeen) => {
193
196
  Map.set(asInt32, offsetAsInt32, valuesSeen)
194
197
 
195
198
  match (load(heapPtr, 0n)) {
196
- t when (
197
- t == Tags._GRAIN_STRING_HEAP_TAG || t == Tags._GRAIN_BYTES_HEAP_TAG
198
- ) => {
199
+ t when t == Tags._GRAIN_STRING_HEAP_TAG || t == Tags._GRAIN_BYTES_HEAP_TAG => {
199
200
  let size = 8n + load(heapPtr, 4n)
200
201
  Memory.copy(buf + offset, heapPtr, size)
201
202
  roundTo8(offset + size)
@@ -214,7 +215,7 @@ let rec marshalHeap = (heapPtr, buf, offset, valuesSeen) => {
214
215
  let asInt32 = toGrain(newInt32(value)): Int32
215
216
  match (Map.get(asInt32, valuesSeen)) {
216
217
  Some(value) => {
217
- let ptr = load(fromGrain(value), 8n)
218
+ let ptr = load(fromGrain(value), 4n)
218
219
  store(buf, ptr, offset + i + 20n)
219
220
  },
220
221
  None => {
@@ -243,7 +244,7 @@ let rec marshalHeap = (heapPtr, buf, offset, valuesSeen) => {
243
244
  let asInt32 = toGrain(newInt32(value)): Int32
244
245
  match (Map.get(asInt32, valuesSeen)) {
245
246
  Some(value) => {
246
- let ptr = load(fromGrain(value), 8n)
247
+ let ptr = load(fromGrain(value), 4n)
247
248
  store(buf, ptr, offset + i + 16n)
248
249
  },
249
250
  None => {
@@ -272,7 +273,7 @@ let rec marshalHeap = (heapPtr, buf, offset, valuesSeen) => {
272
273
  let asInt32 = toGrain(newInt32(value)): Int32
273
274
  match (Map.get(asInt32, valuesSeen)) {
274
275
  Some(value) => {
275
- let ptr = load(fromGrain(value), 8n)
276
+ let ptr = load(fromGrain(value), 4n)
276
277
  store(buf, ptr, offset + i + 8n)
277
278
  },
278
279
  None => {
@@ -301,7 +302,7 @@ let rec marshalHeap = (heapPtr, buf, offset, valuesSeen) => {
301
302
  let asInt32 = toGrain(newInt32(value)): Int32
302
303
  match (Map.get(asInt32, valuesSeen)) {
303
304
  Some(value) => {
304
- let ptr = load(fromGrain(value), 8n)
305
+ let ptr = load(fromGrain(value), 4n)
305
306
  store(buf, ptr, offset + i + 8n)
306
307
  },
307
308
  None => {
@@ -330,7 +331,7 @@ let rec marshalHeap = (heapPtr, buf, offset, valuesSeen) => {
330
331
  let asInt32 = toGrain(newInt32(value)): Int32
331
332
  match (Map.get(asInt32, valuesSeen)) {
332
333
  Some(value) => {
333
- let ptr = load(fromGrain(value), 8n)
334
+ let ptr = load(fromGrain(value), 4n)
334
335
  store(buf, ptr, offset + i + 16n)
335
336
  },
336
337
  None => {
@@ -348,10 +349,6 @@ let rec marshalHeap = (heapPtr, buf, offset, valuesSeen) => {
348
349
  t when t == Tags._GRAIN_BOXED_NUM_HEAP_TAG => {
349
350
  let tag = load(heapPtr, 4n)
350
351
  match (tag) {
351
- t when t == Tags._GRAIN_INT32_BOXED_NUM_TAG => {
352
- Memory.copy(buf + offset, heapPtr, 12n)
353
- offset + 16n
354
- },
355
352
  t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
356
353
  Memory.copy(buf + offset, heapPtr, 16n)
357
354
  offset + 16n
@@ -361,26 +358,22 @@ let rec marshalHeap = (heapPtr, buf, offset, valuesSeen) => {
361
358
  Memory.copy(buf + offset, heapPtr, size)
362
359
  offset + size
363
360
  },
364
- t when t == Tags._GRAIN_FLOAT32_BOXED_NUM_TAG => {
365
- Memory.copy(buf + offset, heapPtr, 12n)
366
- offset + 16n
367
- },
368
361
  t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
369
362
  Memory.copy(buf + offset, heapPtr, 16n)
370
363
  offset + 16n
371
364
  },
372
365
  t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
373
366
  Memory.copy(buf + offset, heapPtr, 8n)
374
- let mut payloadOffset = offset + 16n
367
+ let payloadOffset = offset + 16n
375
368
  store(buf, payloadOffset, offset + 8n)
376
- payloadOffset = marshalHeap(
369
+ let payloadOffset = marshalHeap(
377
370
  load(heapPtr, 8n),
378
371
  buf,
379
372
  payloadOffset,
380
373
  valuesSeen
381
374
  )
382
375
  store(buf, payloadOffset, offset + 12n)
383
- payloadOffset = marshalHeap(
376
+ let payloadOffset = marshalHeap(
384
377
  load(heapPtr, 12n),
385
378
  buf,
386
379
  payloadOffset,
@@ -393,6 +386,16 @@ let rec marshalHeap = (heapPtr, buf, offset, valuesSeen) => {
393
386
  },
394
387
  }
395
388
  },
389
+ t when t == Tags._GRAIN_INT32_HEAP_TAG ||
390
+ t == Tags._GRAIN_FLOAT32_HEAP_TAG ||
391
+ t == Tags._GRAIN_UINT32_HEAP_TAG => {
392
+ Memory.copy(buf + offset, heapPtr, 8n)
393
+ offset + 8n
394
+ },
395
+ t when t == Tags._GRAIN_UINT64_HEAP_TAG => {
396
+ Memory.copy(buf + offset, heapPtr, 16n)
397
+ offset + 16n
398
+ },
396
399
  _ => {
397
400
  fail "Unknown heap type"
398
401
  },
@@ -419,13 +422,19 @@ let marshal = (value, buf) => {
419
422
  * @param value: The value to serialize
420
423
  * @returns A byte-based representation of the value
421
424
  *
425
+ * @example Marshal.marshal(1) == b"\x03\x00\x00\x00"
426
+ * @example Marshal.marshal("🌾") == Marshal.marshal("🌾")
427
+ *
422
428
  * @since v0.5.3
423
429
  */
424
430
  @unsafe
425
- export let marshal = value => {
431
+ provide let marshal = value => {
426
432
  let valuePtr = fromGrain(value)
427
- let buf = allocateBytes(size(valuePtr))
433
+ let size = size(valuePtr)
434
+ let buf = allocateBytes(size)
435
+ Memory.fill(buf + 8n, 0n, size)
428
436
  marshal(valuePtr, buf + 8n)
437
+ ignore(value)
429
438
  toGrain(buf): Bytes
430
439
  }
431
440
 
@@ -440,13 +449,11 @@ let reportError = (message, offset) => {
440
449
  @unsafe
441
450
  let validateStack = (value, offset) => {
442
451
  match (value) {
443
- _ when (
444
- value == fromGrain(true) ||
452
+ _ when value == fromGrain(true) ||
445
453
  value == fromGrain(false) ||
446
454
  value == fromGrain(void) ||
447
455
  (value & Tags._GRAIN_NUMBER_TAG_MASK) == Tags._GRAIN_NUMBER_TAG_TYPE ||
448
- (value & Tags._GRAIN_GENERIC_TAG_MASK) == Tags._GRAIN_CHAR_TAG_TYPE
449
- ) =>
456
+ (value & Tags._GRAIN_GENERIC_TAG_MASK) == Tags._GRAIN_SHORTVAL_TAG_TYPE =>
450
457
  None,
451
458
  _ => reportError("Unknown value", offset),
452
459
  }
@@ -459,276 +466,281 @@ let rec validateHeap = (buf, bufSize, offset, valuesChecked) => {
459
466
 
460
467
  let valuePtr = buf + offset
461
468
  match (load(valuePtr, 0n)) {
462
- t when (
463
- t == Tags._GRAIN_STRING_HEAP_TAG || t == Tags._GRAIN_BYTES_HEAP_TAG
464
- ) => {
469
+ t when t == Tags._GRAIN_STRING_HEAP_TAG || t == Tags._GRAIN_BYTES_HEAP_TAG => {
465
470
  let size = 8n + load(valuePtr, 4n)
466
471
  if (offset + size > bufSize) {
467
- reportError("String/Bytes length exceeds buffer size", offset)
468
- } else {
469
- None
472
+ return reportError("String/Bytes length exceeds buffer size", offset)
470
473
  }
471
474
  },
472
475
  t when t == Tags._GRAIN_ADT_HEAP_TAG => {
473
476
  let arity = load(valuePtr, 16n)
474
477
  let size = 20n + arity * 4n
475
478
 
476
- let mut error = if (offset + size > bufSize) {
477
- reportError("Enum payload size exceeds buffer size", offset)
478
- } else {
479
- None
479
+ if (offset + size > bufSize) {
480
+ return reportError("Enum payload size exceeds buffer size", offset)
480
481
  }
481
482
 
482
483
  let a = arity * 4n
483
484
  for (let mut i = 0n; i < a; i += 4n) {
484
- if (Option.isSome(error)) break
485
-
486
485
  let value = load(valuePtr + i, 20n)
487
486
  if (isHeapPtr(value)) {
488
487
  let asInt32 = toGrain(newInt32(value)): Int32
489
488
  if (Set.contains(asInt32, valuesChecked)) {
490
489
  continue
491
490
  }
492
- error = Option.or(
493
- error,
494
- validateHeap(buf, bufSize, value, valuesChecked)
495
- )
491
+ match (validateHeap(buf, bufSize, value, valuesChecked)) {
492
+ Some(e) => return Some(e),
493
+ None => void,
494
+ }
496
495
  } else {
497
- error = Option.or(error, validateStack(value, offset))
496
+ match (validateStack(value, offset)) {
497
+ Some(e) => return Some(e),
498
+ None => void,
499
+ }
498
500
  }
499
501
  }
500
-
501
- error
502
502
  },
503
503
  t when t == Tags._GRAIN_RECORD_HEAP_TAG => {
504
504
  let arity = load(valuePtr, 12n)
505
505
  let size = 16n + arity * 4n
506
506
 
507
- let mut error = if (offset + size > bufSize) {
508
- reportError("Record payload size exceeds buffer size", offset)
509
- } else {
510
- None
507
+ if (offset + size > bufSize) {
508
+ return reportError("Record payload size exceeds buffer size", offset)
511
509
  }
512
510
 
513
511
  let a = arity * 4n
514
512
  for (let mut i = 0n; i < a; i += 4n) {
515
- if (Option.isSome(error)) break
516
-
517
513
  let value = load(valuePtr + i, 16n)
518
514
  if (isHeapPtr(value)) {
519
515
  let asInt32 = toGrain(newInt32(value)): Int32
520
516
  if (Set.contains(asInt32, valuesChecked)) {
521
517
  continue
522
518
  }
523
- error = Option.or(
524
- error,
525
- validateHeap(buf, bufSize, value, valuesChecked)
526
- )
519
+ match (validateHeap(buf, bufSize, value, valuesChecked)) {
520
+ Some(e) => return Some(e),
521
+ None => void,
522
+ }
527
523
  } else {
528
- error = Option.or(error, validateStack(value, offset))
524
+ match (validateStack(value, offset)) {
525
+ Some(e) => return Some(e),
526
+ None => void,
527
+ }
529
528
  }
530
529
  }
531
-
532
- error
533
530
  },
534
531
  t when t == Tags._GRAIN_ARRAY_HEAP_TAG => {
535
532
  let arity = load(valuePtr, 4n)
536
533
  let size = 8n + arity * 4n
537
534
 
538
- let mut error = if (offset + size > bufSize) {
539
- reportError("Array payload size exceeds buffer size", offset)
540
- } else {
541
- None
535
+ if (offset + size > bufSize) {
536
+ return reportError("Array payload size exceeds buffer size", offset)
542
537
  }
543
538
 
544
539
  let a = arity * 4n
545
540
  for (let mut i = 0n; i < a; i += 4n) {
546
- if (Option.isSome(error)) break
547
-
548
541
  let value = load(valuePtr + i, 8n)
549
542
  if (isHeapPtr(value)) {
550
543
  let asInt32 = toGrain(newInt32(value)): Int32
551
544
  if (Set.contains(asInt32, valuesChecked)) {
552
545
  continue
553
546
  }
554
- error = Option.or(
555
- error,
556
- validateHeap(buf, bufSize, value, valuesChecked)
557
- )
547
+ match (validateHeap(buf, bufSize, value, valuesChecked)) {
548
+ Some(e) => return Some(e),
549
+ None => void,
550
+ }
558
551
  } else {
559
- error = Option.or(error, validateStack(value, offset))
552
+ match (validateStack(value, offset)) {
553
+ Some(e) => return Some(e),
554
+ None => void,
555
+ }
560
556
  }
561
557
  }
562
-
563
- error
564
558
  },
565
559
  t when t == Tags._GRAIN_TUPLE_HEAP_TAG => {
566
560
  let arity = load(valuePtr, 4n)
567
561
  let size = 8n + arity * 4n
568
562
 
569
- let mut error = if (offset + size > bufSize) {
570
- reportError("Tuple payload size exceeds buffer size", offset)
571
- } else {
572
- None
563
+ if (offset + size > bufSize) {
564
+ return reportError("Tuple payload size exceeds buffer size", offset)
573
565
  }
574
566
 
575
567
  let a = arity * 4n
576
568
  for (let mut i = 0n; i < a; i += 4n) {
577
- if (Option.isSome(error)) break
578
-
579
569
  let value = load(valuePtr + i, 8n)
580
570
  if (isHeapPtr(value)) {
581
571
  let asInt32 = toGrain(newInt32(value)): Int32
582
572
  if (Set.contains(asInt32, valuesChecked)) {
583
573
  continue
584
574
  }
585
- error = Option.or(
586
- error,
587
- validateHeap(buf, bufSize, value, valuesChecked)
588
- )
575
+ match (validateHeap(buf, bufSize, value, valuesChecked)) {
576
+ Some(e) => return Some(e),
577
+ None => void,
578
+ }
589
579
  } else {
590
- error = Option.or(error, validateStack(value, offset))
580
+ match (validateStack(value, offset)) {
581
+ Some(e) => return Some(e),
582
+ None => void,
583
+ }
591
584
  }
592
585
  }
593
-
594
- error
595
586
  },
596
587
  t when t == Tags._GRAIN_LAMBDA_HEAP_TAG => {
597
588
  let arity = load(valuePtr, 12n)
598
589
  let size = 16n + arity * 4n
599
590
 
600
- let mut error = if (offset + size > bufSize) {
601
- reportError("Closure payload size exceeds buffer size", offset)
602
- } else {
603
- None
591
+ if (offset + size > bufSize) {
592
+ return reportError("Closure payload size exceeds buffer size", offset)
604
593
  }
605
594
 
606
595
  let a = arity * 4n
607
596
  for (let mut i = 0n; i < a; i += 4n) {
608
- if (Option.isSome(error)) break
609
-
610
597
  let value = load(valuePtr + i, 16n)
611
598
  if (isHeapPtr(value)) {
612
599
  let asInt32 = toGrain(newInt32(value)): Int32
613
600
  if (Set.contains(asInt32, valuesChecked)) {
614
601
  continue
615
602
  }
616
- error = Option.or(
617
- error,
618
- validateHeap(buf, bufSize, value, valuesChecked)
619
- )
603
+ match (validateHeap(buf, bufSize, value, valuesChecked)) {
604
+ Some(e) => return Some(e),
605
+ None => void,
606
+ }
620
607
  } else {
621
- error = Option.or(error, validateStack(value, offset))
608
+ match (validateStack(value, offset)) {
609
+ Some(e) => return Some(e),
610
+ None => void,
611
+ }
622
612
  }
623
613
  }
624
-
625
- error
626
614
  },
627
615
  t when t == Tags._GRAIN_BOXED_NUM_HEAP_TAG => {
628
616
  let tag = load(valuePtr, 4n)
629
617
  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
618
  t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
641
619
  if (offset + 16n > bufSize) {
642
- reportError(
620
+ return reportError(
643
621
  "Not enough bytes remaining in buffer for Int64/Number",
644
622
  offset
645
623
  )
646
- } else {
647
- None
648
624
  }
649
625
  },
650
626
  t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
651
627
  let size = 16n + load(valuePtr, 8n) * 8n
652
628
  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",
629
+ return reportError(
630
+ "BigInt/Number payload size exeeds buffer size",
662
631
  offset
663
632
  )
664
- } else {
665
- None
666
633
  }
667
634
  },
668
635
  t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
669
636
  if (offset + 16n > bufSize) {
670
- reportError(
637
+ return reportError(
671
638
  "Not enough bytes remaining in buffer for Float64/Number",
672
639
  offset
673
640
  )
674
- } else {
675
- None
676
641
  }
677
642
  },
678
643
  t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
679
644
  if (offset + 16n > bufSize) {
680
- reportError(
645
+ return reportError(
681
646
  "Not enough bytes remaining in buffer for Rational/Number",
682
647
  offset
683
648
  )
684
649
  } else {
685
650
  let numeratorOffset = load(valuePtr, 8n)
686
651
  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) !=
652
+ match (validateHeap(buf, bufSize, numeratorOffset, valuesChecked)) {
653
+ Some(err) => return Some(err),
654
+ None => void,
655
+ }
656
+ match (validateHeap(buf, bufSize, denominatorOffset, valuesChecked)) {
657
+ Some(err) => return Some(err),
658
+ None => void,
659
+ }
660
+ if (
661
+ load(buf, numeratorOffset) != Tags._GRAIN_BOXED_NUM_HEAP_TAG &&
662
+ load(buf, numeratorOffset + 4n) !=
663
+ Tags._GRAIN_BIGINT_BOXED_NUM_TAG
664
+ ) {
665
+ return reportError(
666
+ "Rational/Number numerator was not in the expected format",
667
+ offset
668
+ )
669
+ }
670
+ if (
671
+ load(buf, denominatorOffset) != Tags._GRAIN_BOXED_NUM_HEAP_TAG &&
672
+ load(buf, denominatorOffset + 4n) !=
673
+ Tags._GRAIN_BIGINT_BOXED_NUM_TAG
674
+ ) {
675
+ return reportError(
676
+ "Rational/Number denominator was not in the expected format",
677
+ offset
678
+ )
679
+ }
680
+ match (validateHeap(buf, bufSize, denominatorOffset, valuesChecked)) {
681
+ Some(e) => return Some(e),
682
+ None => void,
683
+ }
684
+ if (
685
+ load(buf, numeratorOffset) != Tags._GRAIN_BOXED_NUM_HEAP_TAG &&
686
+ load(buf, numeratorOffset + 4n) !=
695
687
  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) !=
688
+ ) {
689
+ return reportError(
690
+ "Rational/Number numerator was not in the expected format",
691
+ offset
692
+ )
693
+ }
694
+ let denominatorError = if (
695
+ load(buf, denominatorOffset) != Tags._GRAIN_BOXED_NUM_HEAP_TAG &&
696
+ load(buf, denominatorOffset + 4n) !=
708
697
  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
698
+ ) {
699
+ return reportError(
700
+ "Rational/Number denominator was not in the expected format",
701
+ offset
702
+ )
720
703
  }
721
704
  }
722
705
  },
723
- _ => {
724
- None
725
- },
706
+ _ => void,
726
707
  }
727
708
  },
728
- _ => {
729
- None
709
+ t when t == Tags._GRAIN_INT32_HEAP_TAG => {
710
+ if (offset + 8n > bufSize) {
711
+ return reportError(
712
+ "Not enough bytes remaining in buffer for Int32",
713
+ offset
714
+ )
715
+ }
716
+ },
717
+ t when t == Tags._GRAIN_FLOAT32_HEAP_TAG => {
718
+ if (offset + 8n > bufSize) {
719
+ return reportError(
720
+ "Not enough bytes remaining in buffer for Float32",
721
+ offset
722
+ )
723
+ }
724
+ },
725
+ t when t == Tags._GRAIN_UINT32_HEAP_TAG => {
726
+ if (offset + 8n > bufSize) {
727
+ return reportError(
728
+ "Not enough bytes remaining in buffer for Uint32",
729
+ offset
730
+ )
731
+ }
732
+ },
733
+ t when t == Tags._GRAIN_UINT64_HEAP_TAG => {
734
+ if (offset + 16n > bufSize) {
735
+ return reportError(
736
+ "Not enough bytes remaining in buffer for Uint64",
737
+ offset
738
+ )
739
+ }
730
740
  },
741
+ _ => void,
731
742
  }
743
+ return None
732
744
  }
733
745
 
734
746
  @unsafe
@@ -742,15 +754,12 @@ let validate = (buf, bufSize) => {
742
754
  } else {
743
755
  // Handle non-heap values: booleans, chars, void, etc.
744
756
  match (value) {
745
- _ when (
746
- value == fromGrain(true) ||
757
+ _ when value == fromGrain(true) ||
747
758
  value == fromGrain(false) ||
748
759
  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,
760
+ (value & Tags._GRAIN_NUMBER_TAG_MASK) == Tags._GRAIN_NUMBER_TAG_TYPE ||
761
+ (value & Tags._GRAIN_GENERIC_TAG_MASK) ==
762
+ Tags._GRAIN_SHORTVAL_TAG_TYPE => None,
754
763
  _ => reportError("Unknown value", 0n),
755
764
  }
756
765
  }
@@ -763,9 +772,7 @@ let rec unmarshalHeap = (buf, offset, valuesUnmarshaled) => {
763
772
 
764
773
  let valuePtr = buf + offset
765
774
  match (load(valuePtr, 0n)) {
766
- t when (
767
- t == Tags._GRAIN_STRING_HEAP_TAG || t == Tags._GRAIN_BYTES_HEAP_TAG
768
- ) => {
775
+ t when t == Tags._GRAIN_STRING_HEAP_TAG || t == Tags._GRAIN_BYTES_HEAP_TAG => {
769
776
  let size = 8n + load(valuePtr, 4n)
770
777
  let value = Memory.malloc(size)
771
778
  Memory.copy(value, valuePtr, size)
@@ -792,7 +799,7 @@ let rec unmarshalHeap = (buf, offset, valuesUnmarshaled) => {
792
799
  let asInt32 = toGrain(newInt32(subvalue)): Int32
793
800
  match (Map.get(asInt32, valuesUnmarshaled)) {
794
801
  Some(ptr) => {
795
- let ptr = load(fromGrain(ptr), 8n)
802
+ let ptr = load(fromGrain(ptr), 4n)
796
803
  store(value + i, Memory.incRef(ptr), 20n)
797
804
  },
798
805
  None => {
@@ -827,7 +834,7 @@ let rec unmarshalHeap = (buf, offset, valuesUnmarshaled) => {
827
834
  let asInt32 = toGrain(newInt32(subvalue)): Int32
828
835
  match (Map.get(asInt32, valuesUnmarshaled)) {
829
836
  Some(ptr) => {
830
- let ptr = load(fromGrain(ptr), 8n)
837
+ let ptr = load(fromGrain(ptr), 4n)
831
838
  store(value + i, Memory.incRef(ptr), 16n)
832
839
  },
833
840
  None => {
@@ -862,7 +869,7 @@ let rec unmarshalHeap = (buf, offset, valuesUnmarshaled) => {
862
869
  let asInt32 = toGrain(newInt32(subvalue)): Int32
863
870
  match (Map.get(asInt32, valuesUnmarshaled)) {
864
871
  Some(ptr) => {
865
- let ptr = load(fromGrain(ptr), 8n)
872
+ let ptr = load(fromGrain(ptr), 4n)
866
873
  store(value + i, Memory.incRef(ptr), 8n)
867
874
  },
868
875
  None => {
@@ -897,7 +904,7 @@ let rec unmarshalHeap = (buf, offset, valuesUnmarshaled) => {
897
904
  let asInt32 = toGrain(newInt32(subvalue)): Int32
898
905
  match (Map.get(asInt32, valuesUnmarshaled)) {
899
906
  Some(ptr) => {
900
- let ptr = load(fromGrain(ptr), 8n)
907
+ let ptr = load(fromGrain(ptr), 4n)
901
908
  store(value + i, Memory.incRef(ptr), 8n)
902
909
  },
903
910
  None => {
@@ -932,7 +939,7 @@ let rec unmarshalHeap = (buf, offset, valuesUnmarshaled) => {
932
939
  let asInt32 = toGrain(newInt32(subvalue)): Int32
933
940
  match (Map.get(asInt32, valuesUnmarshaled)) {
934
941
  Some(ptr) => {
935
- let ptr = load(fromGrain(ptr), 8n)
942
+ let ptr = load(fromGrain(ptr), 4n)
936
943
  store(value + i, Memory.incRef(ptr), 16n)
937
944
  },
938
945
  None => {
@@ -953,15 +960,6 @@ let rec unmarshalHeap = (buf, offset, valuesUnmarshaled) => {
953
960
  t when t == Tags._GRAIN_BOXED_NUM_HEAP_TAG => {
954
961
  let tag = load(valuePtr, 4n)
955
962
  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
963
  t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
966
964
  let value = Memory.malloc(16n)
967
965
  Memory.copy(value, valuePtr, 16n)
@@ -981,15 +979,6 @@ let rec unmarshalHeap = (buf, offset, valuesUnmarshaled) => {
981
979
 
982
980
  value
983
981
  },
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
982
  t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
994
983
  let value = Memory.malloc(16n)
995
984
  Memory.copy(value, valuePtr, 16n)
@@ -1017,6 +1006,26 @@ let rec unmarshalHeap = (buf, offset, valuesUnmarshaled) => {
1017
1006
  },
1018
1007
  }
1019
1008
  },
1009
+ t when t == Tags._GRAIN_INT32_HEAP_TAG ||
1010
+ t == Tags._GRAIN_FLOAT32_HEAP_TAG ||
1011
+ t == Tags._GRAIN_UINT32_HEAP_TAG => {
1012
+ let value = Memory.malloc(8n)
1013
+ Memory.copy(value, valuePtr, 8n)
1014
+
1015
+ let asInt32 = toGrain(newInt32(value)): Int32
1016
+ Map.set(offsetAsInt32, asInt32, valuesUnmarshaled)
1017
+
1018
+ value
1019
+ },
1020
+ t when t == Tags._GRAIN_UINT64_HEAP_TAG => {
1021
+ let value = Memory.malloc(16n)
1022
+ Memory.copy(value, valuePtr, 16n)
1023
+
1024
+ let asInt32 = toGrain(newInt32(value)): Int32
1025
+ Map.set(offsetAsInt32, asInt32, valuesUnmarshaled)
1026
+
1027
+ value
1028
+ },
1020
1029
  _ => {
1021
1030
  fail "Unknown heap type"
1022
1031
  },
@@ -1045,10 +1054,13 @@ let unmarshal = buf => {
1045
1054
  * @param bytes: The data to deserialize
1046
1055
  * @returns An in-memory value
1047
1056
  *
1057
+ * @example Marshal.unmarshal(Marshal.marshal('🌾')) == Ok('🌾')
1058
+ * @example Marshal.unmarshal(b"\x03\x00\x00\x00") == Ok(1)
1059
+ *
1048
1060
  * @since v0.5.3
1049
1061
  */
1050
1062
  @unsafe
1051
- export let unmarshal = (bytes: Bytes) => {
1063
+ provide let unmarshal = (bytes: Bytes) => {
1052
1064
  let buf = fromGrain(bytes) + 8n
1053
1065
  let bufSize = load(fromGrain(bytes), 4n)
1054
1066
  match (validate(buf, bufSize)) {