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
@@ -0,0 +1,191 @@
1
+ import std.async as aio
2
+ import std.async.libuv_runtime as aio_backend
3
+ import std.deque as deque
4
+ import std.libuv as libuv
5
+ import std.mem.heap as heap
6
+ import std.str as text
7
+ import std.string as string
8
+ import std.sync as sync
9
+ import std.vec as vec
10
+
11
+ type NativeHandle = libuv.uv_handle_t
12
+ type NativeAsyncHandle = libuv.uv_async_t
13
+
14
+ public struct Error:
15
+ code: int
16
+ message: string.String
17
+
18
+ public struct Mailbox[T]:
19
+ state: ptr[MailboxState[T]]?
20
+
21
+ struct MailboxStateBase:
22
+ destroy: fn(state_frame: ptr[void]) -> void
23
+
24
+ struct MailboxState[T]:
25
+ destroy: fn(state_frame: ptr[void]) -> void
26
+ mutex: sync.Mutex
27
+ queue: deque.Deque[T]
28
+ handle: ptr[NativeAsyncHandle]?
29
+ closing: bool
30
+
31
+
32
+ function libuv_error(code: int) -> Error:
33
+ return Error(code = code, message = string.String.from_str(text.cstr_as_str(libuv.strerror(code))))
34
+
35
+
36
+ function mailbox_error(message: str) -> Error:
37
+ return Error(code = -1, message = string.String.from_str(message))
38
+
39
+
40
+ function async_as_handle(handle: ptr[NativeAsyncHandle]) -> ptr[NativeHandle]:
41
+ return unsafe: ptr[NativeHandle]<-handle
42
+
43
+
44
+ function handle_as_async(handle: ptr[NativeHandle]) -> ptr[NativeAsyncHandle]:
45
+ return unsafe: ptr[NativeAsyncHandle]<-handle
46
+
47
+
48
+ function mailbox_async_callback(handle: ptr[NativeAsyncHandle]) -> void:
49
+ unsafe: handle
50
+
51
+
52
+ function mailbox_destroy_state[T](state_frame: ptr[void]) -> void:
53
+ let state = unsafe: ptr[MailboxState[T]]<-state_frame
54
+
55
+ var mutex = unsafe: read(state).mutex
56
+ mutex.release()
57
+
58
+ var queue = unsafe: read(state).queue
59
+ queue.release()
60
+
61
+ heap.release(state)
62
+
63
+
64
+ function mailbox_close_callback(handle: ptr[NativeHandle]) -> void:
65
+ let state_raw = libuv.handle_get_data(handle) else:
66
+ unsafe: heap.release_bytes(ptr[void]<-handle_as_async(handle))
67
+ return
68
+
69
+ unsafe:
70
+ heap.release_bytes(ptr[void]<-handle_as_async(handle))
71
+
72
+ let state_base = unsafe: ptr[MailboxStateBase]<-state_raw
73
+ unsafe: read(state_base).destroy(state_raw)
74
+
75
+
76
+ function alloc_async_handle() -> ptr[NativeAsyncHandle]:
77
+ let handle_size = libuv.handle_size(libuv.uv_handle_type.UV_ASYNC)
78
+ return unsafe: ptr[NativeAsyncHandle]<-heap.must_alloc_zeroed_bytes(1, handle_size)
79
+
80
+
81
+ public function create_on[T](runtime: aio.Runtime) -> Result[Mailbox[T], Error]:
82
+ let mutex_result = sync.create_mutex()
83
+ match mutex_result:
84
+ Result.failure as payload:
85
+ return Result[Mailbox[T], Error].failure(error = Error(
86
+ code = payload.error.code,
87
+ message = payload.error.message
88
+ ))
89
+ Result.success as payload:
90
+ let loop = aio_backend.runtime_loop(runtime)
91
+ let handle = alloc_async_handle()
92
+ let state = heap.must_alloc_zeroed[MailboxState[T]](1)
93
+ unsafe:
94
+ state.destroy = mailbox_destroy_state[T]
95
+ state.mutex = payload.value
96
+ state.queue = deque.Deque[T].create()
97
+ state.handle = handle
98
+ state.closing = false
99
+ libuv.handle_set_data(async_as_handle(handle), ptr[void]<-state)
100
+
101
+ let status_code = libuv.async_init(loop, handle, mailbox_async_callback)
102
+ if status_code != 0:
103
+ payload.value.release()
104
+ unsafe: heap.release_bytes(ptr[void]<-handle)
105
+ heap.release(state)
106
+ return Result[Mailbox[T], Error].failure(error = libuv_error(status_code))
107
+
108
+ return Result[Mailbox[T], Error].success(value = Mailbox[T](state = state))
109
+
110
+
111
+ public function create[T]() -> Result[Mailbox[T], Error]:
112
+ return create_on[T](aio.current_runtime())
113
+
114
+
115
+ extending Error:
116
+ public editable function release() -> void:
117
+ this.message.release()
118
+
119
+
120
+ extending Mailbox[T]:
121
+ public editable function release() -> void:
122
+ let state = this.state else:
123
+ return
124
+
125
+ this.state = null
126
+
127
+ let handle = unsafe: read(state).handle else:
128
+ mailbox_destroy_state[T](unsafe: ptr[void]<-state)
129
+ return
130
+
131
+ unsafe: read(state).closing = true
132
+ libuv.close(async_as_handle(handle), mailbox_close_callback)
133
+
134
+
135
+ public function send(value: T) -> Result[bool, Error]:
136
+ let state = this.state else:
137
+ return Result[bool, Error].failure(error = mailbox_error("mailbox is released"))
138
+
139
+ var mutex = unsafe: read(state).mutex
140
+ mutex.lock()
141
+ defer mutex.unlock()
142
+
143
+ let handle = unsafe: read(state).handle else:
144
+ return Result[bool, Error].failure(error = mailbox_error("mailbox is closed"))
145
+
146
+ if unsafe: read(state).closing:
147
+ return Result[bool, Error].failure(error = mailbox_error("mailbox is closed"))
148
+
149
+ unsafe: read(state).queue.push_back(value)
150
+ let status_code = libuv.async_send(handle)
151
+ if status_code != 0:
152
+ let _ = unsafe: read(state).queue.pop_back()
153
+ return Result[bool, Error].failure(error = libuv_error(status_code))
154
+
155
+ return Result[bool, Error].success(value = true)
156
+
157
+
158
+ public function try_recv() -> Option[T]:
159
+ let state = this.state else:
160
+ return Option[T].none
161
+
162
+ var mutex = unsafe: read(state).mutex
163
+ mutex.lock()
164
+ defer mutex.unlock()
165
+ return unsafe: read(state).queue.pop_front()
166
+
167
+
168
+ public function drain() -> vec.Vec[T]:
169
+ let state = this.state else:
170
+ return vec.Vec[T].create()
171
+
172
+ var mutex = unsafe: read(state).mutex
173
+ mutex.lock()
174
+ defer mutex.unlock()
175
+
176
+ var drained = vec.Vec[T].with_capacity(unsafe: read(state).queue.len())
177
+ while true:
178
+ let message = unsafe: read(state).queue.pop_front()
179
+ if message.is_none():
180
+ return drained
181
+ drained.push(message.unwrap())
182
+
183
+
184
+ public function is_empty() -> bool:
185
+ let state = this.state else:
186
+ return true
187
+
188
+ var mutex = unsafe: read(state).mutex
189
+ mutex.lock()
190
+ defer mutex.unlock()
191
+ return unsafe: read(state).queue.is_empty()
@@ -0,0 +1,87 @@
1
+ import std.async.libuv_runtime as backend
2
+
3
+ public type Runtime = backend.Runtime
4
+
5
+
6
+ public function runtime_create() -> Runtime:
7
+ return backend.runtime_create()
8
+
9
+
10
+ public function runtime_activate(runtime: Runtime) -> void:
11
+ backend.runtime_activate(runtime)
12
+
13
+
14
+ public function runtime_deactivate() -> void:
15
+ backend.runtime_deactivate()
16
+
17
+
18
+ public function runtime_release(runtime: ref[Runtime]) -> void:
19
+ backend.runtime_release(runtime)
20
+
21
+
22
+ public function runtime_poll(runtime: Runtime) -> int:
23
+ return backend.runtime_poll(runtime)
24
+
25
+
26
+ public function sleep(timeout: ptr_uint) -> Task[int]:
27
+ return backend.sleep(timeout)
28
+
29
+
30
+ public function create_runtime() -> Result[Runtime, int]:
31
+ return backend.create_runtime()
32
+
33
+
34
+ public function release_runtime(runtime: ref[Runtime]) -> int:
35
+ return backend.release_runtime(runtime)
36
+
37
+
38
+ public function sleep_on(runtime: Runtime, timeout: ptr_uint) -> Task[int]:
39
+ return backend.sleep_on(runtime, timeout)
40
+
41
+
42
+ public function work[T](run_work: fn() -> T) -> Task[T]:
43
+ return backend.work[T](run_work)
44
+
45
+
46
+ public function current_runtime() -> Runtime:
47
+ return backend.current_runtime_handle()
48
+
49
+
50
+ public function work_on[T](runtime: Runtime, run_work: fn() -> T) -> Task[T]:
51
+ return backend.work_on[T](runtime, run_work)
52
+
53
+
54
+ public function pump(runtime: Runtime) -> void:
55
+ backend.pump(runtime)
56
+
57
+
58
+ public function completed[T](task: Task[T]) -> bool:
59
+ return backend.completed[T](task)
60
+
61
+
62
+ public function result[T](task: Task[T]) -> T:
63
+ return backend.result[T](task)
64
+
65
+
66
+ public function wait_on[T](runtime: Runtime, task: Task[T]) -> T:
67
+ return backend.wait_on[T](runtime, task)
68
+
69
+
70
+ public function run_on(runtime: Runtime, task: Task[void]) -> void:
71
+ backend.run_on(runtime, task)
72
+
73
+
74
+ public function wait[T](root: proc() -> Task[T]) -> T:
75
+ return backend.wait[T](root)
76
+
77
+
78
+ public function run(root: proc() -> Task[void]) -> void:
79
+ backend.run(root)
80
+
81
+
82
+ public function with_runtime[T](body: proc(runtime: Runtime) -> T) -> T:
83
+ return backend.with_runtime[T](body)
84
+
85
+
86
+ public function run_with_runtime(body: proc(runtime: Runtime) -> void) -> void:
87
+ backend.run_with_runtime(body)
data/std/async.mt ADDED
@@ -0,0 +1,87 @@
1
+ import std.async.runtime as backend
2
+
3
+ public type Runtime = backend.Runtime
4
+
5
+
6
+ function runtime_create() -> Runtime:
7
+ return backend.runtime_create()
8
+
9
+
10
+ function runtime_activate(runtime: Runtime) -> void:
11
+ backend.runtime_activate(runtime)
12
+
13
+
14
+ function runtime_deactivate() -> void:
15
+ backend.runtime_deactivate()
16
+
17
+
18
+ function runtime_release(runtime: ref[Runtime]) -> void:
19
+ backend.runtime_release(runtime)
20
+
21
+
22
+ function runtime_poll(runtime: Runtime) -> int:
23
+ return backend.runtime_poll(runtime)
24
+
25
+
26
+ public function sleep(timeout: ptr_uint) -> Task[int]:
27
+ return backend.sleep(timeout)
28
+
29
+
30
+ public function create_runtime() -> Result[Runtime, int]:
31
+ return backend.create_runtime()
32
+
33
+
34
+ public function release_runtime(runtime: ref[Runtime]) -> int:
35
+ return backend.release_runtime(runtime)
36
+
37
+
38
+ public function sleep_on(runtime: Runtime, timeout: ptr_uint) -> Task[int]:
39
+ return backend.sleep_on(runtime, timeout)
40
+
41
+
42
+ public function work[T](run_work: fn() -> T) -> Task[T]:
43
+ return backend.work[T](run_work)
44
+
45
+
46
+ public function current_runtime() -> Runtime:
47
+ return backend.current_runtime()
48
+
49
+
50
+ public function work_on[T](runtime: Runtime, run_work: fn() -> T) -> Task[T]:
51
+ return backend.work_on[T](runtime, run_work)
52
+
53
+
54
+ public function pump(runtime: Runtime) -> void:
55
+ backend.pump(runtime)
56
+
57
+
58
+ public function completed[T](task: Task[T]) -> bool:
59
+ return backend.completed[T](task)
60
+
61
+
62
+ public function result[T](task: Task[T]) -> T:
63
+ return backend.result[T](task)
64
+
65
+
66
+ public function wait_on[T](runtime: Runtime, task: Task[T]) -> T:
67
+ return backend.wait_on[T](runtime, task)
68
+
69
+
70
+ public function run_on(runtime: Runtime, task: Task[void]) -> void:
71
+ backend.run_on(runtime, task)
72
+
73
+
74
+ public function wait[T](root: proc() -> Task[T]) -> T:
75
+ return backend.wait[T](root)
76
+
77
+
78
+ public function run(root: proc() -> Task[void]) -> void:
79
+ backend.run(root)
80
+
81
+
82
+ public function with_runtime[T](body: proc(runtime: Runtime) -> T) -> T:
83
+ return backend.with_runtime[T](body)
84
+
85
+
86
+ public function run_with_runtime(body: proc(runtime: Runtime) -> void) -> void:
87
+ backend.run_with_runtime(body)
data/std/base64.mt ADDED
@@ -0,0 +1,185 @@
1
+ import std.bytes as bytes
2
+ import std.mem.heap as heap
3
+ import std.str as text
4
+ import std.string as string
5
+
6
+ const BASE64_ALPHABET: str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
7
+ const BASE64_URL_ALPHABET: str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
8
+ const BASE64_PAD: ubyte = 61
9
+
10
+
11
+ function lookup(value: ubyte) -> Option[ubyte]:
12
+ if value >= 65 and value <= 90:
13
+ return Option[ubyte].some(value = value - 65)
14
+
15
+ if value >= 97 and value <= 122:
16
+ return Option[ubyte].some(value = value - 71)
17
+
18
+ if value >= 48 and value <= 57:
19
+ return Option[ubyte].some(value = value + 4)
20
+
21
+ if value == 43 or value == 45:
22
+ return Option[ubyte].some(value = 62)
23
+
24
+ if value == 47 or value == 95:
25
+ return Option[ubyte].some(value = 63)
26
+
27
+ return Option[ubyte].none
28
+
29
+
30
+ function encoded_len(input_len: ptr_uint) -> ptr_uint:
31
+ var padded_len = input_len
32
+ let remainder = padded_len % 3
33
+ if remainder != 0:
34
+ padded_len += 3 - remainder
35
+
36
+ return (padded_len / 3) * 4
37
+
38
+
39
+ function encode_impl(input: span[ubyte], alphabet: str, use_padding: bool) -> string.String:
40
+ if input.len == 0:
41
+ return string.String.create()
42
+
43
+ let output_len = encoded_len(input.len)
44
+ var output = string.String.with_capacity(output_len)
45
+
46
+ var index: ptr_uint = 0
47
+ while index < input.len:
48
+ var triple: array[ubyte, 3]
49
+ var group_len: ubyte = 0
50
+
51
+ triple[0] = unsafe: read(input.data + index)
52
+ group_len += 1
53
+ index += 1
54
+
55
+ if index < input.len:
56
+ triple[1] = unsafe: read(input.data + index)
57
+ group_len += 1
58
+ index += 1
59
+ else:
60
+ triple[1] = 0
61
+
62
+ if index < input.len:
63
+ triple[2] = unsafe: read(input.data + index)
64
+ group_len += 1
65
+ index += 1
66
+ else:
67
+ triple[2] = 0
68
+
69
+ let combined = (ulong<-triple[0] << 16) | (ulong<-triple[1] << 8) | ulong<-triple[2]
70
+
71
+ let char0 = alphabet.byte_at(ptr_uint<-( (combined >> 18) & 0x3F) )
72
+ let char1 = alphabet.byte_at(ptr_uint<-( (combined >> 12) & 0x3F) )
73
+ output.push_byte(char0)
74
+ output.push_byte(char1)
75
+
76
+ if group_len >= 2:
77
+ let char2 = alphabet.byte_at(ptr_uint<-( (combined >> 6) & 0x3F) )
78
+ output.push_byte(char2)
79
+ else if use_padding:
80
+ output.push_byte(BASE64_PAD)
81
+
82
+ if group_len >= 3:
83
+ let char3 = alphabet.byte_at(ptr_uint<-(combined & 0x3F))
84
+ output.push_byte(char3)
85
+ else if use_padding:
86
+ output.push_byte(BASE64_PAD)
87
+
88
+ return output
89
+
90
+
91
+ public function encode(input: span[ubyte]) -> string.String:
92
+ return encode_impl(input, BASE64_ALPHABET, true)
93
+
94
+
95
+ public function encode_urlsafe(input: span[ubyte]) -> string.String:
96
+ return encode_impl(input, BASE64_URL_ALPHABET, false)
97
+
98
+ public struct Error:
99
+ message: string.String
100
+
101
+
102
+ function error_message(message: str) -> Error:
103
+ return Error(message = string.String.from_str(message))
104
+
105
+
106
+ public function decode(text_value: str) -> Result[bytes.Bytes, Error]:
107
+ if text_value.len == 0:
108
+ return Result[bytes.Bytes, Error].success(value = bytes.Bytes.empty())
109
+
110
+ var effective_len = text_value.len
111
+ while effective_len > 0 and text_value.byte_at(effective_len - 1) == BASE64_PAD:
112
+ effective_len -= 1
113
+
114
+ if effective_len == 0:
115
+ return Result[bytes.Bytes, Error].success(value = bytes.Bytes.empty())
116
+
117
+ let remainder = effective_len % 4
118
+ if remainder == 1:
119
+ return Result[bytes.Bytes, Error].failure(error = error_message("base64: invalid input length"))
120
+
121
+ var output_len = (effective_len / 4) * 3
122
+ if remainder != 0:
123
+ output_len = output_len + remainder - 1
124
+
125
+ let output = heap.must_alloc[ubyte](output_len)
126
+ var out_index: ptr_uint = 0
127
+ var index: ptr_uint = 0
128
+
129
+ while index < effective_len:
130
+ let c0 = text_value.byte_at(index)
131
+ index += 1
132
+ let raw0_opt = lookup(c0) else:
133
+ heap.release(output)
134
+ return Result[bytes.Bytes, Error].failure(error = error_message("base64: invalid character"))
135
+ let raw0 = raw0_opt
136
+
137
+ var raw1: ubyte = 0
138
+ if index < effective_len:
139
+ let c1 = text_value.byte_at(index)
140
+ index += 1
141
+ let raw1_opt = lookup(c1) else:
142
+ heap.release(output)
143
+ return Result[bytes.Bytes, Error].failure(error = error_message("base64: invalid character"))
144
+ raw1 = raw1_opt
145
+
146
+ var raw2: ubyte = 0
147
+ if index < effective_len:
148
+ let c2 = text_value.byte_at(index)
149
+ index += 1
150
+ let raw2_opt = lookup(c2) else:
151
+ heap.release(output)
152
+ return Result[bytes.Bytes, Error].failure(error = error_message("base64: invalid character"))
153
+ raw2 = raw2_opt
154
+
155
+ var raw3: ubyte = 0
156
+ if index < effective_len:
157
+ let c3 = text_value.byte_at(index)
158
+ index += 1
159
+ let raw3_opt = lookup(c3) else:
160
+ heap.release(output)
161
+ return Result[bytes.Bytes, Error].failure(error = error_message("base64: invalid character"))
162
+ raw3 = raw3_opt
163
+
164
+ let combined = (ulong<-raw0 << 18) | (ulong<-raw1 << 12) | (ulong<-raw2 << 6) | ulong<-raw3
165
+
166
+ unsafe:
167
+ read(output + out_index) = ubyte<-( (combined >> 16) & 0xFF)
168
+ out_index += 1
169
+
170
+ if out_index < output_len:
171
+ unsafe:
172
+ read(output + out_index) = ubyte<-( (combined >> 8) & 0xFF)
173
+ out_index += 1
174
+
175
+ if out_index < output_len:
176
+ unsafe:
177
+ read(output + out_index) = ubyte<-(combined & 0xFF)
178
+ out_index += 1
179
+
180
+ return Result[bytes.Bytes, Error].success(value = bytes.Bytes(data = output, len = output_len))
181
+
182
+
183
+ extending Error:
184
+ public editable function release() -> void:
185
+ this.message.release()