mt-lang 0.2.0 → 0.2.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 (189) hide show
  1. checksums.yaml +4 -4
  2. data/docs/index.html +4 -3
  3. data/lib/milk_tea/base.rb +1 -1
  4. data/std/asset_pack.mt +267 -0
  5. data/std/async/libuv_runtime.mt +539 -0
  6. data/std/async/mailbox.mt +191 -0
  7. data/std/async/runtime.mt +87 -0
  8. data/std/async.mt +87 -0
  9. data/std/base64.mt +185 -0
  10. data/std/behavior_tree.mt +396 -0
  11. data/std/binary.mt +314 -0
  12. data/std/binary_heap.mt +157 -0
  13. data/std/bitset.mt +239 -0
  14. data/std/box2d.mt +535 -0
  15. data/std/bytes.mt +46 -0
  16. data/std/c/box2d.mt +1254 -0
  17. data/std/c/cgltf.mt +647 -0
  18. data/std/c/cjson.mt +106 -0
  19. data/std/c/crypto.mt +11 -0
  20. data/std/c/crypto_support.h +51 -0
  21. data/std/c/ctype.mt +19 -0
  22. data/std/c/ctype_bindgen.h +29 -0
  23. data/std/c/curl.mt +1223 -0
  24. data/std/c/enet.mt +473 -0
  25. data/std/c/errno.mt +41 -0
  26. data/std/c/errno_bindgen.h +53 -0
  27. data/std/c/flecs.mt +2945 -0
  28. data/std/c/fs.linux.mt +43 -0
  29. data/std/c/fs.windows.mt +43 -0
  30. data/std/c/fs_support.h +954 -0
  31. data/std/c/gl.mt +2065 -0
  32. data/std/c/gl_registry_helpers.h +10748 -0
  33. data/std/c/glfw.mt +499 -0
  34. data/std/c/libc.mt +167 -0
  35. data/std/c/libuv.mt +1491 -0
  36. data/std/c/math.mt +22 -0
  37. data/std/c/math_bindgen.h +31 -0
  38. data/std/c/miniaudio.mt +3420 -0
  39. data/std/c/pcre2.mt +735 -0
  40. data/std/c/process.mt +58 -0
  41. data/std/c/process_support.h +1147 -0
  42. data/std/c/raygui.mt +1602 -0
  43. data/std/c/raylib.mt +1245 -0
  44. data/std/c/raymath.mt +163 -0
  45. data/std/c/rlgl.mt +434 -0
  46. data/std/c/rpng.mt +60 -0
  47. data/std/c/rres.mt +187 -0
  48. data/std/c/sdl3.mt +4132 -0
  49. data/std/c/sqlite3.mt +951 -0
  50. data/std/c/stb_image.mt +52 -0
  51. data/std/c/stb_image_resize2.mt +128 -0
  52. data/std/c/stb_image_write.mt +19 -0
  53. data/std/c/stb_rect_pack.mt +38 -0
  54. data/std/c/stb_truetype.mt +175 -0
  55. data/std/c/stb_vorbis.mt +31 -0
  56. data/std/c/stdio.mt +90 -0
  57. data/std/c/steamworks.h +5769 -0
  58. data/std/c/steamworks.mt +4771 -0
  59. data/std/c/string.mt +16 -0
  60. data/std/c/string_bindgen.h +36 -0
  61. data/std/c/sync.mt +33 -0
  62. data/std/c/sync_support.h +219 -0
  63. data/std/c/terminal.mt +24 -0
  64. data/std/c/terminal_support.h +408 -0
  65. data/std/c/time.mt +26 -0
  66. data/std/c/tls.mt +24 -0
  67. data/std/c/tls_support.h +626 -0
  68. data/std/c/tracy.mt +53 -0
  69. data/std/c/zlib.mt +20 -0
  70. data/std/c/zlib_support.h +239 -0
  71. data/std/c/zstd.mt +231 -0
  72. data/std/cell.mt +60 -0
  73. data/std/cgltf.mt +115 -0
  74. data/std/cjson.mt +90 -0
  75. data/std/cli.mt +768 -0
  76. data/std/cookie.mt +198 -0
  77. data/std/counter.mt +160 -0
  78. data/std/crypto.mt +74 -0
  79. data/std/cstring.mt +13 -0
  80. data/std/ctype.mt +52 -0
  81. data/std/curl/runtime.mt +261 -0
  82. data/std/curl.mt +38 -0
  83. data/std/deque.mt +348 -0
  84. data/std/encoding.mt +93 -0
  85. data/std/enet.mt +133 -0
  86. data/std/env.mt +41 -0
  87. data/std/errno.mt +47 -0
  88. data/std/flecs.mt +978 -0
  89. data/std/fmt.mt +271 -0
  90. data/std/fs.linux.mt +696 -0
  91. data/std/fs.windows.mt +711 -0
  92. data/std/fsm.mt +267 -0
  93. data/std/gl.mt +2062 -0
  94. data/std/glfw.mt +471 -0
  95. data/std/goap.mt +342 -0
  96. data/std/graph.mt +521 -0
  97. data/std/gzip.mt +77 -0
  98. data/std/hash.mt +429 -0
  99. data/std/http/server.mt +810 -0
  100. data/std/http.mt +1227 -0
  101. data/std/intern.mt +53 -0
  102. data/std/jobs.mt +288 -0
  103. data/std/json.mt +627 -0
  104. data/std/libc.mt +34 -0
  105. data/std/libuv.mt +554 -0
  106. data/std/linear_algebra.mt +243 -0
  107. data/std/linked_map.mt +372 -0
  108. data/std/linked_map_view.mt +49 -0
  109. data/std/linked_set.mt +117 -0
  110. data/std/log.mt +69 -0
  111. data/std/map.mt +418 -0
  112. data/std/math.mt +24 -0
  113. data/std/mem/arena.mt +137 -0
  114. data/std/mem/endian.mt +51 -0
  115. data/std/mem/heap.mt +298 -0
  116. data/std/mem/pool.mt +164 -0
  117. data/std/mem/stack.mt +47 -0
  118. data/std/mem/tracking.mt +119 -0
  119. data/std/miniaudio.mt +1299 -0
  120. data/std/multiset.mt +191 -0
  121. data/std/net/channel.mt +727 -0
  122. data/std/net/clock.mt +237 -0
  123. data/std/net/discovery.mt +277 -0
  124. data/std/net/lobby.mt +813 -0
  125. data/std/net/manager.mt +539 -0
  126. data/std/net/mux.mt +839 -0
  127. data/std/net/nat.mt +122 -0
  128. data/std/net/packet.mt +219 -0
  129. data/std/net/punch.mt +162 -0
  130. data/std/net/rpc.mt +119 -0
  131. data/std/net/session.mt +1157 -0
  132. data/std/net/stun.mt +252 -0
  133. data/std/net/sync.mt +183 -0
  134. data/std/net/turn.mt +459 -0
  135. data/std/net.mt +2944 -0
  136. data/std/oauth2.mt +408 -0
  137. data/std/option.mt +51 -0
  138. data/std/ordered_map.mt +497 -0
  139. data/std/ordered_set.mt +348 -0
  140. data/std/path.mt +368 -0
  141. data/std/pcre2/runtime.mt +35 -0
  142. data/std/pcre2.mt +78 -0
  143. data/std/priority_queue.mt +55 -0
  144. data/std/process.mt +837 -0
  145. data/std/queue.mt +55 -0
  146. data/std/random.mt +146 -0
  147. data/std/raygui.mt +99 -0
  148. data/std/raylib/debug_console.mt +71 -0
  149. data/std/raylib/easing.mt +388 -0
  150. data/std/raylib/packed_assets.mt +255 -0
  151. data/std/raylib/runtime.mt +30 -0
  152. data/std/raylib/tracy_gpu.mt +37 -0
  153. data/std/raylib.mt +1510 -0
  154. data/std/raymath.mt +153 -0
  155. data/std/result.mt +89 -0
  156. data/std/rlgl.mt +268 -0
  157. data/std/rpng.mt +46 -0
  158. data/std/rres.mt +36 -0
  159. data/std/sdl3/runtime.mt +54 -0
  160. data/std/sdl3.mt +1731 -0
  161. data/std/serialize.mt +68 -0
  162. data/std/set.mt +124 -0
  163. data/std/spatial.mt +176 -0
  164. data/std/sqlite3.mt +151 -0
  165. data/std/stack.mt +55 -0
  166. data/std/stb_image.mt +47 -0
  167. data/std/stb_image_resize2.mt +41 -0
  168. data/std/stb_image_write.mt +17 -0
  169. data/std/stb_rect_pack.mt +15 -0
  170. data/std/stb_truetype.mt +77 -0
  171. data/std/stb_vorbis.mt +16 -0
  172. data/std/stdio.mt +88 -0
  173. data/std/steamworks.mt +1542 -0
  174. data/std/str.mt +293 -0
  175. data/std/string.mt +234 -0
  176. data/std/sync.mt +194 -0
  177. data/std/tar.mt +704 -0
  178. data/std/terminal.mt +1002 -0
  179. data/std/testing.mt +266 -0
  180. data/std/thread.mt +120 -0
  181. data/std/time.mt +105 -0
  182. data/std/tls.mt +616 -0
  183. data/std/toml.mt +1310 -0
  184. data/std/tracy.mt +42 -0
  185. data/std/uri.mt +118 -0
  186. data/std/url.mt +372 -0
  187. data/std/vec.mt +433 -0
  188. data/std/zstd.mt +94 -0
  189. metadata +187 -2
data/std/fs.windows.mt ADDED
@@ -0,0 +1,711 @@
1
+ import std.c.fs as c
2
+ import std.bytes as bytes
3
+ import std.libc as libc
4
+ import std.mem.arena as arena
5
+ import std.mem.heap as heap
6
+ import std.path as path_ops
7
+ import std.str as text
8
+ import std.string as string
9
+ import std.vec as vec
10
+
11
+ const path_kind_none: int = 0
12
+ const path_kind_file: int = 1
13
+ const path_kind_directory: int = 2
14
+ const path_kind_other: int = 3
15
+ public struct Error:
16
+ code: int
17
+ message: string.String
18
+
19
+ public struct Entries:
20
+ values: vec.Vec[string.String]
21
+
22
+ public enum MetadataKind: int
23
+ none = 0
24
+ file = 1
25
+ directory = 2
26
+ other = 3
27
+
28
+ public struct Metadata:
29
+ kind: MetadataKind
30
+ mode: int
31
+ size: ptr_uint
32
+ modified_seconds: ptr_int
33
+ modified_nanoseconds: ptr_int
34
+
35
+
36
+ function take_owned_string(data: ptr[char]?, len: ptr_uint) -> string.String:
37
+ if data == null:
38
+ if len != 0:
39
+ fatal(c"fs.take_owned_string missing storage")
40
+
41
+ return string.String.create()
42
+
43
+ return unsafe: string.String(data = ptr[ubyte]<-data, len = len, capacity = len, owns_storage = true)
44
+
45
+
46
+ function take_owned_bytes(data: ptr[char]?, len: ptr_uint) -> bytes.Bytes:
47
+ if data == null:
48
+ if len != 0:
49
+ fatal(c"fs.take_owned_bytes missing storage")
50
+
51
+ return bytes.Bytes.empty()
52
+
53
+ return unsafe: bytes.Bytes(data = own[ubyte]<-ptr[ubyte]<-data, len = len)
54
+
55
+
56
+ function take_error(raw: c.mt_fs_error, fallback: str) -> Error:
57
+ if raw.message_data == null and raw.message_len == 0:
58
+ return Error(code = raw.code, message = string.String.from_str(fallback))
59
+
60
+ return Error(code = raw.code, message = take_owned_string(raw.message_data, raw.message_len))
61
+
62
+
63
+ function validate_utf8_string(text_value: string.String, error_message: str) -> Result[string.String, Error]:
64
+ match text.utf8_byte_span_as_str(unsafe: span[ubyte](data = ptr[ubyte]<-text_value.data, len = text_value.len)):
65
+ Option.some:
66
+ return Result[string.String, Error].success(value= text_value)
67
+ Option.none:
68
+ var owned = text_value
69
+ owned.release()
70
+ return Result[string.String, Error].failure(error= Error(
71
+ code = -1,
72
+ message = string.String.from_str(error_message)
73
+ ))
74
+
75
+
76
+ function release_string_values(values: ref[vec.Vec[string.String]]) -> void:
77
+ var index: ptr_uint = 0
78
+ while index < values.len():
79
+ let value_ptr = values.get(index) else:
80
+ fatal(c"fs.release_string_values missing value")
81
+
82
+ unsafe:
83
+ read(value_ptr).release()
84
+
85
+ index += 1
86
+
87
+ values.release()
88
+
89
+
90
+ function path_kind(path: str) -> int:
91
+ var storage = arena.create(path.len + 1)
92
+ defer storage.release()
93
+ return c.mt_fs_path_kind(storage.to_cstr(path))
94
+
95
+
96
+ function metadata_kind(raw_kind: int) -> MetadataKind:
97
+ if raw_kind == path_kind_file:
98
+ return MetadataKind.file
99
+
100
+ if raw_kind == path_kind_directory:
101
+ return MetadataKind.directory
102
+
103
+ if raw_kind == path_kind_other:
104
+ return MetadataKind.other
105
+
106
+ return MetadataKind.none
107
+
108
+
109
+ extending Error:
110
+ public editable function release() -> void:
111
+ this.message.release()
112
+
113
+
114
+ extending Entries:
115
+ public function len() -> ptr_uint:
116
+ return this.values.len()
117
+
118
+
119
+ public function get(index: ptr_uint) -> Option[str]:
120
+ let value_ptr = this.values.get(index) else:
121
+ return Option[str].none
122
+
123
+ unsafe:
124
+ return Option[str].some(value= read(value_ptr).as_str())
125
+
126
+
127
+ public function contains(name: str) -> bool:
128
+ var index: ptr_uint = 0
129
+ while index < this.values.len():
130
+ let value_ptr = this.values.get(index) else:
131
+ fatal(c"fs.Entries.contains missing value")
132
+
133
+ unsafe:
134
+ if read(value_ptr).as_str().equal(name):
135
+ return true
136
+
137
+ index += 1
138
+
139
+ return false
140
+
141
+
142
+ public editable function release() -> void:
143
+ release_string_values(ref_of(this.values))
144
+
145
+
146
+ extending Metadata:
147
+ public function is_file() -> bool:
148
+ return this.kind == MetadataKind.file
149
+
150
+
151
+ public function is_directory() -> bool:
152
+ return this.kind == MetadataKind.directory
153
+
154
+
155
+ public function is_other() -> bool:
156
+ return this.kind == MetadataKind.other
157
+
158
+
159
+ public function exists(path: str) -> bool:
160
+ return path_kind(path) != path_kind_none
161
+
162
+
163
+ public function is_file(path: str) -> bool:
164
+ return path_kind(path) == path_kind_file
165
+
166
+
167
+ public function is_directory(path: str) -> bool:
168
+ return path_kind(path) == path_kind_directory
169
+
170
+
171
+ public function read_text(path: str) -> Result[string.String, Error]:
172
+ var storage = arena.create(path.len + 1)
173
+ defer storage.release()
174
+
175
+ var raw_text = zero[c.mt_fs_string]
176
+ var raw_error = zero[c.mt_fs_error]
177
+ let status_code = c.mt_fs_read_text(storage.to_cstr(path), raw_text, raw_error)
178
+ if status_code != 0:
179
+ return Result[string.String, Error].failure(error= take_error(raw_error, "fs read failed"))
180
+
181
+ return validate_utf8_string(take_owned_string(raw_text.data, raw_text.len), "fs.read_text requires UTF-8 text")
182
+
183
+
184
+ public function read_lines(path: str) -> Result[Entries, Error]:
185
+ match read_text(path):
186
+ Result.failure as payload:
187
+ return Result[Entries, Error].failure(error= payload.error)
188
+ Result.success as payload:
189
+ var content = payload.value
190
+ defer content.release()
191
+
192
+ var values = vec.Vec[string.String].create()
193
+ let content_text = content.as_str()
194
+ var start: ptr_uint = 0
195
+ var index: ptr_uint = 0
196
+ while index < content_text.len:
197
+ if content_text.byte_at(index) == 10:
198
+ var stop = index
199
+ if stop > start and content_text.byte_at(stop - 1) == 13:
200
+ stop -= 1
201
+
202
+ values.push(string.String.from_str(content_text.slice(start, stop - start)))
203
+ start = index + 1
204
+
205
+ index += 1
206
+
207
+ if start < content_text.len:
208
+ var stop = content_text.len
209
+ if stop > start and content_text.byte_at(stop - 1) == 13:
210
+ stop -= 1
211
+
212
+ values.push(string.String.from_str(content_text.slice(start, stop - start)))
213
+
214
+ return Result[Entries, Error].success(value= Entries(values = values))
215
+
216
+
217
+ public function read_bytes(path: str) -> Result[bytes.Bytes, Error]:
218
+ var storage = arena.create(path.len + 1)
219
+ defer storage.release()
220
+
221
+ var raw_bytes = zero[c.mt_fs_string]
222
+ var raw_error = zero[c.mt_fs_error]
223
+ let status_code = c.mt_fs_read_bytes(storage.to_cstr(path), raw_bytes, raw_error)
224
+ if status_code != 0:
225
+ return Result[bytes.Bytes, Error].failure(error= take_error(raw_error, "fs read bytes failed"))
226
+
227
+ return Result[bytes.Bytes, Error].success(value= take_owned_bytes(raw_bytes.data, raw_bytes.len))
228
+
229
+
230
+ public function metadata(path: str) -> Result[Metadata, Error]:
231
+ var storage = arena.create(path.len + 1)
232
+ defer storage.release()
233
+
234
+ var raw_metadata = zero[c.mt_fs_metadata]
235
+ var raw_error = zero[c.mt_fs_error]
236
+ let status_code = c.mt_fs_get_metadata(storage.to_cstr(path), raw_metadata, raw_error)
237
+ if status_code != 0:
238
+ return Result[Metadata, Error].failure(error= take_error(raw_error, "fs metadata failed"))
239
+
240
+ return Result[Metadata, Error].success(value= Metadata(
241
+ kind = metadata_kind(raw_metadata.kind),
242
+ mode = raw_metadata.mode,
243
+ size = raw_metadata.size,
244
+ modified_seconds = raw_metadata.modified_seconds,
245
+ modified_nanoseconds = raw_metadata.modified_nanoseconds
246
+ ))
247
+
248
+
249
+ public function write_text(path: str, content: str) -> Result[bool, Error]:
250
+ var storage = arena.create(path.len + 1)
251
+ defer storage.release()
252
+
253
+ var raw_error = zero[c.mt_fs_error]
254
+ let status_code = c.mt_fs_write_text(storage.to_cstr(path), content.data, content.len, raw_error)
255
+ if status_code != 0:
256
+ return Result[bool, Error].failure(error= take_error(raw_error, "fs write failed"))
257
+
258
+ return Result[bool, Error].success(value= true)
259
+
260
+
261
+ public function write_bytes(path: str, content: span[ubyte]) -> Result[bool, Error]:
262
+ var storage = arena.create(path.len + 1)
263
+ defer storage.release()
264
+
265
+ var raw_error = zero[c.mt_fs_error]
266
+ let status_code = c.mt_fs_write_bytes(storage.to_cstr(path), content.data, content.len, raw_error)
267
+ if status_code != 0:
268
+ return Result[bool, Error].failure(error= take_error(raw_error, "fs write bytes failed"))
269
+
270
+ return Result[bool, Error].success(value= true)
271
+
272
+
273
+ public function set_permissions(path: str, mode: int) -> Result[bool, Error]:
274
+ var storage = arena.create(path.len + 1)
275
+ defer storage.release()
276
+
277
+ var raw_error = zero[c.mt_fs_error]
278
+ let status_code = c.mt_fs_set_permissions(storage.to_cstr(path), mode, raw_error)
279
+ if status_code != 0:
280
+ return Result[bool, Error].failure(error= take_error(raw_error, "fs set permissions failed"))
281
+
282
+ return Result[bool, Error].success(value= true)
283
+
284
+
285
+ public function create_directories(path: str) -> Result[bool, Error]:
286
+ var storage = arena.create(path.len + 1)
287
+ defer storage.release()
288
+
289
+ var raw_error = zero[c.mt_fs_error]
290
+ let status_code = c.mt_fs_create_directories(storage.to_cstr(path), raw_error)
291
+ if status_code != 0:
292
+ return Result[bool, Error].failure(error= take_error(raw_error, "fs create directories failed"))
293
+
294
+ return Result[bool, Error].success(value= true)
295
+
296
+
297
+ public function copy_entry(source_path: str, target_path: str) -> Result[bool, Error]:
298
+ if is_file(source_path):
299
+ match create_directories(path_ops.dirname(target_path)):
300
+ Result.failure as payload:
301
+ return Result[bool, Error].failure(error= payload.error)
302
+ Result.success:
303
+ pass
304
+
305
+ match read_bytes(source_path):
306
+ Result.failure as payload:
307
+ return Result[bool, Error].failure(error= payload.error)
308
+ Result.success as payload:
309
+ var data = payload.value
310
+ defer data.release()
311
+ return write_bytes(target_path, data.as_span())
312
+
313
+ if is_directory(source_path):
314
+ match create_directories(target_path):
315
+ Result.failure as payload:
316
+ return Result[bool, Error].failure(error= payload.error)
317
+ Result.success:
318
+ pass
319
+
320
+ match list_entries(source_path):
321
+ Result.failure as payload:
322
+ return Result[bool, Error].failure(error= payload.error)
323
+ Result.success as payload:
324
+ var entries = payload.value
325
+ defer entries.release()
326
+
327
+ var index: ptr_uint = 0
328
+ while index < entries.len():
329
+ match entries.get(index):
330
+ Option.none:
331
+ return Result[
332
+ bool,
333
+ Error
334
+ ].failure(error= static_error("fs copy entry missing source entry"))
335
+ Option.some as entry_payload:
336
+ var child_source = path_ops.join(source_path, entry_payload.value)
337
+ var child_target = path_ops.join(target_path, entry_payload.value)
338
+ match copy_entry(child_source.as_str(), child_target.as_str()):
339
+ Result.failure as child_payload:
340
+ child_source.release()
341
+ child_target.release()
342
+ return Result[bool, Error].failure(error= child_payload.error)
343
+ Result.success:
344
+ pass
345
+ child_source.release()
346
+ child_target.release()
347
+ index += 1
348
+
349
+ return Result[bool, Error].success(value= true)
350
+
351
+ if exists(source_path):
352
+ return Result[
353
+ bool,
354
+ Error
355
+ ].failure(error= static_error("fs.copy_entry supports only regular files and directories"))
356
+
357
+ return Result[bool, Error].failure(error= static_error("fs.copy_entry source does not exist"))
358
+
359
+
360
+ public function remove(path: str) -> Result[bool, Error]:
361
+ var storage = arena.create(path.len + 1)
362
+ defer storage.release()
363
+
364
+ var raw_error = zero[c.mt_fs_error]
365
+ let status_code = c.mt_fs_remove(storage.to_cstr(path), raw_error)
366
+ if status_code != 0:
367
+ return Result[bool, Error].failure(error= take_error(raw_error, "fs remove failed"))
368
+
369
+ return Result[bool, Error].success(value= true)
370
+
371
+
372
+ public function remove_tree(path: str) -> Result[bool, Error]:
373
+ if is_directory(path):
374
+ match list_entries(path):
375
+ Result.failure as payload:
376
+ return Result[bool, Error].failure(error= payload.error)
377
+ Result.success as payload:
378
+ var entries = payload.value
379
+ defer entries.release()
380
+
381
+ var index: ptr_uint = 0
382
+ while index < entries.len():
383
+ match entries.get(index):
384
+ Option.none:
385
+ return Result[bool, Error].failure(error= static_error("fs remove tree missing entry"))
386
+ Option.some as entry_payload:
387
+ var child_path = path_ops.join(path, entry_payload.value)
388
+ match remove_tree(child_path.as_str()):
389
+ Result.failure as child_payload:
390
+ child_path.release()
391
+ return Result[bool, Error].failure(error= child_payload.error)
392
+ Result.success:
393
+ pass
394
+ child_path.release()
395
+ index += 1
396
+
397
+ return remove(path)
398
+
399
+ if exists(path):
400
+ return remove(path)
401
+
402
+ return Result[bool, Error].success(value= true)
403
+
404
+
405
+ public function rename(source_path: str, target_path: str) -> Result[bool, Error]:
406
+ var source_storage = arena.create(source_path.len + 1)
407
+ defer source_storage.release()
408
+ var target_storage = arena.create(target_path.len + 1)
409
+ defer target_storage.release()
410
+
411
+ var raw_error = zero[c.mt_fs_error]
412
+ let status_code = c.mt_fs_rename(
413
+ source_storage.to_cstr(source_path),
414
+ target_storage.to_cstr(target_path),
415
+ raw_error
416
+ )
417
+ if status_code != 0:
418
+ return Result[bool, Error].failure(error= take_error(raw_error, "fs rename failed"))
419
+
420
+ return Result[bool, Error].success(value= true)
421
+
422
+
423
+ public function current_directory() -> Result[string.String, Error]:
424
+ var raw_text = zero[c.mt_fs_string]
425
+ var raw_error = zero[c.mt_fs_error]
426
+ let status_code = c.mt_fs_current_directory(raw_text, raw_error)
427
+ if status_code != 0:
428
+ return Result[string.String, Error].failure(error= take_error(raw_error, "fs current directory failed"))
429
+
430
+ return validate_utf8_string(
431
+ take_owned_string(raw_text.data, raw_text.len),
432
+ "fs.current_directory requires UTF-8 text"
433
+ )
434
+
435
+
436
+ public function find_ancestor_containing(path: str, entry_name: str) -> Option[string.String]:
437
+ var current = path_ops.normalize_separators(path_ops.dirname(path))
438
+ if is_directory(path):
439
+ current.release()
440
+ current = path_ops.normalize_separators(path)
441
+
442
+ while true:
443
+ var candidate = path_ops.join(current.as_str(), entry_name)
444
+ let found = exists(candidate.as_str())
445
+ candidate.release()
446
+ if found:
447
+ return Option[string.String].some(value= current)
448
+
449
+ let parent_text = path_ops.dirname(current.as_str())
450
+ if parent_text == current.as_str():
451
+ current.release()
452
+ return Option[string.String].none
453
+
454
+ let parent = string.String.from_str(parent_text)
455
+ current.release()
456
+ current = parent
457
+
458
+
459
+ function static_error(message: str) -> Error:
460
+ return Error(code = -1, message = string.String.from_str(message))
461
+
462
+
463
+ public function temporary_directory() -> string.String:
464
+ var raw_text = zero[c.mt_fs_string]
465
+ var raw_error = zero[c.mt_fs_error]
466
+ let status_code = c.mt_fs_temporary_directory(raw_text, raw_error)
467
+ if status_code == 0:
468
+ match validate_utf8_string(
469
+ take_owned_string(raw_text.data, raw_text.len),
470
+ "fs.temporary_directory requires UTF-8 text"
471
+ ):
472
+ Result.success as payload:
473
+ return payload.value
474
+ Result.failure as payload:
475
+ payload.error.release()
476
+
477
+ if raw_error.message_data != null or raw_error.message_len != 0:
478
+ var ignored_error = take_error(raw_error, "fs temporary directory failed")
479
+ ignored_error.release()
480
+
481
+ let configured_temp = libc.get_environment_variable("TEMP")
482
+ if configured_temp != null:
483
+ let configured_path = text.cstr_as_str(configured_temp)
484
+ if configured_path.len != 0:
485
+ return string.String.from_str(configured_path)
486
+
487
+ let configured_tmp = libc.get_environment_variable("TMP")
488
+ if configured_tmp != null:
489
+ let configured_path = text.cstr_as_str(configured_tmp)
490
+ if configured_path.len != 0:
491
+ return string.String.from_str(configured_path)
492
+
493
+ let configured_local_app_data = libc.get_environment_variable("LOCALAPPDATA")
494
+ if configured_local_app_data != null:
495
+ let configured_path = text.cstr_as_str(configured_local_app_data)
496
+ if configured_path.len != 0:
497
+ return string.String.from_str(configured_path)
498
+
499
+ return string.String.from_str("C:/Windows/Temp")
500
+
501
+
502
+ public function canonicalize(path: str) -> Result[string.String, Error]:
503
+ var storage = arena.create(path.len + 1)
504
+ defer storage.release()
505
+
506
+ var raw_text = zero[c.mt_fs_string]
507
+ var raw_error = zero[c.mt_fs_error]
508
+ let status_code = c.mt_fs_canonicalize(storage.to_cstr(path), raw_text, raw_error)
509
+ if status_code != 0:
510
+ return Result[string.String, Error].failure(error= take_error(raw_error, "fs canonicalize failed"))
511
+
512
+ return validate_utf8_string(take_owned_string(raw_text.data, raw_text.len), "fs.canonicalize requires UTF-8 text")
513
+
514
+
515
+ public function create_temporary_directory(parent_dir: str, prefix: str) -> Result[string.String, Error]:
516
+ if prefix.len == 0:
517
+ return Result[
518
+ string.String,
519
+ Error
520
+ ].failure(error= static_error("fs.create_temporary_directory requires a non-empty prefix"))
521
+
522
+ var storage = arena.create(parent_dir.len + prefix.len + 2)
523
+ defer storage.release()
524
+
525
+ var raw_text = zero[c.mt_fs_string]
526
+ var raw_error = zero[c.mt_fs_error]
527
+ let status_code = c.mt_fs_create_temporary_directory(
528
+ storage.to_cstr(parent_dir),
529
+ storage.to_cstr(prefix),
530
+ raw_text,
531
+ raw_error
532
+ )
533
+ if status_code != 0:
534
+ return Result[string.String, Error].failure(error= take_error(
535
+ raw_error,
536
+ "fs create temporary directory failed"
537
+ ))
538
+
539
+ return validate_utf8_string(
540
+ take_owned_string(raw_text.data, raw_text.len),
541
+ "fs.create_temporary_directory requires UTF-8 text"
542
+ )
543
+
544
+
545
+ public function create_temporary_directory_in_system_temp(prefix: str) -> Result[string.String, Error]:
546
+ var root = temporary_directory()
547
+ defer root.release()
548
+ return create_temporary_directory(root.as_str(), prefix)
549
+
550
+
551
+ public function create_temporary_file(parent_dir: str, prefix: str, suffix: str) -> Result[string.String, Error]:
552
+ if prefix.len == 0:
553
+ return Result[
554
+ string.String,
555
+ Error
556
+ ].failure(error= static_error("fs.create_temporary_file requires a non-empty prefix"))
557
+
558
+ var storage = arena.create(parent_dir.len + prefix.len + suffix.len + 3)
559
+ defer storage.release()
560
+
561
+ var raw_text = zero[c.mt_fs_string]
562
+ var raw_error = zero[c.mt_fs_error]
563
+ let status_code = c.mt_fs_create_temporary_file(
564
+ storage.to_cstr(parent_dir),
565
+ storage.to_cstr(prefix),
566
+ storage.to_cstr(suffix),
567
+ raw_text,
568
+ raw_error
569
+ )
570
+ if status_code != 0:
571
+ return Result[string.String, Error].failure(error= take_error(raw_error, "fs create temporary file failed"))
572
+
573
+ return validate_utf8_string(
574
+ take_owned_string(raw_text.data, raw_text.len),
575
+ "fs.create_temporary_file requires UTF-8 text"
576
+ )
577
+
578
+
579
+ public function create_temporary_file_in_system_temp(prefix: str, suffix: str) -> Result[string.String, Error]:
580
+ var root = temporary_directory()
581
+ defer root.release()
582
+ return create_temporary_file(root.as_str(), prefix, suffix)
583
+
584
+
585
+ public function list_entries(path: str) -> Result[Entries, Error]:
586
+ var storage = arena.create(path.len + 1)
587
+ defer storage.release()
588
+
589
+ var raw_entries = zero[c.mt_fs_entries]
590
+ var raw_error = zero[c.mt_fs_error]
591
+ let status_code = c.mt_fs_list_entries(storage.to_cstr(path), raw_entries, raw_error)
592
+ if status_code != 0:
593
+ return Result[Entries, Error].failure(error= take_error(raw_error, "fs list entries failed"))
594
+
595
+ var values = vec.Vec[string.String].with_capacity(raw_entries.count)
596
+ var index: ptr_uint = 0
597
+ if raw_entries.count != 0 and (raw_entries.data == null or raw_entries.lengths == null):
598
+ fatal(c"fs.list_entries missing storage")
599
+
600
+ unsafe:
601
+ let data_ptr = ptr[ptr[char]]<-raw_entries.data
602
+ let length_ptr = ptr[ptr_uint]<-raw_entries.lengths
603
+ while index < raw_entries.count:
604
+ let owned = take_owned_string(read(data_ptr + index), read(length_ptr + index))
605
+ match validate_utf8_string(owned, "fs.list_entries requires UTF-8 entry names"):
606
+ Result.failure as payload:
607
+ var remaining = index + 1
608
+ while remaining < raw_entries.count:
609
+ heap.release(read(data_ptr + remaining))
610
+ remaining += 1
611
+ heap.release(raw_entries.data)
612
+ heap.release(raw_entries.lengths)
613
+ release_string_values(ref_of(values))
614
+ return Result[Entries, Error].failure(error= payload.error)
615
+ Result.success as validated_payload:
616
+ values.push(validated_payload.value)
617
+
618
+ index += 1
619
+
620
+ heap.release(raw_entries.data)
621
+ heap.release(raw_entries.lengths)
622
+ return Result[Entries, Error].success(value= Entries(values = values))
623
+
624
+
625
+ public function list_files_recursive(path: str) -> Result[Entries, Error]:
626
+ if is_file(path):
627
+ var values = vec.Vec[string.String].create()
628
+ values.push(string.String.from_str(path))
629
+ return Result[Entries, Error].success(value= Entries(values = values))
630
+
631
+ if not is_directory(path):
632
+ if exists(path):
633
+ return Result[
634
+ Entries,
635
+ Error
636
+ ].failure(error= static_error("fs.list_files_recursive supports only regular files and directories"))
637
+
638
+ return Result[Entries, Error].failure(error= static_error("fs.list_files_recursive path does not exist"))
639
+
640
+ var values = vec.Vec[string.String].create()
641
+ match collect_files_recursive(path, ref_of(values)):
642
+ Result.failure as payload:
643
+ release_string_values(ref_of(values))
644
+ return Result[Entries, Error].failure(error= payload.error)
645
+ Result.success:
646
+ return Result[Entries, Error].success(value= Entries(values = values))
647
+
648
+
649
+ function collect_files_recursive(path: str, output: ref[vec.Vec[string.String]]) -> Result[bool, Error]:
650
+ if is_file(path):
651
+ insert_sorted_string(output, string.String.from_str(path))
652
+ return Result[bool, Error].success(value= true)
653
+
654
+ if not is_directory(path):
655
+ return Result[bool, Error].success(value= true)
656
+
657
+ match list_entries(path):
658
+ Result.failure as payload:
659
+ return Result[bool, Error].failure(error= payload.error)
660
+ Result.success as payload:
661
+ var entries = payload.value
662
+ defer entries.release()
663
+
664
+ var index: ptr_uint = 0
665
+ while index < entries.len():
666
+ match entries.get(index):
667
+ Option.none:
668
+ return Result[bool, Error].failure(error= static_error("fs.list_files_recursive missing entry"))
669
+ Option.some as entry_payload:
670
+ var child_path = path_ops.join(path, entry_payload.value)
671
+ match collect_files_recursive(child_path.as_str(), output):
672
+ Result.failure as child_payload:
673
+ child_path.release()
674
+ return Result[bool, Error].failure(error= child_payload.error)
675
+ Result.success:
676
+ pass
677
+ child_path.release()
678
+ index += 1
679
+
680
+ return Result[bool, Error].success(value= true)
681
+
682
+
683
+ function insert_sorted_string(values: ref[vec.Vec[string.String]], value: string.String) -> void:
684
+ var index: ptr_uint = 0
685
+ while index < values.len():
686
+ let existing_ptr = values.get(index) else:
687
+ fatal(c"fs.insert_sorted_string missing value")
688
+
689
+ unsafe:
690
+ if string_less(value.as_str(), read(existing_ptr).as_str()):
691
+ break
692
+
693
+ index += 1
694
+
695
+ if not values.insert(index, value):
696
+ fatal(c"fs.insert_sorted_string insert failed")
697
+
698
+
699
+ function string_less(left: str, right: str) -> bool:
700
+ var index: ptr_uint = 0
701
+ let shared_len = if left.len < right.len: left.len else: right.len
702
+ while index < shared_len:
703
+ let left_value = left.byte_at(index)
704
+ let right_value = right.byte_at(index)
705
+ if left_value < right_value:
706
+ return true
707
+ if left_value > right_value:
708
+ return false
709
+ index += 1
710
+
711
+ return left.len < right.len