@grain/stdlib 0.5.13 → 0.6.1

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 +201 -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 +62 -40
  21. package/hash.md +27 -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 +2071 -0
  31. package/json.md +646 -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 +193 -174
  92. package/runtime/numberUtils.md +29 -9
  93. package/runtime/numbers.gr +1695 -1021
  94. package/runtime/numbers.md +1098 -134
  95. package/runtime/string.gr +543 -245
  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
@@ -1,56 +1,60 @@
1
1
  /**
2
- * @module File: Utilities for accessing the filesystem & working with files.
2
+ * Utilities for accessing the filesystem & working with files.
3
3
  *
4
4
  * Many of the functions in this module are not intended to be used directly, but rather for other libraries to be built on top of them.
5
5
  *
6
- * @example import File from "sys/file"
6
+ * @example from "wasi/file" include File
7
7
  */
8
-
9
- import WasmI32, {
10
- add as (+),
11
- sub as (-),
12
- mul as (*),
13
- shl as (<<),
14
- shrS as (>>),
15
- shrU as (>>>),
16
- eq as (==),
17
- ne as (!=),
18
- ltS as (<),
19
- leS as (<=),
20
- gtS as (>),
21
- geS as (>=),
22
- and as (&),
23
- or as (|),
24
- } from "runtime/unsafe/wasmi32"
25
- import WasmI64 from "runtime/unsafe/wasmi64"
26
- import Wasi from "runtime/wasi"
27
- import Memory from "runtime/unsafe/memory"
28
- import {
8
+ module File
9
+
10
+ from "runtime/unsafe/wasmi32" include WasmI32
11
+ use WasmI32.{
12
+ (+),
13
+ (-),
14
+ (*),
15
+ (<<),
16
+ (>>),
17
+ (>>>),
18
+ (==),
19
+ (!=),
20
+ (<),
21
+ (<=),
22
+ (>),
23
+ (>=),
24
+ (&),
25
+ (|),
26
+ }
27
+ from "runtime/unsafe/wasmi64" include WasmI64
28
+ from "runtime/wasi" include Wasi
29
+ from "runtime/unsafe/memory" include Memory
30
+ from "runtime/dataStructures" include DataStructures
31
+ use DataStructures.{
29
32
  tagSimpleNumber,
33
+ untagSimpleNumber,
30
34
  allocateArray,
35
+ allocateBytes,
31
36
  allocateString,
37
+ newInt32,
32
38
  newInt64,
33
39
  allocateInt64,
34
- } from "runtime/dataStructures"
35
-
36
- import List from "list"
40
+ }
37
41
 
38
- /**
39
- * @section Types: Type declarations included in the File module.
40
- */
42
+ from "list" include List
41
43
 
42
44
  /**
43
45
  * Represents a handle to an open file on the system.
44
46
  */
45
- export enum FileDescriptor {
47
+ provide enum FileDescriptor {
46
48
  FileDescriptor(Number),
47
49
  }
48
50
 
49
51
  /**
50
52
  * Flags that determine how paths should be resolved when looking up a file or directory.
51
53
  */
52
- export enum LookupFlag {
53
- // Follow symlinks
54
+ provide enum LookupFlag {
55
+ /**
56
+ * Follow symlinks
57
+ */
54
58
  SymlinkFollow,
55
59
  }
56
60
 
@@ -75,14 +79,22 @@ let combineLookupFlags = dirflags => {
75
79
  /**
76
80
  * Flags that determine how a file or directory should be opened.
77
81
  */
78
- export enum OpenFlag {
79
- // Create file if it does not exist.
82
+ provide enum OpenFlag {
83
+ /**
84
+ * Create file if it does not exist.
85
+ */
80
86
  Create,
81
- // Fail if not a directory.
87
+ /**
88
+ * Fail if not a directory.
89
+ */
82
90
  Directory,
83
- // Fail if file already exists.
91
+ /**
92
+ * Fail if file already exists.
93
+ */
84
94
  Exclusive,
85
- // Truncate file to size 0.
95
+ /**
96
+ * Truncate file to size 0.
97
+ */
86
98
  Truncate,
87
99
  }
88
100
 
@@ -111,76 +123,134 @@ let combineOpenFlags = dirflags => {
111
123
  * Flags that determine which rights a `FileDescriptor` should have
112
124
  * and which rights new `FileDescriptor`s should inherit from it.
113
125
  */
114
- export enum Rights {
115
- // The right to invoke `fdDatasync`.
116
- // If `PathOpen` is set, includes the right to invoke
117
- // `pathOpen` with `FdFlag::Dsync`.
126
+ provide enum Rights {
127
+ /**
128
+ * The right to invoke `fdDatasync`.
129
+ * If `PathOpen` is set, includes the right to invoke
130
+ * `pathOpen` with `FdFlag::Dsync`.
131
+ */
118
132
  FdDatasync,
119
- // The right to invoke `fdRead`.
120
- // If `Rights::FdSeek` is set, includes the right to invoke `fdPread`.
133
+ /**
134
+ * The right to invoke `fdRead`.
135
+ * If `Rights::FdSeek` is set, includes the right to invoke `fdPread`.
136
+ */
121
137
  FdRead,
122
- // The right to invoke `fdSeek`. This flag implies `Rights::FdTell`.
138
+ /**
139
+ * The right to invoke `fdSeek`. This flag implies `Rights::FdTell`.
140
+ */
123
141
  FdSeek,
124
- // The right to invoke `fdSetFlags`.
142
+ /**
143
+ * The right to invoke `fdSetFlags`.
144
+ */
125
145
  FdSetFlags,
126
- // The right to invoke `fdSync`.
127
- // If `PathOpen` is set, includes the right to invoke
128
- // `pathOpen` with `FdFlag::Rsync` and `FdFlag::Dsync`.
146
+ /**
147
+ * The right to invoke `fdSync`.
148
+ * If `PathOpen` is set, includes the right to invoke
149
+ * `pathOpen` with `FdFlag::Rsync` and `FdFlag::Dsync`.
150
+ */
129
151
  FdSync,
130
- // The right to invoke `fdSeek` in such a way that the file offset
131
- // remains unaltered (i.e., `Whence::Current` with offset zero), or to
132
- // invoke `fdTell`.
152
+ /**
153
+ * The right to invoke `fdSeek` in such a way that the file offset
154
+ * remains unaltered (i.e., `Whence::Current` with offset zero), or to
155
+ * invoke `fdTell`.
156
+ */
133
157
  FdTell,
134
- // The right to invoke `fdWrite`.
135
- // If `Rights::FdSeek` is set, includes the right to invoke `fdPwrite`.
158
+ /**
159
+ * The right to invoke `fdWrite`.
160
+ * If `Rights::FdSeek` is set, includes the right to invoke `fdPwrite`.
161
+ */
136
162
  FdWrite,
137
- // The right to invoke `fdAdvise`.
163
+ /**
164
+ * The right to invoke `fdAdvise`.
165
+ */
138
166
  FdAdvise,
139
- // The right to invoke `fdAllocate`.
167
+ /**
168
+ * The right to invoke `fdAllocate`.
169
+ */
140
170
  FdAllocate,
141
- // The right to invoke `pathCreateDirectory`.
171
+ /**
172
+ * The right to invoke `pathCreateDirectory`.
173
+ */
142
174
  PathCreateDirectory,
143
- // If `PathOpen` is set, the right to invoke `pathOpen` with `OpenFlag::Create`.
175
+ /**
176
+ * If `PathOpen` is set, the right to invoke `pathOpen` with `OpenFlag::Create`.
177
+ */
144
178
  PathCreateFile,
145
- // The right to invoke `pathLink` with the file descriptor as the
146
- // source directory.
179
+ /**
180
+ * The right to invoke `pathLink` with the file descriptor as the
181
+ * source directory.
182
+ */
147
183
  PathLinkSource,
148
- // The right to invoke `pathLink` with the file descriptor as the
149
- // target directory.
184
+ /**
185
+ * The right to invoke `pathLink` with the file descriptor as the
186
+ * target directory.
187
+ */
150
188
  PathLinkTarget,
151
- // The right to invoke `pathOpen`.
189
+ /**
190
+ * The right to invoke `pathOpen`.
191
+ */
152
192
  PathOpen,
153
- // The right to invoke `fdReaddir`.
193
+ /**
194
+ * The right to invoke `fdReaddir`.
195
+ */
154
196
  FdReaddir,
155
- // The right to invoke `pathReadlink`.
197
+ /**
198
+ * The right to invoke `pathReadlink`.
199
+ */
156
200
  PathReadlink,
157
- // The right to invoke `pathRename` with the file descriptor as the source directory.
201
+ /**
202
+ * The right to invoke `pathRename` with the file descriptor as the source directory.
203
+ */
158
204
  PathRenameSource,
159
- // The right to invoke `pathRename` with the file descriptor as the target directory.
205
+ /**
206
+ * The right to invoke `pathRename` with the file descriptor as the target directory.
207
+ */
160
208
  PathRenameTarget,
161
- // The right to invoke `pathFilestats`.
209
+ /**
210
+ * The right to invoke `pathFilestats`.
211
+ */
162
212
  PathFilestats,
163
- // The right to change a file's size (there's no `pathSetSize`).
164
- // If `PathOpen` is set, includes the right to invoke `pathOpen` with `OpenFlag::Truncate`.
213
+ /**
214
+ * The right to change a file's size (there's no `pathSetSize`).
215
+ * If `PathOpen` is set, includes the right to invoke `pathOpen` with `OpenFlag::Truncate`.
216
+ */
165
217
  PathSetSize,
166
- // The right to invoke `pathSetAccessTime`, `pathSetAccessTimeNow`, `pathSetModifiedTime`, or `pathSetModifiedTimeNow`.
218
+ /**
219
+ * The right to invoke `pathSetAccessTime`, `pathSetAccessTimeNow`, `pathSetModifiedTime`, or `pathSetModifiedTimeNow`.
220
+ */
167
221
  PathSetTimes,
168
- // The right to invoke `fdFilestats`.
222
+ /**
223
+ * The right to invoke `fdFilestats`.
224
+ */
169
225
  FdFilestats,
170
- // The right to invoke `fdSetSize`.
226
+ /**
227
+ * The right to invoke `fdSetSize`.
228
+ */
171
229
  FdSetSize,
172
- // The right to invoke `fdSetAccessTime`, `fdSetAccessTimeNow`, `fdSetModifiedTime`, or `fdSetModifiedTimeNow`.
230
+ /**
231
+ * The right to invoke `fdSetAccessTime`, `fdSetAccessTimeNow`, `fdSetModifiedTime`, or `fdSetModifiedTimeNow`.
232
+ */
173
233
  FdSetTimes,
174
- // The right to invoke `pathSymlink`.
234
+ /**
235
+ * The right to invoke `pathSymlink`.
236
+ */
175
237
  PathSymlink,
176
- // The right to invoke `pathRemoveDirectory`.
238
+ /**
239
+ * The right to invoke `pathRemoveDirectory`.
240
+ */
177
241
  PathRemoveDirectory,
178
- // The right to invoke `pathUnlinkFile`.
242
+ /**
243
+ * The right to invoke `pathUnlinkFile`.
244
+ */
179
245
  PathUnlinkFile,
180
- // If `Rights::FdRead` is set, includes the right to invoke `pollOneoff` (not yet implemented) to subscribe to `EventType::FdRead`.
181
- // If `Rights::FdWrite` is set, includes the right to invoke `pollOneoff` (not yet implemented) to subscribe to `EventType::FdWrite`.
246
+ /**
247
+ * If `Rights::FdRead` is set, includes the right to invoke `pollOneoff` (not yet implemented) to subscribe to `EventType::FdRead`.
248
+ * If `Rights::FdWrite` is set, includes the right to invoke `pollOneoff` (not yet implemented) to subscribe to `EventType::FdWrite`.
249
+ */
182
250
  PollFdReadwrite,
183
- // The right to invoke `sockShutdown` (not yet implemented).
251
+ /**
252
+ * The right to invoke `sockShutdown` (not yet implemented).
253
+ */
184
254
  SockShutdown,
185
255
  }
186
256
 
@@ -248,6 +318,7 @@ let _RIGHT_SOCK_SHUTDOWN = 268435456N
248
318
  // TODO(#775): This has specific ordering requirements because of ambiguous type inference
249
319
  @unsafe
250
320
  let rec combineRightsHelp = (acc, dirflags) => {
321
+ use WasmI64.{ (|) }
251
322
  match (dirflags) {
252
323
  [] => acc,
253
324
  [hd, ...tl] => {
@@ -288,7 +359,7 @@ let rec combineRightsHelp = (acc, dirflags) => {
288
359
  0N
289
360
  },
290
361
  }
291
- combineRightsHelp(WasmI64.or(flag, acc), tl)
362
+ combineRightsHelp(flag | acc, tl)
292
363
  },
293
364
  }
294
365
  }
@@ -300,14 +371,22 @@ let combineRights = dirflags => {
300
371
  /**
301
372
  * Flags that determine the mode(s) that a `FileDescriptor` operates in.
302
373
  */
303
- export enum FdFlag {
304
- // Append mode: Data written to the file is always appended to the file's end.
374
+ provide enum FdFlag {
375
+ /**
376
+ * Append mode: Data written to the file is always appended to the file's end.
377
+ */
305
378
  Append,
306
- // Write according to synchronized I/O data integrity completion. Only the data stored in the file is synchronized.
379
+ /**
380
+ * Write according to synchronized I/O data integrity completion. Only the data stored in the file is synchronized.
381
+ */
307
382
  Dsync,
308
- // Non-blocking mode.
383
+ /**
384
+ * Non-blocking mode.
385
+ */
309
386
  Nonblock,
310
- // Synchronized read I/O operations.
387
+ /**
388
+ * Synchronized read I/O operations.
389
+ */
311
390
  Rsync,
312
391
  // Write according to synchronized I/O file integrity completion. In
313
392
  // addition to synchronizing the data stored in the file, the implementation
@@ -340,22 +419,38 @@ let combineFdFlags = dirflags => {
340
419
  /**
341
420
  * The type of file a `FileDescriptor` refers to.
342
421
  */
343
- export enum Filetype {
344
- // The type of the file descriptor or file is unknown or is different from any of the other types specified.
422
+ provide enum Filetype {
423
+ /**
424
+ * The type of the file descriptor or file is unknown or is different from any of the other types specified.
425
+ */
345
426
  Unknown,
346
- // The file descriptor or file refers to a block device inode.
427
+ /**
428
+ * The file descriptor or file refers to a block device inode.
429
+ */
347
430
  BlockDevice,
348
- // The file descriptor or file refers to a character device inode.
431
+ /**
432
+ * The file descriptor or file refers to a character device inode.
433
+ */
349
434
  CharacterDevice,
350
- // The file descriptor or file refers to a directory inode.
435
+ /**
436
+ * The file descriptor or file refers to a directory inode.
437
+ */
351
438
  Directory,
352
- // The file descriptor or file refers to a regular file inode.
439
+ /**
440
+ * The file descriptor or file refers to a regular file inode.
441
+ */
353
442
  RegularFile,
354
- // The file descriptor or file refers to a datagram socket.
443
+ /**
444
+ * The file descriptor or file refers to a datagram socket.
445
+ */
355
446
  SocketDatagram,
356
- // The file descriptor or file refers to a byte-stream socket.
447
+ /**
448
+ * The file descriptor or file refers to a byte-stream socket.
449
+ */
357
450
  SocketStream,
358
- // The file refers to a symbolic link inode.
451
+ /**
452
+ * The file refers to a symbolic link inode.
453
+ */
359
454
  SymbolicLink,
360
455
  }
361
456
 
@@ -378,19 +473,25 @@ let filetypeFromNumber = filetype => {
378
473
  /**
379
474
  * Flags that determine where seeking should begin in a file.
380
475
  */
381
- export enum Whence {
382
- // Seek relative to start-of-file.
476
+ provide enum Whence {
477
+ /**
478
+ * Seek relative to start-of-file.
479
+ */
383
480
  Set,
384
- // Seek relative to current position.
481
+ /**
482
+ * Seek relative to current position.
483
+ */
385
484
  Current,
386
- // Seek relative to end-of-file.
485
+ /**
486
+ * Seek relative to end-of-file.
487
+ */
387
488
  End,
388
489
  }
389
490
 
390
491
  /**
391
492
  * Information about a `FileDescriptor`.
392
493
  */
393
- export record Stats {
494
+ provide record Stats {
394
495
  filetype: Filetype,
395
496
  flags: List<FdFlag>,
396
497
  rights: List<Rights>,
@@ -400,7 +501,7 @@ export record Stats {
400
501
  /**
401
502
  * Information about the file that a `FileDescriptor` refers to.
402
503
  */
403
- export record Filestats {
504
+ provide record Filestats {
404
505
  device: Int64,
405
506
  inode: Int64,
406
507
  filetype: Filetype,
@@ -414,32 +515,31 @@ export record Filestats {
414
515
  /**
415
516
  * An entry in a directory.
416
517
  */
417
- export record DirectoryEntry {
518
+ provide record DirectoryEntry {
418
519
  inode: Int64,
419
520
  filetype: Filetype,
420
521
  path: String,
421
522
  }
422
523
 
423
524
  /**
424
- * @section Values: Functions and constants included in the File module.
525
+ * Information about a preopened directory
425
526
  */
527
+ provide enum Prestat {
528
+ Dir{ prefix: String, fd: FileDescriptor },
529
+ }
426
530
 
427
531
  /**
428
532
  * The `FileDescriptor` for `stdin`.
429
533
  */
430
- export let stdin = FileDescriptor(0)
534
+ provide let stdin = FileDescriptor(0)
431
535
  /**
432
536
  * The `FileDescriptor` for `stdout`.
433
537
  */
434
- export let stdout = FileDescriptor(1)
538
+ provide let stdout = FileDescriptor(1)
435
539
  /**
436
540
  * The `FileDescriptor` for `stderr`.
437
541
  */
438
- export let stderr = FileDescriptor(2)
439
- /**
440
- * The `FileDescriptor` for the current working directory of the process.
441
- */
442
- export let pwdfd = FileDescriptor(3)
542
+ provide let stderr = FileDescriptor(2)
443
543
 
444
544
  /**
445
545
  * Open a file or directory.
@@ -454,20 +554,21 @@ export let pwdfd = FileDescriptor(3)
454
554
  * @returns `Ok(fd)` of the opened file or directory if successful or `Err(exception)` otherwise
455
555
  */
456
556
  @unsafe
457
- export let pathOpen =
458
- (
459
- dirFd: FileDescriptor,
460
- dirFlags: List<LookupFlag>,
461
- path: String,
462
- openFlags: List<OpenFlag>,
463
- rights: List<Rights>,
464
- rightsInheriting: List<Rights>,
465
- flags: List<FdFlag>,
466
- ) => {
557
+ provide let pathOpen = (
558
+ dirFd: FileDescriptor,
559
+ dirFlags: List<LookupFlag>,
560
+ path: String,
561
+ openFlags: List<OpenFlag>,
562
+ rights: List<Rights>,
563
+ rightsInheriting: List<Rights>,
564
+ flags: List<FdFlag>,
565
+ ) => {
467
566
  let dirFdArg = dirFd
468
567
  let pathArg = path
469
568
  let rightsInheritingArg = rightsInheriting
470
- let dirFd = match (dirFd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
569
+ let dirFd = match (dirFd) {
570
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
571
+ }
471
572
 
472
573
  let combinedDirFlags = combineLookupFlags(dirFlags)
473
574
 
@@ -495,16 +596,15 @@ export let pathOpen =
495
596
  combinedFsFlags,
496
597
  newFd
497
598
  )
498
- if (err != Wasi._ESUCCESS) {
499
- Memory.free(newFd)
500
- Err(Wasi.SystemError(tagSimpleNumber(err)))
501
- } else {
502
- let fd = FileDescriptor(tagSimpleNumber(WasmI32.load(newFd, 0n)))
503
599
 
600
+ if (err != Wasi._ESUCCESS) {
504
601
  Memory.free(newFd)
505
-
506
- Ok(fd)
602
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
507
603
  }
604
+
605
+ let fd = FileDescriptor(tagSimpleNumber(WasmI32.load(newFd, 0n)))
606
+ Memory.free(newFd)
607
+ return Ok(fd)
508
608
  }
509
609
 
510
610
  /**
@@ -515,14 +615,16 @@ export let pathOpen =
515
615
  * @returns `Ok((contents, numBytes))` of bytes read and the number of bytes read if successful or `Err(exception)` otherwise
516
616
  */
517
617
  @unsafe
518
- export let fdRead = (fd: FileDescriptor, size: Number) => {
618
+ provide let fdRead = (fd: FileDescriptor, size: Number) => {
519
619
  let fdArg = fd
520
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
620
+ let fd = match (fd) {
621
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
622
+ }
521
623
 
522
624
  let n = WasmI32.fromGrain(size) >> 1n
523
625
 
524
626
  let iovs = Memory.malloc(3n * 4n)
525
- let strPtr = allocateString(n)
627
+ let strPtr = allocateBytes(n)
526
628
 
527
629
  WasmI32.store(iovs, strPtr + 2n * 4n, 0n)
528
630
  WasmI32.store(iovs, n, 4n)
@@ -533,16 +635,13 @@ export let fdRead = (fd: FileDescriptor, size: Number) => {
533
635
  if (err != Wasi._ESUCCESS) {
534
636
  Memory.free(iovs)
535
637
  Memory.free(strPtr)
536
- Err(Wasi.SystemError(tagSimpleNumber(err)))
537
- } else {
538
- nread = WasmI32.load(nread, 0n)
539
-
540
- WasmI32.store(strPtr, nread, 4n)
541
-
542
- Memory.free(iovs)
543
-
544
- Ok((WasmI32.toGrain(strPtr): String, tagSimpleNumber(nread)))
638
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
545
639
  }
640
+
641
+ nread = WasmI32.load(nread, 0n)
642
+ WasmI32.store(strPtr, nread, 4n)
643
+ Memory.free(iovs)
644
+ return Ok((WasmI32.toGrain(strPtr): Bytes, tagSimpleNumber(nread)))
546
645
  }
547
646
 
548
647
  /**
@@ -554,17 +653,19 @@ export let fdRead = (fd: FileDescriptor, size: Number) => {
554
653
  * @returns `Ok((contents, numBytes))` of bytes read and the number of bytes read if successful or `Err(exception)` otherwise
555
654
  */
556
655
  @unsafe
557
- export let fdPread = (fd: FileDescriptor, offset: Int64, size: Number) => {
656
+ provide let fdPread = (fd: FileDescriptor, offset: Int64, size: Number) => {
558
657
  let fdArg = fd
559
658
  let offsetArg = offset
560
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
659
+ let fd = match (fd) {
660
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
661
+ }
561
662
 
562
663
  let offset = WasmI64.load(WasmI32.fromGrain(offset), 8n)
563
664
 
564
665
  let n = WasmI32.fromGrain(size) >> 1n
565
666
 
566
667
  let iovs = Memory.malloc(3n * 4n)
567
- let strPtr = allocateString(n)
668
+ let strPtr = allocateBytes(n)
568
669
 
569
670
  WasmI32.store(iovs, strPtr + 2n * 4n, 0n)
570
671
  WasmI32.store(iovs, n, 4n)
@@ -575,16 +676,60 @@ export let fdPread = (fd: FileDescriptor, offset: Int64, size: Number) => {
575
676
  if (err != Wasi._ESUCCESS) {
576
677
  Memory.free(iovs)
577
678
  Memory.free(strPtr)
578
- Err(Wasi.SystemError(tagSimpleNumber(err)))
579
- } else {
580
- nread = WasmI32.load(nread, 0n)
679
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
680
+ }
581
681
 
582
- WasmI32.store(strPtr, nread, 4n)
682
+ nread = WasmI32.load(nread, 0n)
683
+ WasmI32.store(strPtr, nread, 4n)
684
+ Memory.free(iovs)
685
+ return Ok((WasmI32.toGrain(strPtr): Bytes, tagSimpleNumber(nread)))
686
+ }
583
687
 
584
- Memory.free(iovs)
688
+ /**
689
+ * Get information about a preopened directory.
690
+ *
691
+ * @param fd: The file descriptor to check
692
+ * @returns `Ok(Dir{prefix, fd})` if successful or `Err(exception)` otherwise
693
+ *
694
+ * @since v0.6.0
695
+ */
696
+ @unsafe
697
+ provide let fdPrestatGet = (fd: FileDescriptor) => {
698
+ let fdArg = fd
699
+ let fd = match (fd) {
700
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
701
+ }
702
+
703
+ let dir = Memory.malloc(8n)
704
+ let err = Wasi.fd_prestat_get(fd, dir)
705
+ if (err != Wasi._ESUCCESS) {
706
+ Memory.free(dir)
707
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
708
+ }
709
+
710
+ let prefixLen = WasmI32.load(dir, 4n)
711
+ Memory.free(dir)
712
+
713
+ let prefix = allocateString(prefixLen)
714
+ let err = Wasi.fd_prestat_dir_name(fd, prefix + 8n, prefixLen)
715
+ if (err != Wasi._ESUCCESS) {
716
+ Memory.free(prefix)
717
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
718
+ }
585
719
 
586
- Ok((WasmI32.toGrain(strPtr): String, tagSimpleNumber(nread)))
720
+ if (
721
+ prefixLen > 0n &&
722
+ WasmI32.eqz(WasmI32.load8U(prefix + prefixLen - 1n, 8n))
723
+ ) {
724
+ // in uvwasi environments the string is null-terminated and the size is reported including it
725
+ // https://github.com/grain-lang/grain/issues/1818
726
+ WasmI32.store(prefix, prefixLen - 1n, 4n)
587
727
  }
728
+
729
+ let prefix = WasmI32.toGrain(prefix): String
730
+ let fd = fdArg
731
+
732
+ return Ok(Dir{ prefix, fd })
588
733
  }
589
734
 
590
735
  /**
@@ -595,9 +740,11 @@ export let fdPread = (fd: FileDescriptor, offset: Int64, size: Number) => {
595
740
  * @returns `Ok(numBytes)` of the number of bytes written if successful or `Err(Exception)` otherwise
596
741
  */
597
742
  @unsafe
598
- export let fdWrite = (fd: FileDescriptor, data: String) => {
743
+ provide let fdWrite = (fd: FileDescriptor, data: Bytes) => {
599
744
  let fdArg = fd
600
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
745
+ let fd = match (fd) {
746
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
747
+ }
601
748
 
602
749
  let iovs = Memory.malloc(3n * 4n)
603
750
  let strPtr = WasmI32.fromGrain(data)
@@ -610,14 +757,12 @@ export let fdWrite = (fd: FileDescriptor, data: String) => {
610
757
  let err = Wasi.fd_write(fd, iovs, 1n, nwritten)
611
758
  if (err != Wasi._ESUCCESS) {
612
759
  Memory.free(iovs)
613
- Err(Wasi.SystemError(tagSimpleNumber(err)))
614
- } else {
615
- nwritten = WasmI32.load(nwritten, 0n)
616
-
617
- Memory.free(iovs)
618
-
619
- Ok(tagSimpleNumber(nwritten))
760
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
620
761
  }
762
+
763
+ nwritten = WasmI32.load(nwritten, 0n)
764
+ Memory.free(iovs)
765
+ return Ok(tagSimpleNumber(nwritten))
621
766
  }
622
767
 
623
768
  /**
@@ -629,10 +774,12 @@ export let fdWrite = (fd: FileDescriptor, data: String) => {
629
774
  * @returns `Ok(numBytes)` of the number of bytes written if successful or `Err(exception)` otherwise
630
775
  */
631
776
  @unsafe
632
- export let fdPwrite = (fd: FileDescriptor, data: String, offset: Int64) => {
777
+ provide let fdPwrite = (fd: FileDescriptor, data: Bytes, offset: Int64) => {
633
778
  let fdArg = fd
634
779
  let offsetArg = offset
635
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
780
+ let fd = match (fd) {
781
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
782
+ }
636
783
 
637
784
  let iovs = Memory.malloc(3n * 4n)
638
785
  let strPtr = WasmI32.fromGrain(data)
@@ -647,14 +794,12 @@ export let fdPwrite = (fd: FileDescriptor, data: String, offset: Int64) => {
647
794
  let err = Wasi.fd_pwrite(fd, iovs, 1n, offset, nwritten)
648
795
  if (err != Wasi._ESUCCESS) {
649
796
  Memory.free(iovs)
650
- Err(Wasi.SystemError(tagSimpleNumber(err)))
651
- } else {
652
- nwritten = WasmI32.load(nwritten, 0n)
653
-
654
- Memory.free(iovs)
655
-
656
- Ok(tagSimpleNumber(nwritten))
797
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
657
798
  }
799
+
800
+ nwritten = WasmI32.load(nwritten, 0n)
801
+ Memory.free(iovs)
802
+ return Ok(tagSimpleNumber(nwritten))
658
803
  }
659
804
 
660
805
  /**
@@ -666,11 +811,13 @@ export let fdPwrite = (fd: FileDescriptor, data: String, offset: Int64) => {
666
811
  * @returns `Ok(void)` if successful or `Err(exception)` otherwise
667
812
  */
668
813
  @unsafe
669
- export let fdAllocate = (fd: FileDescriptor, offset: Int64, size: Int64) => {
814
+ provide let fdAllocate = (fd: FileDescriptor, offset: Int64, size: Int64) => {
670
815
  let fdArg = fd
671
816
  let offsetArg = offset
672
817
  let sizeArg = size
673
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
818
+ let fd = match (fd) {
819
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
820
+ }
674
821
 
675
822
  let offset = WasmI64.load(WasmI32.fromGrain(offset), 8n)
676
823
 
@@ -678,10 +825,10 @@ export let fdAllocate = (fd: FileDescriptor, offset: Int64, size: Int64) => {
678
825
 
679
826
  let err = Wasi.fd_allocate(fd, offset, size)
680
827
  if (err != Wasi._ESUCCESS) {
681
- Err(Wasi.SystemError(tagSimpleNumber(err)))
682
- } else {
683
- Ok(void)
828
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
684
829
  }
830
+
831
+ return Ok(void)
685
832
  }
686
833
 
687
834
  /**
@@ -691,16 +838,18 @@ export let fdAllocate = (fd: FileDescriptor, offset: Int64, size: Int64) => {
691
838
  * @returns `Ok(void)` if successful or `Err(exception)` otherwise
692
839
  */
693
840
  @unsafe
694
- export let fdClose = (fd: FileDescriptor) => {
841
+ provide let fdClose = (fd: FileDescriptor) => {
695
842
  let fdArg = fd
696
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
843
+ let fd = match (fd) {
844
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
845
+ }
697
846
 
698
847
  let err = Wasi.fd_close(fd)
699
848
  if (err != Wasi._ESUCCESS) {
700
- Err(Wasi.SystemError(tagSimpleNumber(err)))
701
- } else {
702
- Ok(void)
849
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
703
850
  }
851
+
852
+ return Ok(void)
704
853
  }
705
854
 
706
855
  /**
@@ -710,16 +859,18 @@ export let fdClose = (fd: FileDescriptor) => {
710
859
  * @returns `Ok(void)` if successful or `Err(exception)` otherwise
711
860
  */
712
861
  @unsafe
713
- export let fdDatasync = (fd: FileDescriptor) => {
862
+ provide let fdDatasync = (fd: FileDescriptor) => {
714
863
  let fdArg = fd
715
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
864
+ let fd = match (fd) {
865
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
866
+ }
716
867
 
717
868
  let err = Wasi.fd_datasync(fd)
718
869
  if (err != Wasi._ESUCCESS) {
719
- Err(Wasi.SystemError(tagSimpleNumber(err)))
720
- } else {
721
- Ok(void)
870
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
722
871
  }
872
+
873
+ return Ok(void)
723
874
  }
724
875
 
725
876
  /**
@@ -729,16 +880,18 @@ export let fdDatasync = (fd: FileDescriptor) => {
729
880
  * @returns `Ok(void)` if successful or `Err(exception)` otherwise
730
881
  */
731
882
  @unsafe
732
- export let fdSync = (fd: FileDescriptor) => {
883
+ provide let fdSync = (fd: FileDescriptor) => {
733
884
  let fdArg = fd
734
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
885
+ let fd = match (fd) {
886
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
887
+ }
735
888
 
736
889
  let err = Wasi.fd_sync(fd)
737
890
  if (err != Wasi._ESUCCESS) {
738
- Err(Wasi.SystemError(tagSimpleNumber(err)))
739
- } else {
740
- Ok(void)
891
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
741
892
  }
893
+
894
+ return Ok(void)
742
895
  }
743
896
 
744
897
  let orderedFdflags = [Append, Dsync, Nonblock, Rsync, Sync]
@@ -781,56 +934,53 @@ let orderedRights = [
781
934
  * @returns `Ok(stats)` of the `Stats` associated with the file descriptor if successful or `Err(exception)` otherwise
782
935
  */
783
936
  @unsafe
784
- export let fdStats = (fd: FileDescriptor) => {
937
+ provide let fdStats = (fd: FileDescriptor) => {
785
938
  let fdArg = fd
786
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
939
+ let fd = match (fd) {
940
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
941
+ }
787
942
 
788
943
  let structPtr = Memory.malloc(24n)
789
944
 
790
945
  let err = Wasi.fd_fdstat_get(fd, structPtr)
791
946
  if (err != Wasi._ESUCCESS) {
792
947
  Memory.free(structPtr)
793
- Err(Wasi.SystemError(tagSimpleNumber(err)))
794
- } else {
795
- let filetype = WasmI32.load8U(structPtr, 0n)
948
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
949
+ }
950
+ let filetype = WasmI32.load8U(structPtr, 0n)
796
951
 
797
- let filetype = filetypeFromNumber(filetype)
952
+ let filetype = filetypeFromNumber(filetype)
798
953
 
799
- let flagsToWasmVal = (flag, i) => {
800
- let fdflags = WasmI32.load16U(structPtr, 4n)
801
- WasmI32.gtU(fdflags & 1n << (WasmI32.fromGrain(i) >> 1n), 0n)
802
- }
803
- let fdflagsList = List.filteri(flagsToWasmVal, orderedFdflags)
804
-
805
- let (&) = WasmI64.and
806
- let (>) = WasmI64.gtU
807
- let (<<) = WasmI64.shl
954
+ let flagsToWasmVal = (flag, i) => {
955
+ let fdflags = WasmI32.load16U(structPtr, 4n)
956
+ WasmI32.gtU(fdflags & 1n << (WasmI32.fromGrain(i) >> 1n), 0n)
957
+ }
958
+ let fdflagsList = List.filteri(flagsToWasmVal, orderedFdflags)
959
+ use WasmI64.{ (&), gtU as (>), (<<) }
808
960
 
809
- let flagsToWasmVal = (flag, i) => {
810
- let rights = WasmI64.load(structPtr, 8n)
811
- (rights & 1N << WasmI64.extendI32U(WasmI32.fromGrain(i) >> 1n)) > 0N
812
- }
813
- let rightsList = List.filteri(flagsToWasmVal, orderedRights)
961
+ let flagsToWasmVal = (flag, i) => {
962
+ let rights = WasmI64.load(structPtr, 8n)
963
+ (rights & 1N << WasmI64.extendI32U(WasmI32.fromGrain(i) >> 1n)) > 0N
964
+ }
965
+ let rightsList = List.filteri(flagsToWasmVal, orderedRights)
814
966
 
815
- let flagsToWasmVal = (flag, i) => {
816
- let rightsInheriting = WasmI64.load(structPtr, 16n)
817
- (rightsInheriting &
818
- 1N << WasmI64.extendI32U(WasmI32.fromGrain(i) >> 1n)) >
819
- 0N
820
- }
821
- let rightsInheritingList = List.filteri(flagsToWasmVal, orderedRights)
967
+ let flagsToWasmVal = (flag, i) => {
968
+ let rightsInheriting = WasmI64.load(structPtr, 16n)
969
+ (rightsInheriting & 1N << WasmI64.extendI32U(WasmI32.fromGrain(i) >> 1n)) >
970
+ 0N
971
+ }
972
+ let rightsInheritingList = List.filteri(flagsToWasmVal, orderedRights)
822
973
 
823
- Memory.free(structPtr)
974
+ Memory.free(structPtr)
824
975
 
825
- Ok(
826
- {
827
- filetype,
828
- flags: fdflagsList,
829
- rights: rightsList,
830
- rightsInheriting: rightsInheritingList,
831
- }
832
- )
833
- }
976
+ return Ok(
977
+ {
978
+ filetype,
979
+ flags: fdflagsList,
980
+ rights: rightsList,
981
+ rightsInheriting: rightsInheritingList,
982
+ },
983
+ )
834
984
  }
835
985
 
836
986
  /**
@@ -841,19 +991,21 @@ export let fdStats = (fd: FileDescriptor) => {
841
991
  * @returns `Ok(void)` if successful or `Err(exception)` otherwise
842
992
  */
843
993
  @unsafe
844
- export let fdSetFlags = (fd: FileDescriptor, flags: List<FdFlag>) => {
994
+ provide let fdSetFlags = (fd: FileDescriptor, flags: List<FdFlag>) => {
845
995
  let fdArg = fd
846
996
  let flagsArg = flags
847
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
997
+ let fd = match (fd) {
998
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
999
+ }
848
1000
 
849
1001
  let flags = combineFdFlags(flags)
850
1002
 
851
1003
  let err = Wasi.fd_fdstat_set_flags(fd, flags)
852
1004
  if (err != Wasi._ESUCCESS) {
853
- Err(Wasi.SystemError(tagSimpleNumber(err)))
854
- } else {
855
- Ok(void)
1005
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
856
1006
  }
1007
+
1008
+ return Ok(void)
857
1009
  }
858
1010
 
859
1011
  /**
@@ -865,26 +1017,27 @@ export let fdSetFlags = (fd: FileDescriptor, flags: List<FdFlag>) => {
865
1017
  * @returns `Ok(void)` if successful or `Err(exception)` otherwise
866
1018
  */
867
1019
  @unsafe
868
- export let fdSetRights =
869
- (
870
- fd: FileDescriptor,
871
- rights: List<Rights>,
872
- rightsInheriting: List<Rights>,
873
- ) => {
1020
+ provide let fdSetRights = (
1021
+ fd: FileDescriptor,
1022
+ rights: List<Rights>,
1023
+ rightsInheriting: List<Rights>,
1024
+ ) => {
874
1025
  let fdArg = fd
875
1026
  let rightsArg = rights
876
1027
  let rightsInheritingArg = rightsInheriting
877
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
1028
+ let fd = match (fd) {
1029
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
1030
+ }
878
1031
 
879
1032
  let rights = combineRights(rights)
880
1033
  let rightsInheriting = combineRights(rightsInheriting)
881
1034
 
882
1035
  let err = Wasi.fd_fdstat_set_rights(fd, rights, rightsInheriting)
883
1036
  if (err != Wasi._ESUCCESS) {
884
- Err(Wasi.SystemError(tagSimpleNumber(err)))
885
- } else {
886
- Ok(void)
1037
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
887
1038
  }
1039
+
1040
+ return Ok(void)
888
1041
  }
889
1042
 
890
1043
  /**
@@ -894,38 +1047,34 @@ export let fdSetRights =
894
1047
  * @returns `Ok(info)` of the `Filestats` associated with the file descriptor if successful or `Err(exception)` otherwise
895
1048
  */
896
1049
  @unsafe
897
- export let fdFilestats = (fd: FileDescriptor) => {
1050
+ provide let fdFilestats = (fd: FileDescriptor) => {
898
1051
  let fdArg = fd
899
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
1052
+ let fd = match (fd) {
1053
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
1054
+ }
900
1055
 
901
1056
  let filestats = Memory.malloc(64n)
902
1057
 
903
1058
  let err = Wasi.fd_filestat_get(fd, filestats)
904
1059
  if (err != Wasi._ESUCCESS) {
905
1060
  Memory.free(filestats)
906
- Err(Wasi.SystemError(tagSimpleNumber(err)))
907
- } else {
908
- let device = WasmI32.toGrain(newInt64(WasmI64.load(filestats, 0n))): Int64
909
- let inode = WasmI32.toGrain(newInt64(WasmI64.load(filestats, 8n))): Int64
910
- let filetype = filetypeFromNumber(WasmI32.load8U(filestats, 16n))
911
- let linkcount = WasmI32.toGrain(
912
- newInt64(WasmI64.load(filestats, 24n))
913
- ): Int64
914
- let size = WasmI32.toGrain(newInt64(WasmI64.load(filestats, 32n))): Int64
915
- let accessed = WasmI32.toGrain(
916
- newInt64(WasmI64.load(filestats, 40n))
917
- ): Int64
918
- let modified = WasmI32.toGrain(
919
- newInt64(WasmI64.load(filestats, 48n))
920
- ): Int64
921
- let changed = WasmI32.toGrain(newInt64(WasmI64.load(filestats, 56n))): Int64
1061
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
1062
+ }
922
1063
 
923
- Memory.free(filestats)
1064
+ let device = WasmI32.toGrain(newInt64(WasmI64.load(filestats, 0n))): Int64
1065
+ let inode = WasmI32.toGrain(newInt64(WasmI64.load(filestats, 8n))): Int64
1066
+ let filetype = filetypeFromNumber(WasmI32.load8U(filestats, 16n))
1067
+ let linkcount = WasmI32.toGrain(newInt64(WasmI64.load(filestats, 24n))): Int64
1068
+ let size = WasmI32.toGrain(newInt64(WasmI64.load(filestats, 32n))): Int64
1069
+ let accessed = WasmI32.toGrain(newInt64(WasmI64.load(filestats, 40n))): Int64
1070
+ let modified = WasmI32.toGrain(newInt64(WasmI64.load(filestats, 48n))): Int64
1071
+ let changed = WasmI32.toGrain(newInt64(WasmI64.load(filestats, 56n))): Int64
924
1072
 
925
- Ok(
926
- { device, inode, filetype, linkcount, size, accessed, modified, changed }
927
- )
928
- }
1073
+ Memory.free(filestats)
1074
+
1075
+ return Ok(
1076
+ { device, inode, filetype, linkcount, size, accessed, modified, changed },
1077
+ )
929
1078
  }
930
1079
 
931
1080
  /**
@@ -936,19 +1085,21 @@ export let fdFilestats = (fd: FileDescriptor) => {
936
1085
  * @returns `Ok(void)` if successful or `Err(exception)` otherwise
937
1086
  */
938
1087
  @unsafe
939
- export let fdSetSize = (fd: FileDescriptor, size: Int64) => {
1088
+ provide let fdSetSize = (fd: FileDescriptor, size: Int64) => {
940
1089
  let fdArg = fd
941
1090
  let sizeArg = size
942
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
1091
+ let fd = match (fd) {
1092
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
1093
+ }
943
1094
 
944
1095
  let size = WasmI64.load(WasmI32.fromGrain(size), 8n)
945
1096
 
946
1097
  let err = Wasi.fd_filestat_set_size(fd, size)
947
1098
  if (err != Wasi._ESUCCESS) {
948
- Err(Wasi.SystemError(tagSimpleNumber(err)))
949
- } else {
950
- Ok(void)
1099
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
951
1100
  }
1101
+
1102
+ return Ok(void)
952
1103
  }
953
1104
 
954
1105
  /**
@@ -959,18 +1110,20 @@ export let fdSetSize = (fd: FileDescriptor, size: Int64) => {
959
1110
  * @returns `Ok(void)` if successful or `Err(exception)` otherwise
960
1111
  */
961
1112
  @unsafe
962
- export let fdSetAccessTime = (fd: FileDescriptor, timestamp: Int64) => {
1113
+ provide let fdSetAccessTime = (fd: FileDescriptor, timestamp: Int64) => {
963
1114
  let fdArg = fd
964
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
1115
+ let fd = match (fd) {
1116
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
1117
+ }
965
1118
 
966
1119
  let time = WasmI64.load(WasmI32.fromGrain(timestamp), 8n)
967
1120
 
968
1121
  let err = Wasi.fd_filestat_set_times(fd, time, 0N, Wasi._TIME_SET_ATIM)
969
1122
  if (err != Wasi._ESUCCESS) {
970
- Err(Wasi.SystemError(tagSimpleNumber(err)))
971
- } else {
972
- Ok(void)
1123
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
973
1124
  }
1125
+
1126
+ return Ok(void)
974
1127
  }
975
1128
 
976
1129
  /**
@@ -980,16 +1133,18 @@ export let fdSetAccessTime = (fd: FileDescriptor, timestamp: Int64) => {
980
1133
  * @returns `Ok(void)` if successful or `Err(exception)` otherwise
981
1134
  */
982
1135
  @unsafe
983
- export let fdSetAccessTimeNow = (fd: FileDescriptor) => {
1136
+ provide let fdSetAccessTimeNow = (fd: FileDescriptor) => {
984
1137
  let fdArg = fd
985
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
1138
+ let fd = match (fd) {
1139
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
1140
+ }
986
1141
 
987
1142
  let err = Wasi.fd_filestat_set_times(fd, 0N, 0N, Wasi._TIME_SET_ATIM_NOW)
988
1143
  if (err != Wasi._ESUCCESS) {
989
- Err(Wasi.SystemError(tagSimpleNumber(err)))
990
- } else {
991
- Ok(void)
1144
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
992
1145
  }
1146
+
1147
+ return Ok(void)
993
1148
  }
994
1149
 
995
1150
  /**
@@ -1000,18 +1155,20 @@ export let fdSetAccessTimeNow = (fd: FileDescriptor) => {
1000
1155
  * @returns `Ok(void)` if successful or `Err(exception)` otherwise
1001
1156
  */
1002
1157
  @unsafe
1003
- export let fdSetModifiedTime = (fd: FileDescriptor, timestamp: Int64) => {
1158
+ provide let fdSetModifiedTime = (fd: FileDescriptor, timestamp: Int64) => {
1004
1159
  let fdArg = fd
1005
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
1160
+ let fd = match (fd) {
1161
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
1162
+ }
1006
1163
 
1007
1164
  let time = WasmI64.load(WasmI32.fromGrain(timestamp), 8n)
1008
1165
 
1009
1166
  let err = Wasi.fd_filestat_set_times(fd, 0N, time, Wasi._TIME_SET_MTIM)
1010
1167
  if (err != Wasi._ESUCCESS) {
1011
- Err(Wasi.SystemError(tagSimpleNumber(err)))
1012
- } else {
1013
- Ok(void)
1168
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
1014
1169
  }
1170
+
1171
+ return Ok(void)
1015
1172
  }
1016
1173
 
1017
1174
  /**
@@ -1021,16 +1178,18 @@ export let fdSetModifiedTime = (fd: FileDescriptor, timestamp: Int64) => {
1021
1178
  * @returns `Ok(void)` if successful or `Err(exception)` otherwise
1022
1179
  */
1023
1180
  @unsafe
1024
- export let fdSetModifiedTimeNow = (fd: FileDescriptor) => {
1181
+ provide let fdSetModifiedTimeNow = (fd: FileDescriptor) => {
1025
1182
  let fdArg = fd
1026
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
1183
+ let fd = match (fd) {
1184
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
1185
+ }
1027
1186
 
1028
1187
  let err = Wasi.fd_filestat_set_times(fd, 0N, 0N, Wasi._TIME_SET_MTIM_NOW)
1029
1188
  if (err != Wasi._ESUCCESS) {
1030
- Err(Wasi.SystemError(tagSimpleNumber(err)))
1031
- } else {
1032
- Ok(void)
1189
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
1033
1190
  }
1191
+
1192
+ return Ok(void)
1034
1193
  }
1035
1194
 
1036
1195
  /**
@@ -1040,9 +1199,11 @@ export let fdSetModifiedTimeNow = (fd: FileDescriptor) => {
1040
1199
  * @returns `Ok(dirEntries)` of an array of `DirectoryEntry` for each entry in the directory if successful or `Err(exception)` otherwise
1041
1200
  */
1042
1201
  @unsafe
1043
- export let fdReaddir = (fd: FileDescriptor) => {
1202
+ provide let fdReaddir = (fd: FileDescriptor) => {
1044
1203
  let fdArg = fd
1045
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
1204
+ let fd = match (fd) {
1205
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
1206
+ }
1046
1207
 
1047
1208
  let structWidth = 24n
1048
1209
 
@@ -1056,94 +1217,87 @@ export let fdReaddir = (fd: FileDescriptor) => {
1056
1217
  if (err != Wasi._ESUCCESS) {
1057
1218
  Memory.free(buf)
1058
1219
  Memory.free(bufUsed)
1059
- Err(Wasi.SystemError(tagSimpleNumber(err)))
1060
- } else {
1061
- let used = WasmI32.load(bufUsed, 0n)
1220
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
1221
+ }
1062
1222
 
1063
- if (used <= 0n) {
1064
- Memory.free(buf)
1065
- Memory.free(bufUsed)
1066
- Ok(WasmI32.toGrain(allocateArray(0n)): Array<DirectoryEntry>)
1067
- } else {
1068
- bufLen = WasmI32.load(buf, 16n) + structWidth * 2n
1069
-
1070
- Memory.free(buf)
1071
-
1072
- // simple linked list
1073
- // ptr +0n -> current buffer
1074
- // ptr +4n -> bufs
1075
- let mut bufs = 0n
1076
-
1077
- let mut numEntries = 0n
1078
- let mut hasErr = None
1079
-
1080
- while (true) {
1081
- numEntries += 1n
1082
-
1083
- buf = Memory.malloc(bufLen)
1084
- let cons = Memory.malloc(8n)
1085
- WasmI32.store(cons, buf, 0n)
1086
- WasmI32.store(cons, bufs, 4n)
1087
- bufs = cons
1088
-
1089
- let err = Wasi.fd_readdir(fd, buf, bufLen, cookie, bufUsed)
1090
- if (err != Wasi._ESUCCESS) {
1091
- while (bufs != 0n) {
1092
- Memory.free(WasmI32.load(bufs, 0n))
1093
- let next = WasmI32.load(bufs, 4n)
1094
- Memory.free(bufs)
1095
- bufs = next
1096
- }
1097
- Memory.free(bufUsed)
1098
- hasErr = Some(Err(Wasi.SystemError(tagSimpleNumber(err))))
1099
- break
1100
- }
1101
-
1102
- if (WasmI32.load(bufUsed, 0n) != bufLen) {
1103
- break
1104
- } else {
1105
- let curLen = WasmI32.load(buf, 16n)
1106
- cookie = WasmI64.load(buf, 0n)
1107
- let nextDirentPtr = buf + structWidth + curLen
1108
- bufLen = WasmI32.load(nextDirentPtr, 16n) + structWidth * 2n
1109
- }
1223
+ let used = WasmI32.load(bufUsed, 0n)
1224
+
1225
+ if (used <= 0n) {
1226
+ Memory.free(buf)
1227
+ Memory.free(bufUsed)
1228
+ return Ok(WasmI32.toGrain(allocateArray(0n)): Array<DirectoryEntry>)
1229
+ }
1230
+
1231
+ bufLen = WasmI32.load(buf, 16n) + structWidth * 2n
1232
+
1233
+ Memory.free(buf)
1234
+
1235
+ // simple linked list
1236
+ // ptr +0n -> current buffer
1237
+ // ptr +4n -> bufs
1238
+ let mut bufs = 0n
1239
+
1240
+ let mut numEntries = 0n
1241
+
1242
+ while (true) {
1243
+ numEntries += 1n
1244
+
1245
+ buf = Memory.malloc(bufLen)
1246
+ let cons = Memory.malloc(8n)
1247
+ WasmI32.store(cons, buf, 0n)
1248
+ WasmI32.store(cons, bufs, 4n)
1249
+ bufs = cons
1250
+
1251
+ let err = Wasi.fd_readdir(fd, buf, bufLen, cookie, bufUsed)
1252
+ if (err != Wasi._ESUCCESS) {
1253
+ while (bufs != 0n) {
1254
+ Memory.free(WasmI32.load(bufs, 0n))
1255
+ let next = WasmI32.load(bufs, 4n)
1256
+ Memory.free(bufs)
1257
+ bufs = next
1110
1258
  }
1259
+ Memory.free(bufUsed)
1260
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
1261
+ }
1111
1262
 
1112
- match (hasErr) {
1113
- Some(err) => err,
1114
- None => {
1115
- Memory.free(bufUsed)
1263
+ if (WasmI32.load(bufUsed, 0n) != bufLen) {
1264
+ break
1265
+ }
1116
1266
 
1117
- let arr = allocateArray(numEntries)
1267
+ let curLen = WasmI32.load(buf, 16n)
1268
+ cookie = WasmI64.load(buf, 0n)
1269
+ let nextDirentPtr = buf + structWidth + curLen
1270
+ bufLen = WasmI32.load(nextDirentPtr, 16n) + structWidth * 2n
1271
+ }
1118
1272
 
1119
- for (let mut i = numEntries - 1n; i >= 0n; i -= 1n) {
1120
- let ent = WasmI32.load(bufs, 0n)
1273
+ Memory.free(bufUsed)
1121
1274
 
1122
- let inode = WasmI32.toGrain(newInt64(WasmI64.load(ent, 8n))): Int64
1275
+ let arr = allocateArray(numEntries)
1123
1276
 
1124
- let dirnameLen = WasmI32.load(ent, 16n)
1125
- let dirname = allocateString(dirnameLen)
1126
- Memory.copy(dirname + 8n, ent + structWidth, dirnameLen)
1127
- let path = WasmI32.toGrain(dirname): String
1277
+ for (let mut i = numEntries - 1n; i >= 0n; i -= 1n) {
1278
+ let ent = WasmI32.load(bufs, 0n)
1128
1279
 
1129
- let filetype = filetypeFromNumber(WasmI32.load8U(ent, 20n))
1280
+ let inode = WasmI32.toGrain(newInt64(WasmI64.load(ent, 8n))): Int64
1130
1281
 
1131
- let dirent = WasmI32.fromGrain({ inode, path, filetype })
1282
+ let dirnameLen = WasmI32.load(ent, 16n)
1283
+ let dirname = allocateString(dirnameLen)
1284
+ Memory.copy(dirname + 8n, ent + structWidth, dirnameLen)
1285
+ let path = WasmI32.toGrain(dirname): String
1132
1286
 
1133
- WasmI32.store(arr + i * 4n, Memory.incRef(dirent), 8n)
1287
+ let filetype = filetypeFromNumber(WasmI32.load8U(ent, 20n))
1134
1288
 
1135
- let next = WasmI32.load(bufs, 4n)
1136
- Memory.free(bufs)
1137
- Memory.free(ent)
1289
+ let dirent = WasmI32.fromGrain({ inode, path, filetype })
1138
1290
 
1139
- bufs = next
1140
- }
1291
+ WasmI32.store(arr + i * 4n, Memory.incRef(dirent), 8n)
1141
1292
 
1142
- Ok(WasmI32.toGrain(arr): Array<DirectoryEntry>)
1143
- },
1144
- }
1145
- }
1293
+ let next = WasmI32.load(bufs, 4n)
1294
+ Memory.free(bufs)
1295
+ Memory.free(ent)
1296
+
1297
+ bufs = next
1146
1298
  }
1299
+
1300
+ return Ok(WasmI32.toGrain(arr): Array<DirectoryEntry>)
1147
1301
  }
1148
1302
 
1149
1303
  /**
@@ -1154,21 +1308,23 @@ export let fdReaddir = (fd: FileDescriptor) => {
1154
1308
  * @returns `Ok(void)` if successful or `Err(exception)` otherwise
1155
1309
  */
1156
1310
  @unsafe
1157
- export let fdRenumber = (fromFd: FileDescriptor, toFd: FileDescriptor) => {
1311
+ provide let fdRenumber = (fromFd: FileDescriptor, toFd: FileDescriptor) => {
1158
1312
  let fromFdArg = fromFd
1159
1313
  let toFdArg = toFd
1160
1314
  let fromFd = match (fromFd) {
1161
1315
  FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
1162
1316
  }
1163
1317
 
1164
- let toFd = match (toFd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
1318
+ let toFd = match (toFd) {
1319
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
1320
+ }
1165
1321
 
1166
1322
  let err = Wasi.fd_renumber(fromFd, toFd)
1167
1323
  if (err != Wasi._ESUCCESS) {
1168
- Err(Wasi.SystemError(tagSimpleNumber(err)))
1169
- } else {
1170
- Ok(void)
1324
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
1171
1325
  }
1326
+
1327
+ return Ok(void)
1172
1328
  }
1173
1329
 
1174
1330
  /**
@@ -1180,11 +1336,13 @@ export let fdRenumber = (fromFd: FileDescriptor, toFd: FileDescriptor) => {
1180
1336
  * @returns `Ok(offset)` of the new offset of the file descriptor, relative to the start of the file, if successful or `Err(exception)` otherwise
1181
1337
  */
1182
1338
  @unsafe
1183
- export let fdSeek = (fd: FileDescriptor, offset: Int64, whence: Whence) => {
1339
+ provide let fdSeek = (fd: FileDescriptor, offset: Int64, whence: Whence) => {
1184
1340
  let fdArg = fd
1185
1341
  let offsetArg = offset
1186
1342
  let whenceArg = whence
1187
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
1343
+ let fd = match (fd) {
1344
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
1345
+ }
1188
1346
 
1189
1347
  let offset = WasmI64.load(WasmI32.fromGrain(offset), 8n)
1190
1348
 
@@ -1200,10 +1358,10 @@ export let fdSeek = (fd: FileDescriptor, offset: Int64, whence: Whence) => {
1200
1358
  let err = Wasi.fd_seek(fd, offset, whence, newoffsetPtr)
1201
1359
  if (err != Wasi._ESUCCESS) {
1202
1360
  Memory.free(newoffset)
1203
- Err(Wasi.SystemError(tagSimpleNumber(err)))
1204
- } else {
1205
- Ok(WasmI32.toGrain(newoffset): Int64)
1361
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
1206
1362
  }
1363
+
1364
+ return Ok(WasmI32.toGrain(newoffset): Int64)
1207
1365
  }
1208
1366
 
1209
1367
  /**
@@ -1213,9 +1371,11 @@ export let fdSeek = (fd: FileDescriptor, offset: Int64, whence: Whence) => {
1213
1371
  * @returns `Ok(offset)` of the offset of the file descriptor, relative to the start of the file, if successful or `Err(exception)` otherwise
1214
1372
  */
1215
1373
  @unsafe
1216
- export let fdTell = (fd: FileDescriptor) => {
1374
+ provide let fdTell = (fd: FileDescriptor) => {
1217
1375
  let fdArg = fd
1218
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
1376
+ let fd = match (fd) {
1377
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
1378
+ }
1219
1379
 
1220
1380
  let offset = allocateInt64()
1221
1381
  let offsetPtr = offset + 8n
@@ -1223,10 +1383,10 @@ export let fdTell = (fd: FileDescriptor) => {
1223
1383
  let err = Wasi.fd_tell(fd, offsetPtr)
1224
1384
  if (err != Wasi._ESUCCESS) {
1225
1385
  Memory.free(offset)
1226
- Err(Wasi.SystemError(tagSimpleNumber(err)))
1227
- } else {
1228
- Ok(WasmI32.toGrain(offset): Int64)
1386
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
1229
1387
  }
1388
+
1389
+ return Ok(WasmI32.toGrain(offset): Int64)
1230
1390
  }
1231
1391
 
1232
1392
  /**
@@ -1237,9 +1397,11 @@ export let fdTell = (fd: FileDescriptor) => {
1237
1397
  * @returns `Ok(void)` if successful or `Err(exception)` otherwise
1238
1398
  */
1239
1399
  @unsafe
1240
- export let pathCreateDirectory = (fd: FileDescriptor, path: String) => {
1400
+ provide let pathCreateDirectory = (fd: FileDescriptor, path: String) => {
1241
1401
  let fdArg = fd
1242
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
1402
+ let fd = match (fd) {
1403
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
1404
+ }
1243
1405
 
1244
1406
  let stringPtr = WasmI32.fromGrain(path)
1245
1407
 
@@ -1247,10 +1409,10 @@ export let pathCreateDirectory = (fd: FileDescriptor, path: String) => {
1247
1409
 
1248
1410
  let err = Wasi.path_create_directory(fd, stringPtr + 8n, size)
1249
1411
  if (err != Wasi._ESUCCESS) {
1250
- Err(Wasi.SystemError(tagSimpleNumber(err)))
1251
- } else {
1252
- Ok(void)
1412
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
1253
1413
  }
1414
+
1415
+ return Ok(void)
1254
1416
  }
1255
1417
 
1256
1418
  /**
@@ -1262,14 +1424,15 @@ export let pathCreateDirectory = (fd: FileDescriptor, path: String) => {
1262
1424
  * @returns `Ok(info)` of the `Filestats` associated with the file descriptor if successful or `Err(exception)` otherwise
1263
1425
  */
1264
1426
  @unsafe
1265
- export let pathFilestats =
1266
- (
1267
- fd: FileDescriptor,
1268
- dirFlags: List<LookupFlag>,
1269
- path: String,
1270
- ) => {
1427
+ provide let pathFilestats = (
1428
+ fd: FileDescriptor,
1429
+ dirFlags: List<LookupFlag>,
1430
+ path: String,
1431
+ ) => {
1271
1432
  let fdArg = fd
1272
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
1433
+ let fd = match (fd) {
1434
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
1435
+ }
1273
1436
 
1274
1437
  let combinedDirFlags = combineLookupFlags(dirFlags)
1275
1438
 
@@ -1288,29 +1451,23 @@ export let pathFilestats =
1288
1451
  )
1289
1452
  if (err != Wasi._ESUCCESS) {
1290
1453
  Memory.free(filestats)
1291
- Err(Wasi.SystemError(tagSimpleNumber(err)))
1292
- } else {
1293
- let device = WasmI32.toGrain(newInt64(WasmI64.load(filestats, 0n))): Int64
1294
- let inode = WasmI32.toGrain(newInt64(WasmI64.load(filestats, 8n))): Int64
1295
- let filetype = filetypeFromNumber(WasmI32.load8U(filestats, 16n))
1296
- let linkcount = WasmI32.toGrain(
1297
- newInt64(WasmI64.load(filestats, 24n))
1298
- ): Int64
1299
- let size = WasmI32.toGrain(newInt64(WasmI64.load(filestats, 32n))): Int64
1300
- let accessed = WasmI32.toGrain(
1301
- newInt64(WasmI64.load(filestats, 40n))
1302
- ): Int64
1303
- let modified = WasmI32.toGrain(
1304
- newInt64(WasmI64.load(filestats, 48n))
1305
- ): Int64
1306
- let changed = WasmI32.toGrain(newInt64(WasmI64.load(filestats, 56n))): Int64
1454
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
1455
+ }
1307
1456
 
1308
- Memory.free(filestats)
1457
+ let device = WasmI32.toGrain(newInt64(WasmI64.load(filestats, 0n))): Int64
1458
+ let inode = WasmI32.toGrain(newInt64(WasmI64.load(filestats, 8n))): Int64
1459
+ let filetype = filetypeFromNumber(WasmI32.load8U(filestats, 16n))
1460
+ let linkcount = WasmI32.toGrain(newInt64(WasmI64.load(filestats, 24n))): Int64
1461
+ let size = WasmI32.toGrain(newInt64(WasmI64.load(filestats, 32n))): Int64
1462
+ let accessed = WasmI32.toGrain(newInt64(WasmI64.load(filestats, 40n))): Int64
1463
+ let modified = WasmI32.toGrain(newInt64(WasmI64.load(filestats, 48n))): Int64
1464
+ let changed = WasmI32.toGrain(newInt64(WasmI64.load(filestats, 56n))): Int64
1309
1465
 
1310
- Ok(
1311
- { device, inode, filetype, linkcount, size, accessed, modified, changed }
1312
- )
1313
- }
1466
+ Memory.free(filestats)
1467
+
1468
+ return Ok(
1469
+ { device, inode, filetype, linkcount, size, accessed, modified, changed },
1470
+ )
1314
1471
  }
1315
1472
 
1316
1473
  /**
@@ -1323,15 +1480,16 @@ export let pathFilestats =
1323
1480
  * @returns `Ok(void)` if successful or `Err(exception)` otherwise
1324
1481
  */
1325
1482
  @unsafe
1326
- export let pathSetAccessTime =
1327
- (
1328
- fd: FileDescriptor,
1329
- dirFlags: List<LookupFlag>,
1330
- path: String,
1331
- timestamp: Int64,
1332
- ) => {
1483
+ provide let pathSetAccessTime = (
1484
+ fd: FileDescriptor,
1485
+ dirFlags: List<LookupFlag>,
1486
+ path: String,
1487
+ timestamp: Int64,
1488
+ ) => {
1333
1489
  let fdArg = fd
1334
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
1490
+ let fd = match (fd) {
1491
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
1492
+ }
1335
1493
 
1336
1494
  let combinedDirFlags = combineLookupFlags(dirFlags)
1337
1495
 
@@ -1351,10 +1509,10 @@ export let pathSetAccessTime =
1351
1509
  Wasi._TIME_SET_ATIM
1352
1510
  )
1353
1511
  if (err != Wasi._ESUCCESS) {
1354
- Err(Wasi.SystemError(tagSimpleNumber(err)))
1355
- } else {
1356
- Ok(void)
1512
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
1357
1513
  }
1514
+
1515
+ return Ok(void)
1358
1516
  }
1359
1517
 
1360
1518
  /**
@@ -1366,14 +1524,15 @@ export let pathSetAccessTime =
1366
1524
  * @returns `Ok(void)` if successful or `Err(exception)` otherwise
1367
1525
  */
1368
1526
  @unsafe
1369
- export let pathSetAccessTimeNow =
1370
- (
1371
- fd: FileDescriptor,
1372
- dirFlags: List<LookupFlag>,
1373
- path: String,
1374
- ) => {
1527
+ provide let pathSetAccessTimeNow = (
1528
+ fd: FileDescriptor,
1529
+ dirFlags: List<LookupFlag>,
1530
+ path: String,
1531
+ ) => {
1375
1532
  let fdArg = fd
1376
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
1533
+ let fd = match (fd) {
1534
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
1535
+ }
1377
1536
 
1378
1537
  let combinedDirFlags = combineLookupFlags(dirFlags)
1379
1538
 
@@ -1391,10 +1550,10 @@ export let pathSetAccessTimeNow =
1391
1550
  Wasi._TIME_SET_ATIM_NOW
1392
1551
  )
1393
1552
  if (err != Wasi._ESUCCESS) {
1394
- Err(Wasi.SystemError(tagSimpleNumber(err)))
1395
- } else {
1396
- Ok(void)
1553
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
1397
1554
  }
1555
+
1556
+ return Ok(void)
1398
1557
  }
1399
1558
 
1400
1559
  /**
@@ -1407,15 +1566,16 @@ export let pathSetAccessTimeNow =
1407
1566
  * @returns `Ok(void)` if successful or `Err(exception)` otherwise
1408
1567
  */
1409
1568
  @unsafe
1410
- export let pathSetModifiedTime =
1411
- (
1412
- fd: FileDescriptor,
1413
- dirFlags: List<LookupFlag>,
1414
- path: String,
1415
- timestamp: Int64,
1416
- ) => {
1569
+ provide let pathSetModifiedTime = (
1570
+ fd: FileDescriptor,
1571
+ dirFlags: List<LookupFlag>,
1572
+ path: String,
1573
+ timestamp: Int64,
1574
+ ) => {
1417
1575
  let fdArg = fd
1418
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
1576
+ let fd = match (fd) {
1577
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
1578
+ }
1419
1579
 
1420
1580
  let combinedDirFlags = combineLookupFlags(dirFlags)
1421
1581
 
@@ -1435,10 +1595,10 @@ export let pathSetModifiedTime =
1435
1595
  Wasi._TIME_SET_MTIM
1436
1596
  )
1437
1597
  if (err != Wasi._ESUCCESS) {
1438
- Err(Wasi.SystemError(tagSimpleNumber(err)))
1439
- } else {
1440
- Ok(void)
1598
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
1441
1599
  }
1600
+
1601
+ return Ok(void)
1442
1602
  }
1443
1603
 
1444
1604
  /**
@@ -1450,14 +1610,15 @@ export let pathSetModifiedTime =
1450
1610
  * @returns `Ok(void)` if successful or `Err(exception)` otherwise
1451
1611
  */
1452
1612
  @unsafe
1453
- export let pathSetModifiedTimeNow =
1454
- (
1455
- fd: FileDescriptor,
1456
- dirFlags: List<LookupFlag>,
1457
- path: String,
1458
- ) => {
1613
+ provide let pathSetModifiedTimeNow = (
1614
+ fd: FileDescriptor,
1615
+ dirFlags: List<LookupFlag>,
1616
+ path: String,
1617
+ ) => {
1459
1618
  let fdArg = fd
1460
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
1619
+ let fd = match (fd) {
1620
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
1621
+ }
1461
1622
 
1462
1623
  let combinedDirFlags = combineLookupFlags(dirFlags)
1463
1624
 
@@ -1475,10 +1636,10 @@ export let pathSetModifiedTimeNow =
1475
1636
  Wasi._TIME_SET_MTIM_NOW
1476
1637
  )
1477
1638
  if (err != Wasi._ESUCCESS) {
1478
- Err(Wasi.SystemError(tagSimpleNumber(err)))
1479
- } else {
1480
- Ok(void)
1639
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
1481
1640
  }
1641
+
1642
+ return Ok(void)
1482
1643
  }
1483
1644
 
1484
1645
  /**
@@ -1492,14 +1653,13 @@ export let pathSetModifiedTimeNow =
1492
1653
  * @returns `Ok(void)` if successful or `Err(exception)` otherwise
1493
1654
  */
1494
1655
  @unsafe
1495
- export let pathLink =
1496
- (
1497
- sourceFd: FileDescriptor,
1498
- dirFlags: List<LookupFlag>,
1499
- sourcePath: String,
1500
- targetFd: FileDescriptor,
1501
- targetPath: String,
1502
- ) => {
1656
+ provide let pathLink = (
1657
+ sourceFd: FileDescriptor,
1658
+ dirFlags: List<LookupFlag>,
1659
+ sourcePath: String,
1660
+ targetFd: FileDescriptor,
1661
+ targetPath: String,
1662
+ ) => {
1503
1663
  let sourceFdArg = sourceFd
1504
1664
  let targetFdArg = targetFd
1505
1665
  let sourceFd = match (sourceFd) {
@@ -1528,10 +1688,10 @@ export let pathLink =
1528
1688
  targetSize
1529
1689
  )
1530
1690
  if (err != Wasi._ESUCCESS) {
1531
- Err(Wasi.SystemError(tagSimpleNumber(err)))
1532
- } else {
1533
- Ok(void)
1691
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
1534
1692
  }
1693
+
1694
+ return Ok(void)
1535
1695
  }
1536
1696
 
1537
1697
  /**
@@ -1543,14 +1703,15 @@ export let pathLink =
1543
1703
  * @returns `Ok(void)` if successful or `Err(exception)` otherwise
1544
1704
  */
1545
1705
  @unsafe
1546
- export let pathSymlink =
1547
- (
1548
- fd: FileDescriptor,
1549
- sourcePath: String,
1550
- targetPath: String,
1551
- ) => {
1706
+ provide let pathSymlink = (
1707
+ fd: FileDescriptor,
1708
+ sourcePath: String,
1709
+ targetPath: String,
1710
+ ) => {
1552
1711
  let fdArg = fd
1553
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
1712
+ let fd = match (fd) {
1713
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
1714
+ }
1554
1715
 
1555
1716
  let sourcePtr = WasmI32.fromGrain(sourcePath)
1556
1717
  let targetPtr = WasmI32.fromGrain(targetPath)
@@ -1566,10 +1727,10 @@ export let pathSymlink =
1566
1727
  targetSize
1567
1728
  )
1568
1729
  if (err != Wasi._ESUCCESS) {
1569
- Err(Wasi.SystemError(tagSimpleNumber(err)))
1570
- } else {
1571
- Ok(void)
1730
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
1572
1731
  }
1732
+
1733
+ return Ok(void)
1573
1734
  }
1574
1735
 
1575
1736
  /**
@@ -1580,19 +1741,21 @@ export let pathSymlink =
1580
1741
  * @returns `Ok(void)` if successful or `Err(exception)` otherwise
1581
1742
  */
1582
1743
  @unsafe
1583
- export let pathUnlink = (fd: FileDescriptor, path: String) => {
1744
+ provide let pathUnlink = (fd: FileDescriptor, path: String) => {
1584
1745
  let fdArg = fd
1585
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
1746
+ let fd = match (fd) {
1747
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
1748
+ }
1586
1749
 
1587
1750
  let pathPtr = WasmI32.fromGrain(path)
1588
1751
  let pathSize = WasmI32.load(pathPtr, 4n)
1589
1752
 
1590
1753
  let err = Wasi.path_unlink_file(fd, pathPtr + 8n, pathSize)
1591
1754
  if (err != Wasi._ESUCCESS) {
1592
- Err(Wasi.SystemError(tagSimpleNumber(err)))
1593
- } else {
1594
- Ok(void)
1755
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
1595
1756
  }
1757
+
1758
+ return Ok(void)
1596
1759
  }
1597
1760
 
1598
1761
  /**
@@ -1604,10 +1767,12 @@ export let pathUnlink = (fd: FileDescriptor, path: String) => {
1604
1767
  * @returns `Ok((contents, numBytes))` of the bytes read and the number of bytes read if successful or `Err(exception)` otherwise
1605
1768
  */
1606
1769
  @unsafe
1607
- export let pathReadlink = (fd: FileDescriptor, path: String, size: Number) => {
1770
+ provide let pathReadlink = (fd: FileDescriptor, path: String, size: Number) => {
1608
1771
  let fdArg = fd
1609
1772
  let sizeArg = size
1610
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
1773
+ let fd = match (fd) {
1774
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
1775
+ }
1611
1776
 
1612
1777
  let pathPtr = WasmI32.fromGrain(path)
1613
1778
  let pathSize = WasmI32.load(pathPtr, 4n)
@@ -1623,13 +1788,13 @@ export let pathReadlink = (fd: FileDescriptor, path: String, size: Number) => {
1623
1788
  if (err != Wasi._ESUCCESS) {
1624
1789
  Memory.free(grainStrPtr)
1625
1790
  Memory.free(nread)
1626
- Err(Wasi.SystemError(tagSimpleNumber(err)))
1627
- } else {
1628
- let read = tagSimpleNumber(WasmI32.load(nread, 0n))
1629
- Memory.free(nread)
1630
-
1631
- Ok((WasmI32.toGrain(grainStrPtr): String, read))
1791
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
1632
1792
  }
1793
+
1794
+ let read = tagSimpleNumber(WasmI32.load(nread, 0n))
1795
+ Memory.free(nread)
1796
+
1797
+ return Ok((WasmI32.toGrain(grainStrPtr): String, read))
1633
1798
  }
1634
1799
 
1635
1800
  /**
@@ -1640,19 +1805,21 @@ export let pathReadlink = (fd: FileDescriptor, path: String, size: Number) => {
1640
1805
  * @returns `Ok(void)` if successful or `Err(exception)` otherwise
1641
1806
  */
1642
1807
  @unsafe
1643
- export let pathRemoveDirectory = (fd: FileDescriptor, path: String) => {
1808
+ provide let pathRemoveDirectory = (fd: FileDescriptor, path: String) => {
1644
1809
  let fdArg = fd
1645
- let fd = match (fd) { FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n }
1810
+ let fd = match (fd) {
1811
+ FileDescriptor(n) => WasmI32.fromGrain(n) >> 1n,
1812
+ }
1646
1813
 
1647
1814
  let pathPtr = WasmI32.fromGrain(path)
1648
1815
  let pathSize = WasmI32.load(pathPtr, 4n)
1649
1816
 
1650
1817
  let err = Wasi.path_remove_directory(fd, pathPtr + 8n, pathSize)
1651
1818
  if (err != Wasi._ESUCCESS) {
1652
- Err(Wasi.SystemError(tagSimpleNumber(err)))
1653
- } else {
1654
- Ok(void)
1819
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
1655
1820
  }
1821
+
1822
+ return Ok(void)
1656
1823
  }
1657
1824
 
1658
1825
  /**
@@ -1665,13 +1832,12 @@ export let pathRemoveDirectory = (fd: FileDescriptor, path: String) => {
1665
1832
  * @returns `Ok(void)` if successful or `Err(exception)` otherwise
1666
1833
  */
1667
1834
  @unsafe
1668
- export let pathRename =
1669
- (
1670
- sourceFd: FileDescriptor,
1671
- sourcePath: String,
1672
- targetFd: FileDescriptor,
1673
- targetPath: String,
1674
- ) => {
1835
+ provide let pathRename = (
1836
+ sourceFd: FileDescriptor,
1837
+ sourcePath: String,
1838
+ targetFd: FileDescriptor,
1839
+ targetPath: String,
1840
+ ) => {
1675
1841
  let sourceFdArg = sourceFd
1676
1842
  let targetFdArg = targetFd
1677
1843
  let sourceFd = match (sourceFd) {
@@ -1697,8 +1863,256 @@ export let pathRename =
1697
1863
  targetSize
1698
1864
  )
1699
1865
  if (err != Wasi._ESUCCESS) {
1700
- Err(Wasi.SystemError(tagSimpleNumber(err)))
1866
+ return Err(Wasi.SystemError(tagSimpleNumber(err)))
1867
+ }
1868
+
1869
+ return Ok(void)
1870
+ }
1871
+
1872
+ @unsafe
1873
+ let _CHAR_SLASH = 0x2fn
1874
+ @unsafe
1875
+ let _CHAR_DOT = 0x2en
1876
+
1877
+ @unsafe
1878
+ let stripPrefixes = (path: String) => {
1879
+ let origPathPtr = WasmI32.fromGrain(path)
1880
+ let mut pathPtr = origPathPtr
1881
+ let mut pathLen = WasmI32.load(pathPtr, 4n)
1882
+ pathPtr += 8n
1883
+
1884
+ while (true) {
1885
+ if (WasmI32.load8U(pathPtr, 0n) == _CHAR_SLASH) {
1886
+ pathPtr += 1n
1887
+ pathLen -= 1n
1888
+ } else if (
1889
+ WasmI32.load8U(pathPtr, 0n) == _CHAR_DOT &&
1890
+ WasmI32.load8U(pathPtr, 1n) == _CHAR_SLASH
1891
+ ) {
1892
+ pathPtr += 2n
1893
+ pathLen -= 2n
1894
+ } else if (WasmI32.load8U(pathPtr, 0n) == _CHAR_DOT && pathLen == 1n) {
1895
+ pathPtr += 1n
1896
+ pathLen -= 1n
1897
+ break
1898
+ } else {
1899
+ break
1900
+ }
1901
+ }
1902
+
1903
+ if (pathPtr == origPathPtr) {
1904
+ path
1905
+ } else {
1906
+ let strippedPath = allocateString(pathLen)
1907
+ Memory.copy(strippedPath + 8n, pathPtr, pathLen)
1908
+ WasmI32.toGrain(strippedPath): String
1909
+ }
1910
+ }
1911
+
1912
+ let mut preopens = None
1913
+ @unsafe
1914
+ let populatePreopens = () => {
1915
+ let mut preopenedDirs = []
1916
+ // Skip stdin, stdout, and stderr.
1917
+ for (let mut fd = 3n; fd != 0n; fd += 1n) {
1918
+ let fd = FileDescriptor(tagSimpleNumber(fd))
1919
+ match (fdPrestatGet(fd)) {
1920
+ Ok(Dir{ prefix, fd }) =>
1921
+ preopenedDirs = [(fd, stripPrefixes(prefix)), ...preopenedDirs],
1922
+ // We've reached a bad file descriptor; we're done.
1923
+ Err(Wasi.SystemError(e)) when untagSimpleNumber(e) == Wasi._EBADF =>
1924
+ break,
1925
+ Err(_) => fail "Failed to populate preopens",
1926
+ }
1927
+ }
1928
+ preopens = Some(preopenedDirs)
1929
+ preopenedDirs
1930
+ }
1931
+
1932
+ @unsafe
1933
+ let prefixMatches = (prefix, prefixLen, path, pathLen) => {
1934
+ // Allow an empty string as a prefix of any relative path.
1935
+ if (WasmI32.load8U(path, 0n) != _CHAR_SLASH && prefixLen == 0n) {
1936
+ return true
1937
+ }
1938
+
1939
+ // Check whether any bytes of the prefix differ.
1940
+ if (Memory.compare(path, prefix, prefixLen) != 0n) {
1941
+ return false
1942
+ }
1943
+
1944
+ // Ignore trailing slashes in directory names.
1945
+ let mut i = prefixLen
1946
+ while (i > 0n && WasmI32.load8U(prefix + i - 1n, 0n) == _CHAR_SLASH) {
1947
+ i -= 1n
1948
+ }
1949
+
1950
+ // Match only complete path components.
1951
+ let last = WasmI32.load8U(path + i, 0n)
1952
+ return last == _CHAR_SLASH || i == pathLen
1953
+ }
1954
+
1955
+ @unsafe
1956
+ let rec findPath = (path, pathLen, preopens, bestMatch) => {
1957
+ match (preopens) {
1958
+ [(fd, prefix) as preopen, ...preopens] => {
1959
+ let prefix = WasmI32.fromGrain(prefix)
1960
+ let prefixLen = WasmI32.load(prefix, 4n)
1961
+ let prefix = prefix + 8n
1962
+
1963
+ let (hasBestMatch, matchLen) = match (bestMatch) {
1964
+ Some((matchPrefix, _)) =>
1965
+ (
1966
+ true,
1967
+ tagSimpleNumber(WasmI32.load(WasmI32.fromGrain(matchPrefix), 4n)),
1968
+ ),
1969
+ None => (false, 0),
1970
+ }
1971
+
1972
+ let bestMatch = if (
1973
+ (!hasBestMatch || pathLen > untagSimpleNumber(matchLen)) &&
1974
+ prefixMatches(prefix, prefixLen, path, pathLen)
1975
+ ) {
1976
+ Some(preopen)
1977
+ } else {
1978
+ bestMatch
1979
+ }
1980
+
1981
+ findPath(path, pathLen, preopens, bestMatch)
1982
+ },
1983
+ [] => {
1984
+ match (bestMatch) {
1985
+ Some((fd, prefix)) => {
1986
+ let matchLen = WasmI32.load(WasmI32.fromGrain(prefix), 4n)
1987
+ let mut computed = path + matchLen
1988
+ while (WasmI32.load8U(computed, 0n) == _CHAR_SLASH) {
1989
+ computed += 1n
1990
+ }
1991
+ let computedPath = if (computed == path + pathLen) {
1992
+ "."
1993
+ } else {
1994
+ let computedLen = path + pathLen - computed
1995
+ let computedPath = allocateString(computedLen)
1996
+ Memory.copy(computedPath + 8n, computed, computedLen)
1997
+ WasmI32.toGrain(computedPath): String
1998
+ }
1999
+ Ok((fd, computedPath))
2000
+ },
2001
+ None => Err(Wasi.SystemError(tagSimpleNumber(Wasi._ENOENT))),
2002
+ }
2003
+ },
2004
+ }
2005
+ }
2006
+
2007
+ @unsafe
2008
+ let findPath = (path: String) => {
2009
+ let pathPtr = WasmI32.fromGrain(path)
2010
+ let mut pathLen = WasmI32.load(pathPtr, 4n)
2011
+ let mut pathPtr = pathPtr + 8n
2012
+
2013
+ // ignore leading `/` characters
2014
+ while (WasmI32.load8U(pathPtr, 0n) == _CHAR_SLASH) {
2015
+ pathPtr += 1n
2016
+ pathLen -= 1n
2017
+ }
2018
+
2019
+ let preopens = match (preopens) {
2020
+ Some(preopens) => preopens,
2021
+ None => populatePreopens(),
2022
+ }
2023
+
2024
+ let matchingPath = findPath(pathPtr, pathLen, preopens, None)
2025
+ ignore(path)
2026
+ matchingPath
2027
+ }
2028
+
2029
+ // explicit just in case we ever want to support changing directories
2030
+ let cwd = "/"
2031
+
2032
+ @unsafe
2033
+ let makeAbsolute = (path: String) => {
2034
+ let origPathPtr = WasmI32.fromGrain(path)
2035
+ let mut pathPtr = origPathPtr
2036
+ let mut pathLen = WasmI32.load(pathPtr, 4n)
2037
+ pathPtr += 8n
2038
+
2039
+ // already absolute
2040
+ if (WasmI32.load8U(pathPtr, 0n) == _CHAR_SLASH) {
2041
+ return path
2042
+ }
2043
+
2044
+ // pointing at the current dirextory
2045
+ if (
2046
+ pathLen == 0n ||
2047
+ pathLen == 1n && WasmI32.load8U(pathPtr, 0n) == _CHAR_DOT ||
2048
+ pathLen == 2n &&
2049
+ WasmI32.load8U(pathPtr, 0n) == _CHAR_DOT &&
2050
+ WasmI32.load8U(pathPtr, 1n) == _CHAR_SLASH
2051
+ ) {
2052
+ return cwd
2053
+ }
2054
+
2055
+ // strip leading ./
2056
+ if (
2057
+ WasmI32.load8U(pathPtr, 0n) == _CHAR_DOT &&
2058
+ WasmI32.load8U(pathPtr, 1n) == _CHAR_SLASH
2059
+ ) {
2060
+ pathPtr += 2n
2061
+ pathLen -= 2n
2062
+ }
2063
+
2064
+ let mut cwdPtr = WasmI32.fromGrain(cwd)
2065
+ let cwdLen = WasmI32.load(cwdPtr, 4n)
2066
+ cwdPtr += 8n
2067
+
2068
+ let needSlash = WasmI32.load8U(cwdPtr + cwdLen - 1n, 0n) != _CHAR_SLASH
2069
+
2070
+ if (needSlash) {
2071
+ let fullPath = allocateString(cwdLen + 1n + pathLen)
2072
+ Memory.copy(fullPath + 8n, cwdPtr, cwdLen)
2073
+ WasmI32.store8(fullPath + 8n + cwdLen, _CHAR_SLASH, 0n)
2074
+ Memory.copy(fullPath + 8n + cwdLen + 1n, pathPtr, pathLen)
2075
+ return WasmI32.toGrain(fullPath): String
1701
2076
  } else {
1702
- Ok(void)
2077
+ let fullPath = allocateString(cwdLen + pathLen)
2078
+ Memory.copy(fullPath + 8n, cwdPtr, cwdLen)
2079
+ Memory.copy(fullPath + 8n + cwdLen, pathPtr, pathLen)
2080
+ return WasmI32.toGrain(fullPath): String
2081
+ }
2082
+ }
2083
+
2084
+ /**
2085
+ * Similar to `pathOpen`, but resolves the path relative to preopened directories.
2086
+ *
2087
+ * @param path: The path to the file or directory
2088
+ * @param openFlags: Flags that decide how the path will be opened
2089
+ * @param rights: The rights that dictate what may be done with the returned file descriptor
2090
+ * @param rightsInheriting: The rights that dictate what may be done with file descriptors derived from this file descriptor
2091
+ * @param flags: Flags which affect read/write operations on this file descriptor
2092
+ * @returns `Ok(fd)` of the opened file or directory if successful or `Err(exception)` otherwise
2093
+ *
2094
+ * @since v0.6.0
2095
+ */
2096
+ @unsafe
2097
+ provide let open = (
2098
+ path: String,
2099
+ openFlags: List<OpenFlag>,
2100
+ rights: List<Rights>,
2101
+ rightsInheriting: List<Rights>,
2102
+ flags: List<FdFlag>,
2103
+ ) => {
2104
+ match (findPath(makeAbsolute(path))) {
2105
+ Ok((fd, relativePath)) => {
2106
+ pathOpen(
2107
+ fd,
2108
+ [SymlinkFollow],
2109
+ relativePath,
2110
+ openFlags,
2111
+ rights,
2112
+ rightsInheriting,
2113
+ flags
2114
+ )
2115
+ },
2116
+ Err(e) => Err(e),
1703
2117
  }
1704
2118
  }