mt-lang 0.2.0 → 0.2.2

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 (191) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +12 -0
  3. data/Rakefile +1 -1
  4. data/docs/index.html +13 -3
  5. data/lib/milk_tea/base.rb +7 -2
  6. data/std/asset_pack.mt +267 -0
  7. data/std/async/libuv_runtime.mt +539 -0
  8. data/std/async/mailbox.mt +191 -0
  9. data/std/async/runtime.mt +87 -0
  10. data/std/async.mt +87 -0
  11. data/std/base64.mt +185 -0
  12. data/std/behavior_tree.mt +396 -0
  13. data/std/binary.mt +314 -0
  14. data/std/binary_heap.mt +157 -0
  15. data/std/bitset.mt +239 -0
  16. data/std/box2d.mt +535 -0
  17. data/std/bytes.mt +46 -0
  18. data/std/c/box2d.mt +1254 -0
  19. data/std/c/cgltf.mt +647 -0
  20. data/std/c/cjson.mt +106 -0
  21. data/std/c/crypto.mt +11 -0
  22. data/std/c/crypto_support.h +51 -0
  23. data/std/c/ctype.mt +19 -0
  24. data/std/c/ctype_bindgen.h +29 -0
  25. data/std/c/curl.mt +1223 -0
  26. data/std/c/enet.mt +473 -0
  27. data/std/c/errno.mt +41 -0
  28. data/std/c/errno_bindgen.h +53 -0
  29. data/std/c/flecs.mt +2945 -0
  30. data/std/c/fs.linux.mt +43 -0
  31. data/std/c/fs.windows.mt +43 -0
  32. data/std/c/fs_support.h +954 -0
  33. data/std/c/gl.mt +2065 -0
  34. data/std/c/gl_registry_helpers.h +10748 -0
  35. data/std/c/glfw.mt +499 -0
  36. data/std/c/libc.mt +167 -0
  37. data/std/c/libuv.mt +1491 -0
  38. data/std/c/math.mt +22 -0
  39. data/std/c/math_bindgen.h +31 -0
  40. data/std/c/miniaudio.mt +3420 -0
  41. data/std/c/pcre2.mt +735 -0
  42. data/std/c/process.mt +58 -0
  43. data/std/c/process_support.h +1147 -0
  44. data/std/c/raygui.mt +1602 -0
  45. data/std/c/raylib.mt +1245 -0
  46. data/std/c/raymath.mt +163 -0
  47. data/std/c/rlgl.mt +434 -0
  48. data/std/c/rpng.mt +60 -0
  49. data/std/c/rres.mt +187 -0
  50. data/std/c/sdl3.mt +4132 -0
  51. data/std/c/sqlite3.mt +951 -0
  52. data/std/c/stb_image.mt +52 -0
  53. data/std/c/stb_image_resize2.mt +128 -0
  54. data/std/c/stb_image_write.mt +19 -0
  55. data/std/c/stb_rect_pack.mt +38 -0
  56. data/std/c/stb_truetype.mt +175 -0
  57. data/std/c/stb_vorbis.mt +31 -0
  58. data/std/c/stdio.mt +90 -0
  59. data/std/c/steamworks.h +5769 -0
  60. data/std/c/steamworks.mt +4771 -0
  61. data/std/c/string.mt +16 -0
  62. data/std/c/string_bindgen.h +36 -0
  63. data/std/c/sync.mt +33 -0
  64. data/std/c/sync_support.h +219 -0
  65. data/std/c/terminal.mt +24 -0
  66. data/std/c/terminal_support.h +408 -0
  67. data/std/c/time.mt +26 -0
  68. data/std/c/tls.mt +24 -0
  69. data/std/c/tls_support.h +626 -0
  70. data/std/c/tracy.mt +53 -0
  71. data/std/c/zlib.mt +20 -0
  72. data/std/c/zlib_support.h +239 -0
  73. data/std/c/zstd.mt +231 -0
  74. data/std/cell.mt +60 -0
  75. data/std/cgltf.mt +115 -0
  76. data/std/cjson.mt +90 -0
  77. data/std/cli.mt +768 -0
  78. data/std/cookie.mt +198 -0
  79. data/std/counter.mt +160 -0
  80. data/std/crypto.mt +74 -0
  81. data/std/cstring.mt +13 -0
  82. data/std/ctype.mt +52 -0
  83. data/std/curl/runtime.mt +261 -0
  84. data/std/curl.mt +38 -0
  85. data/std/deque.mt +348 -0
  86. data/std/encoding.mt +93 -0
  87. data/std/enet.mt +133 -0
  88. data/std/env.mt +41 -0
  89. data/std/errno.mt +47 -0
  90. data/std/flecs.mt +978 -0
  91. data/std/fmt.mt +271 -0
  92. data/std/fs.linux.mt +696 -0
  93. data/std/fs.windows.mt +711 -0
  94. data/std/fsm.mt +267 -0
  95. data/std/gl.mt +2062 -0
  96. data/std/glfw.mt +471 -0
  97. data/std/goap.mt +342 -0
  98. data/std/graph.mt +521 -0
  99. data/std/gzip.mt +77 -0
  100. data/std/hash.mt +429 -0
  101. data/std/http/server.mt +810 -0
  102. data/std/http.mt +1227 -0
  103. data/std/intern.mt +53 -0
  104. data/std/jobs.mt +288 -0
  105. data/std/json.mt +627 -0
  106. data/std/libc.mt +34 -0
  107. data/std/libuv.mt +554 -0
  108. data/std/linear_algebra.mt +243 -0
  109. data/std/linked_map.mt +372 -0
  110. data/std/linked_map_view.mt +49 -0
  111. data/std/linked_set.mt +117 -0
  112. data/std/log.mt +69 -0
  113. data/std/map.mt +418 -0
  114. data/std/math.mt +24 -0
  115. data/std/mem/arena.mt +137 -0
  116. data/std/mem/endian.mt +51 -0
  117. data/std/mem/heap.mt +298 -0
  118. data/std/mem/pool.mt +164 -0
  119. data/std/mem/stack.mt +47 -0
  120. data/std/mem/tracking.mt +119 -0
  121. data/std/miniaudio.mt +1299 -0
  122. data/std/multiset.mt +191 -0
  123. data/std/net/channel.mt +727 -0
  124. data/std/net/clock.mt +237 -0
  125. data/std/net/discovery.mt +277 -0
  126. data/std/net/lobby.mt +813 -0
  127. data/std/net/manager.mt +539 -0
  128. data/std/net/mux.mt +839 -0
  129. data/std/net/nat.mt +122 -0
  130. data/std/net/packet.mt +219 -0
  131. data/std/net/punch.mt +162 -0
  132. data/std/net/rpc.mt +119 -0
  133. data/std/net/session.mt +1157 -0
  134. data/std/net/stun.mt +252 -0
  135. data/std/net/sync.mt +183 -0
  136. data/std/net/turn.mt +459 -0
  137. data/std/net.mt +2944 -0
  138. data/std/oauth2.mt +408 -0
  139. data/std/option.mt +51 -0
  140. data/std/ordered_map.mt +497 -0
  141. data/std/ordered_set.mt +348 -0
  142. data/std/path.mt +368 -0
  143. data/std/pcre2/runtime.mt +35 -0
  144. data/std/pcre2.mt +78 -0
  145. data/std/priority_queue.mt +55 -0
  146. data/std/process.mt +837 -0
  147. data/std/queue.mt +55 -0
  148. data/std/random.mt +146 -0
  149. data/std/raygui.mt +99 -0
  150. data/std/raylib/debug_console.mt +71 -0
  151. data/std/raylib/easing.mt +388 -0
  152. data/std/raylib/packed_assets.mt +255 -0
  153. data/std/raylib/runtime.mt +30 -0
  154. data/std/raylib/tracy_gpu.mt +37 -0
  155. data/std/raylib.mt +1510 -0
  156. data/std/raymath.mt +153 -0
  157. data/std/result.mt +89 -0
  158. data/std/rlgl.mt +268 -0
  159. data/std/rpng.mt +46 -0
  160. data/std/rres.mt +36 -0
  161. data/std/sdl3/runtime.mt +54 -0
  162. data/std/sdl3.mt +1731 -0
  163. data/std/serialize.mt +68 -0
  164. data/std/set.mt +124 -0
  165. data/std/spatial.mt +176 -0
  166. data/std/sqlite3.mt +151 -0
  167. data/std/stack.mt +55 -0
  168. data/std/stb_image.mt +47 -0
  169. data/std/stb_image_resize2.mt +41 -0
  170. data/std/stb_image_write.mt +17 -0
  171. data/std/stb_rect_pack.mt +15 -0
  172. data/std/stb_truetype.mt +77 -0
  173. data/std/stb_vorbis.mt +16 -0
  174. data/std/stdio.mt +88 -0
  175. data/std/steamworks.mt +1542 -0
  176. data/std/str.mt +293 -0
  177. data/std/string.mt +234 -0
  178. data/std/sync.mt +194 -0
  179. data/std/tar.mt +704 -0
  180. data/std/terminal.mt +1002 -0
  181. data/std/testing.mt +266 -0
  182. data/std/thread.mt +120 -0
  183. data/std/time.mt +105 -0
  184. data/std/tls.mt +616 -0
  185. data/std/toml.mt +1310 -0
  186. data/std/tracy.mt +42 -0
  187. data/std/uri.mt +118 -0
  188. data/std/url.mt +372 -0
  189. data/std/vec.mt +433 -0
  190. data/std/zstd.mt +94 -0
  191. metadata +187 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b4aaba4671bdb71836f067696332bad9ffa35c7b62fbc349465d687d983cc2e9
4
- data.tar.gz: 87a38b693e11e6a91530ad4356e520cc0a4be4fc3551b0570447049578a69e57
3
+ metadata.gz: 4cffe1ff676e4ac5144fe70cf4e7be194072adc1291c59fa38678e1f4082e00f
4
+ data.tar.gz: 0bc2bf96c010bab477df55452c835bd82ff6e18ce96d2b3f18ce6fa648ae2f59
5
5
  SHA512:
6
- metadata.gz: 13d55f5a744ac69123b94dd7d0cc495ddc2cfba698139d1af9bdfaca9a3b768bbf4e62c9ba7082c41f6d6b8321c7e979a967051557b0fd494059595d744d3e99
7
- data.tar.gz: f7c37ea07ab4f3ff4f8cf32987952611dc90ebc88dbc60c59309119cd0d9c9752dc4aa380e46527bd01db83aa820f8a39ff6a65a3a1a1c52c6f5f7d88e39a8ff
6
+ metadata.gz: 24e0c9b23bdde1e472073a5fcbf39ac5742bce6df1ccc7b1688a7fffed9ad71aa8f681056e582e3d310a338790045a23f292daf91872b511eaa92576fa320adf
7
+ data.tar.gz: 3e33af1f89a1c8571182fd11bbec65e10088c51f0f2105af131f50dccc77e93aa06cd05dd3aa4b666038d080f2dc52f4da9935686df8ec97d88b915d5663d91c
data/README.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Milk Tea
2
2
 
3
+ A statically typed, indentation-based systems language for games.
4
+ Compiles to readable C. Safe by default, explicit by design.
5
+
6
+ ```bash
7
+ gem install mt-lang
8
+ mtc run hello.mt
9
+ ```
10
+
11
+ [VS Code extension](https://marketplace.visualstudio.com/items?itemName=teefan.milk-tea-lang) — syntax highlighting, IntelliSense, debugging
12
+
13
+ ---
14
+
3
15
  This README is the primary, implementation-focused language reference for the project.
4
16
  It is the preferred first entry point for getting to know the language.
5
17
 
data/Rakefile CHANGED
@@ -296,7 +296,7 @@ namespace :release do
296
296
  desc "Build and publish the gem to RubyGems.org"
297
297
  task :push do
298
298
  sh "gem build milk_tea.gemspec"
299
- gem_file = Dir["milk_tea-*.gem"].sort_by { |f| File.mtime(f) }.last
299
+ gem_file = Dir["mt-lang-*.gem"].sort_by { |f| File.mtime(f) }.last
300
300
  sh "gem push #{gem_file}"
301
301
  end
302
302
  end
data/docs/index.html CHANGED
@@ -1,9 +1,10 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en" data-theme="light">
3
3
  <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Milk Tea &mdash; Language Reference</title>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiB2aWV3Qm94PSIwIDAgMTI4IDEyOCIgZmlsbD0ibm9uZSI+CiAgPHBhdGggZD0iTTc4IDEwbDE2IDgtMTggMzUtMTYtOCAxOC0zNXoiIGZpbGw9IiNkOTc3MDYiLz4KCiAgPHBhdGggZD0iTTMxIDMzaDY2YzQgMCA4IDQgOCA4djJIMjN2LTJjMC00IDQtOCA4LTh6IiBmaWxsPSIjZTBmMmZlIi8+CiAgPHBhdGggZD0iTTI3IDQ0aDc0IiBzdHJva2U9IiM3ZGQzZmMiIHN0cm9rZS13aWR0aD0iMyIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+CgogIDxwYXRoIGQ9Ik0zNCA0M2g2MGwtOCA3MEg0MmwtOC03MHoiIGZpbGw9IiNhMTYyMDciLz4KICA8cGF0aCBkPSJNMzggNDNoNTJsLTcgNzBINDVsLTctNzB6IiBmaWxsPSIjZDZhNTZiIi8+CgogIDxjaXJjbGUgY3g9IjQ5IiBjeT0iOTYiIHI9IjYiIGZpbGw9IiMyYTE1MGQiLz4KICA8Y2lyY2xlIGN4PSI2MyIgY3k9Ijk4IiByPSI2IiBmaWxsPSIjMmExNTBkIi8+CiAgPGNpcmNsZSBjeD0iNzciIGN5PSI5NiIgcj0iNiIgZmlsbD0iIzJhMTUwZCIvPgogIDxjaXJjbGUgY3g9IjU2IiBjeT0iODYiIHI9IjUiIGZpbGw9IiMyYTE1MGQiLz4KICA8Y2lyY2xlIGN4PSI3MCIgY3k9Ijg2IiByPSI1IiBmaWxsPSIjMmExNTBkIi8+CgogIDxwYXRoIGQ9Ik00NyAxMTZoMzQiIHN0cm9rZT0iI2I0NTMwOSIgc3Ryb2tlLXdpZHRoPSI1IiBzdHJva2UtbGluZWNhcD0icm91bmQiLz4KPC9zdmc+Cg==">
7
+ <title>Milk Tea &mdash; Language Reference</title>
7
8
  <meta name="description" content="Milk Tea is a statically typed, indentation-based systems language for games. It targets beautiful C.">
8
9
  <style>
9
10
  /* ── Reset ────────────────────────────────────────────────────────────────── */
@@ -269,7 +270,16 @@ p + p{margin-top:-.25rem}
269
270
  <div class="hero">
270
271
  <h1>Milk Tea <span>Reference</span></h1>
271
272
  <p class="tagline">A statically typed, indentation-based systems language for games. Safe by default, explicit by design, compiling to <strong>beautiful C</strong>.</p>
273
+ <div class="code-wrap" style="margin-bottom:1rem">
274
+ <button class="copy-btn" onclick="copyCode(this)">Copy</button>
275
+ <pre><code>$ gem install mt-lang
276
+ $ mtc run hello.mt</code></pre>
277
+ </div>
272
278
  <div class="badges">
279
+ <span class="badge">&#128230; Install: <code>gem install mt-lang</code></span>
280
+ <span class="badge ac"><a href="https://marketplace.visualstudio.com/items?itemName=teefan.milk-tea-lang" style="color:inherit;text-decoration:none">&#128187; VS Code Extension</a></span>
281
+ </div>
282
+ <div class="badges" style="margin-top:.5rem">
273
283
  <span class="badge">&#9889; Statically Typed</span>
274
284
  <span class="badge">&#127758; Compiles to C</span>
275
285
  <span class="badge ac">&#128274; Safe by Default</span>
data/lib/milk_tea/base.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  require "pathname"
4
4
 
5
5
  module MilkTea
6
- VERSION = "0.2.0"
6
+ VERSION = "0.2.2"
7
7
 
8
8
  def self.root
9
9
  @root ||= Pathname.new(File.expand_path("../..", __dir__))
@@ -11,7 +11,7 @@ module MilkTea
11
11
 
12
12
  def self.data_root
13
13
  @data_root ||= begin
14
- if File.writable?(root.to_s)
14
+ if !installed_as_gem? && File.writable?(root.to_s)
15
15
  root
16
16
  else
17
17
  xdg_cache = ENV.fetch("XDG_CACHE_HOME", File.join(Dir.home, ".cache"))
@@ -20,6 +20,11 @@ module MilkTea
20
20
  end
21
21
  end
22
22
 
23
+ def self.installed_as_gem?
24
+ root.to_s.match?(%r{/gems/mt-lang-})
25
+ end
26
+ private_class_method :installed_as_gem?
27
+
23
28
  def self.writable_root_for(root)
24
29
  resolved = Pathname.new(File.expand_path(root.to_s))
25
30
  if resolved.to_s == MilkTea.root.to_s
data/std/asset_pack.mt ADDED
@@ -0,0 +1,267 @@
1
+ import std.bytes as bytes
2
+ import std.mem.heap as heap
3
+ import std.stdio as stdio
4
+
5
+ const MAGIC_M: ubyte = 77
6
+ const MAGIC_T: ubyte = 84
7
+ const MAGIC_A: ubyte = 65
8
+ const MAGIC_P: ubyte = 80
9
+ const VERSION: uint = 1
10
+ const HEADER_FLAGS: uint = 0
11
+ const ENTRY_FLAGS_RAW: uint = 0
12
+ const HEADER_SIZE_BYTES: ptr_uint = 28
13
+ const ENTRY_PREFIX_SIZE_BYTES: ptr_uint = 32
14
+
15
+ public enum Error: int
16
+ open_failed = 1
17
+ closed = 2
18
+ invalid_magic = 3
19
+ unsupported_version = 4
20
+ unsupported_flags = 5
21
+ range = 6
22
+ malformed_header = 7
23
+ malformed_index = 8
24
+ entry_not_found = 9
25
+ io = 10
26
+
27
+ public struct Reader:
28
+ file: stdio.File?
29
+ entry_count: uint
30
+
31
+ struct EntryMetadata:
32
+ path_length: ptr_uint
33
+ entry_flags: uint
34
+ data_offset: ptr_uint
35
+ stored_size: ptr_uint
36
+ unpacked_size: ptr_uint
37
+
38
+
39
+ public function open(path: str) -> Result[Reader, Error]:
40
+ let file = stdio.file_open(path, "rb") else:
41
+ return Result[Reader, Error].failure(error= Error.open_failed)
42
+
43
+ var header = zero[array[ubyte, 28]]
44
+ let header_ptr = ptr_of(header[0])
45
+ if not read_exact(file, header_ptr, HEADER_SIZE_BYTES):
46
+ stdio.file_close(file)
47
+ return Result[Reader, Error].failure(error= Error.malformed_header)
48
+
49
+ if not valid_magic(header_ptr):
50
+ stdio.file_close(file)
51
+ return Result[Reader, Error].failure(error= Error.invalid_magic)
52
+
53
+ let version = decode_u16_le(unsafe: header_ptr + 4)
54
+ if version != VERSION:
55
+ stdio.file_close(file)
56
+ return Result[Reader, Error].failure(error= Error.unsupported_version)
57
+
58
+ let header_bits = decode_u16_le(unsafe: header_ptr + 6)
59
+ if header_bits != HEADER_FLAGS:
60
+ stdio.file_close(file)
61
+ return Result[Reader, Error].failure(error= Error.unsupported_flags)
62
+
63
+ let entry_count = decode_u32_le(unsafe: header_ptr + 8)
64
+ let index_size_result = decode_u64_le(unsafe: header_ptr + 12)
65
+ var index_size: ptr_uint
66
+ match index_size_result:
67
+ Result.failure as payload:
68
+ stdio.file_close(file)
69
+ return Result[Reader, Error].failure(error= payload.error)
70
+ Result.success as index_payload:
71
+ index_size = index_payload.value
72
+
73
+ let data_offset_result = decode_u64_le(unsafe: header_ptr + 20)
74
+ var data_offset: ptr_uint
75
+ match data_offset_result:
76
+ Result.failure as payload:
77
+ stdio.file_close(file)
78
+ return Result[Reader, Error].failure(error= payload.error)
79
+ Result.success as data_payload:
80
+ data_offset = data_payload.value
81
+
82
+ if data_offset != HEADER_SIZE_BYTES + index_size:
83
+ stdio.file_close(file)
84
+ return Result[Reader, Error].failure(error= Error.malformed_header)
85
+
86
+ return Result[Reader, Error].success(value= Reader(file = file, entry_count = entry_count))
87
+
88
+
89
+ extending Reader:
90
+ public editable function close() -> void:
91
+ if this.file != null:
92
+ stdio.file_close(this.file)
93
+
94
+ this.file = null
95
+ this.entry_count = 0
96
+
97
+
98
+ public function read_bytes(logical_path: str) -> Result[bytes.Bytes, Error]:
99
+ if this.file == null:
100
+ return Result[bytes.Bytes, Error].failure(error= Error.closed)
101
+
102
+ if stdio.file_seek(this.file, HEADER_SIZE_BYTES, stdio.SEEK_SET) != 0:
103
+ return Result[bytes.Bytes, Error].failure(error= Error.io)
104
+
105
+ var entry_index: uint = 0
106
+ while entry_index < this.entry_count:
107
+ let metadata_result = read_entry_metadata(this.file)
108
+ match metadata_result:
109
+ Result.failure as payload:
110
+ return Result[bytes.Bytes, Error].failure(error= payload.error)
111
+ Result.success as metadata_payload:
112
+ let metadata = metadata_payload.value
113
+ let path_match_result = read_path_matches(this.file, metadata.path_length, logical_path)
114
+ match path_match_result:
115
+ Result.failure as payload:
116
+ return Result[bytes.Bytes, Error].failure(error= payload.error)
117
+ Result.success as match_payload:
118
+ if match_payload.value:
119
+ if metadata.entry_flags != ENTRY_FLAGS_RAW:
120
+ return Result[bytes.Bytes, Error].failure(error= Error.unsupported_flags)
121
+
122
+ if metadata.stored_size != metadata.unpacked_size:
123
+ return Result[bytes.Bytes, Error].failure(error= Error.malformed_index)
124
+
125
+ if stdio.file_seek(this.file, ptr_int<-metadata.data_offset, stdio.SEEK_SET) != 0:
126
+ return Result[bytes.Bytes, Error].failure(error= Error.io)
127
+
128
+ return read_payload(this.file, metadata.stored_size)
129
+ entry_index += 1
130
+
131
+ return Result[bytes.Bytes, Error].failure(error= Error.entry_not_found)
132
+
133
+
134
+ function valid_magic(header: ptr[ubyte]) -> bool:
135
+ unsafe:
136
+ return (
137
+ read(header + 0) == MAGIC_M and
138
+ read(header + 1) == MAGIC_T and
139
+ read(header + 2) == MAGIC_A and
140
+ read(header + 3) == MAGIC_P
141
+ )
142
+
143
+
144
+ function read_entry_metadata(file: stdio.File?) -> Result[EntryMetadata, Error]:
145
+ var prefix = zero[array[ubyte, 32]]
146
+ let prefix_ptr = ptr_of(prefix[0])
147
+ if not read_exact(file, prefix_ptr, ENTRY_PREFIX_SIZE_BYTES):
148
+ return Result[EntryMetadata, Error].failure(error= Error.malformed_index)
149
+
150
+ let path_length = ptr_uint<-decode_u32_le(prefix_ptr)
151
+ if path_length == 0:
152
+ return Result[EntryMetadata, Error].failure(error= Error.malformed_index)
153
+
154
+ let entry_bits = decode_u32_le(unsafe: prefix_ptr + 4)
155
+ let data_offset_result = decode_u64_le(unsafe: prefix_ptr + 8)
156
+ var data_offset: ptr_uint
157
+ match data_offset_result:
158
+ Result.failure as payload:
159
+ return Result[EntryMetadata, Error].failure(error= payload.error)
160
+ Result.success as data_offset_payload:
161
+ data_offset = data_offset_payload.value
162
+
163
+ let stored_size_result = decode_u64_le(unsafe: prefix_ptr + 16)
164
+ var stored_size: ptr_uint
165
+ match stored_size_result:
166
+ Result.failure as payload:
167
+ return Result[EntryMetadata, Error].failure(error= payload.error)
168
+ Result.success as stored_size_payload:
169
+ stored_size = stored_size_payload.value
170
+
171
+ let unpacked_size_result = decode_u64_le(unsafe: prefix_ptr + 24)
172
+ var unpacked_size: ptr_uint
173
+ match unpacked_size_result:
174
+ Result.failure as payload:
175
+ return Result[EntryMetadata, Error].failure(error= payload.error)
176
+ Result.success as unpacked_size_payload:
177
+ unpacked_size = unpacked_size_payload.value
178
+
179
+ return Result[EntryMetadata, Error].success(value= EntryMetadata(
180
+ path_length = path_length,
181
+ entry_flags = entry_bits,
182
+ data_offset = data_offset,
183
+ stored_size = stored_size,
184
+ unpacked_size = unpacked_size
185
+ ))
186
+
187
+
188
+ function read_path_matches(file: stdio.File?, path_length: ptr_uint, logical_path: str) -> Result[bool, Error]:
189
+ let path_buffer = heap.must_alloc[ubyte](path_length)
190
+ defer heap.release(path_buffer)
191
+
192
+ if not read_exact(file, path_buffer, path_length):
193
+ return Result[bool, Error].failure(error= Error.malformed_index)
194
+
195
+ return Result[bool, Error].success(value= bytes_equal_str(path_buffer, path_length, logical_path))
196
+
197
+
198
+ function read_payload(file: stdio.File?, size_bytes: ptr_uint) -> Result[bytes.Bytes, Error]:
199
+ if size_bytes == 0:
200
+ return Result[bytes.Bytes, Error].success(value= bytes.Bytes.empty())
201
+
202
+ let data = heap.must_alloc[ubyte](size_bytes)
203
+ if not read_exact(file, data, size_bytes):
204
+ heap.release(data)
205
+ return Result[bytes.Bytes, Error].failure(error= Error.io)
206
+
207
+ return Result[bytes.Bytes, Error].success(value= bytes.Bytes(data = data, len = size_bytes))
208
+
209
+
210
+ function read_exact(file: stdio.File?, buffer: ptr[ubyte], size_bytes: ptr_uint) -> bool:
211
+ if size_bytes == 0:
212
+ return true
213
+
214
+ return stdio.file_read_bytes(unsafe: ptr[void]<-buffer, 1, size_bytes, file) == size_bytes
215
+
216
+
217
+ function bytes_equal_str(left: ptr[ubyte], left_len: ptr_uint, right: str) -> bool:
218
+ if left_len != right.len:
219
+ return false
220
+
221
+ var index: ptr_uint = 0
222
+ while index < left_len:
223
+ unsafe:
224
+ if read(left + index) != ubyte<-read(right.data + index):
225
+ return false
226
+ index += 1
227
+
228
+ return true
229
+
230
+
231
+ function decode_u16_le(bytes: ptr[ubyte]) -> uint:
232
+ unsafe:
233
+ return uint<-read(bytes + 0) | (uint<-read(bytes + 1) << 8)
234
+
235
+
236
+ function decode_u32_le(bytes: ptr[ubyte]) -> uint:
237
+ unsafe:
238
+ return (
239
+ uint<-read(bytes + 0) |
240
+ uint<-read(bytes + 1) << 8 |
241
+ uint<-read(bytes + 2) << 16 |
242
+ uint<-read(bytes + 3) << 24
243
+ )
244
+
245
+
246
+ function decode_u64_le(bytes: ptr[ubyte]) -> Result[ptr_uint, Error]:
247
+ if size_of(ptr[void]) < 8:
248
+ var upper_index: ptr_uint = 4
249
+ while upper_index < 8:
250
+ unsafe:
251
+ if read(bytes + upper_index) != 0:
252
+ return Result[ptr_uint, Error].failure(error= Error.range)
253
+ upper_index += 1
254
+
255
+ let word_bytes = size_of(ptr[void])
256
+ var count = word_bytes
257
+ if count > 8:
258
+ count = 8
259
+
260
+ var value: ptr_uint = 0
261
+ var index: ptr_uint = 0
262
+ while index < count:
263
+ unsafe:
264
+ value = value | (ptr_uint<-read(bytes + index) << (index * 8))
265
+ index += 1
266
+
267
+ return Result[ptr_uint, Error].success(value= value)