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/tls.mt ADDED
@@ -0,0 +1,616 @@
1
+ import std.async as aio
2
+ import std.async.libuv_runtime as aio_backend
3
+ import std.bytes as bytes
4
+ import std.c.tls as c
5
+ import std.fmt as fmt
6
+ import std.libuv as libuv
7
+ import std.mem.arena as arena
8
+ import std.mem.heap as heap
9
+ import std.net as net
10
+ import std.str as text
11
+ import std.string as string
12
+ import std.vec as vec
13
+
14
+ type NativeHandle = libuv.uv_handle_t
15
+ type NativePollHandle = libuv.uv_poll_t
16
+
17
+ const tls_io_ready: int = 0
18
+ const tls_io_want_read: int = 1
19
+ const tls_io_want_write: int = 2
20
+ const tls_io_eof: int = 3
21
+
22
+ public struct Error:
23
+ code: int
24
+ message: string.String
25
+
26
+ public struct Stream:
27
+ state: ptr[StreamState]?
28
+
29
+ struct StreamState:
30
+ client: ptr[c.mt_tls_client]?
31
+ tcp: net.TcpStream
32
+ fd: int
33
+ pending_operation: bool
34
+
35
+ struct PollState:
36
+ ready: bool
37
+ status_code: int
38
+ revents: int
39
+ error: Error
40
+ error_owned: bool
41
+ waiter_frame: ptr[void]?
42
+ waiter: fn(frame: ptr[void]) -> void
43
+ waiter_registered: bool
44
+ handle: ptr[NativePollHandle]?
45
+ closing: bool
46
+ closed: bool
47
+ released: bool
48
+
49
+
50
+ function take_owned_string(data: ptr[char]?, len: ptr_uint) -> string.String:
51
+ if data == null:
52
+ if len != 0:
53
+ fatal(c"tls.take_owned_string missing storage")
54
+
55
+ return string.String.create()
56
+
57
+ return unsafe: string.String(data = ptr[ubyte]<-data, len = len, capacity = len, owns_storage = true)
58
+
59
+
60
+ function take_owned_bytes(data: ptr[ubyte]?, len: ptr_uint) -> bytes.Bytes:
61
+ if data == null:
62
+ if len != 0:
63
+ fatal(c"tls.take_owned_bytes missing storage")
64
+
65
+ return bytes.Bytes.empty()
66
+
67
+ return unsafe: bytes.Bytes(data = own[ubyte]<-data, len = len)
68
+
69
+
70
+ function take_error(raw: c.mt_tls_error, fallback: str) -> Error:
71
+ if raw.message_data == null and raw.message_len == 0:
72
+ return Error(code = raw.code, message = string.String.from_str(fallback))
73
+
74
+ return Error(code = raw.code, message = take_owned_string(raw.message_data, raw.message_len))
75
+
76
+
77
+ function take_net_error(raw: net.Error) -> Error:
78
+ return Error(code = raw.code, message = raw.message)
79
+
80
+
81
+ function empty_error() -> Error:
82
+ return Error(code = 0, message = string.String.create())
83
+
84
+
85
+ function tls_error(message: str) -> Error:
86
+ return Error(code = -1, message = string.String.from_str(message))
87
+
88
+
89
+ function libuv_error(code: int) -> Error:
90
+ return Error(code = code, message = string.String.from_str(text.cstr_as_str(libuv.strerror(code))))
91
+
92
+
93
+ function release_socket_addresses(values: ref[vec.Vec[net.SocketAddress]]) -> void:
94
+ var index: ptr_uint = 0
95
+ while index < values.len:
96
+ let current = values.get(index) else:
97
+ fatal(c"tls release_socket_addresses missing value")
98
+
99
+ var address = unsafe: read(current)
100
+ address.release()
101
+ index += 1
102
+
103
+ values.release()
104
+
105
+
106
+ function poll_state(frame: ptr[void]) -> ptr[PollState]:
107
+ return unsafe: ptr[PollState]<-frame
108
+
109
+
110
+ function poll_as_handle(handle: ptr[NativePollHandle]) -> ptr[NativeHandle]:
111
+ return unsafe: ptr[NativeHandle]<-handle
112
+
113
+
114
+ function handle_as_poll(handle: ptr[NativeHandle]) -> ptr[NativePollHandle]:
115
+ return unsafe: ptr[NativePollHandle]<-handle
116
+
117
+
118
+ function noop_waiter(frame: ptr[void]) -> void:
119
+ unsafe: frame
120
+
121
+
122
+ function poll_task(state: ptr[PollState]) -> Task[Result[int, Error]]:
123
+ return unsafe: Task[Result[int, Error]](
124
+ frame = ptr[void]<-state,
125
+ ready = poll_ready,
126
+ set_waiter = poll_set_waiter,
127
+ release = poll_release,
128
+ take_result = poll_take_result
129
+ )
130
+
131
+
132
+ function release_poll_error(state: ptr[PollState]) -> void:
133
+ unsafe:
134
+ if state.error_owned:
135
+ state.error.release()
136
+ state.error = empty_error()
137
+ state.error_owned = false
138
+
139
+
140
+ function poll_close_callback(handle: ptr[NativeHandle]) -> void:
141
+ let state_raw = libuv.handle_get_data(handle) else:
142
+ unsafe: heap.release_bytes(ptr[void]<-handle_as_poll(handle))
143
+ return
144
+
145
+ let state = unsafe: ptr[PollState]<-state_raw
146
+ unsafe:
147
+ heap.release_bytes(ptr[void]<-handle_as_poll(handle))
148
+ state.handle = null
149
+ state.closed = true
150
+
151
+ if state.released:
152
+ release_poll_error(state)
153
+ heap.release(state)
154
+
155
+
156
+ function close_poll_handle(state: ptr[PollState]) -> void:
157
+ unsafe:
158
+ let poll = state.handle else:
159
+ state.closed = true
160
+ return
161
+
162
+ if state.closing or state.closed:
163
+ return
164
+
165
+ state.closing = true
166
+ libuv.poll_stop(poll)
167
+ libuv.close(poll_as_handle(poll), poll_close_callback)
168
+
169
+
170
+ function finish_poll_success(state: ptr[PollState], revents: int) -> void:
171
+ unsafe:
172
+ release_poll_error(state)
173
+ state.ready = true
174
+ state.status_code = 0
175
+ state.revents = revents
176
+ close_poll_handle(state)
177
+
178
+ if state.waiter_registered:
179
+ state.waiter(ptr[void]<-state.waiter_frame)
180
+
181
+
182
+ function finish_poll_failure(state: ptr[PollState], error: Error, status_code: int) -> void:
183
+ unsafe:
184
+ release_poll_error(state)
185
+ state.ready = true
186
+ state.status_code = status_code
187
+ state.revents = 0
188
+ state.error = error
189
+ state.error_owned = true
190
+ close_poll_handle(state)
191
+
192
+ if state.waiter_registered:
193
+ state.waiter(ptr[void]<-state.waiter_frame)
194
+
195
+
196
+ function poll_ready(frame: ptr[void]) -> bool:
197
+ return unsafe: poll_state(frame).ready
198
+
199
+
200
+ function poll_set_waiter(frame: ptr[void], waiter_frame: ptr[void], waiter: fn(frame: ptr[void]) -> void) -> void:
201
+ let state = poll_state(frame)
202
+ unsafe:
203
+ if state.ready:
204
+ waiter(waiter_frame)
205
+ return
206
+
207
+ state.waiter_frame = waiter_frame
208
+ state.waiter = waiter
209
+ state.waiter_registered = true
210
+
211
+
212
+ function poll_release(frame: ptr[void]) -> void:
213
+ let state = poll_state(frame)
214
+
215
+ unsafe:
216
+ if state.closed:
217
+ release_poll_error(state)
218
+ heap.release(state)
219
+ return
220
+
221
+ state.released = true
222
+ if state.handle == null:
223
+ release_poll_error(state)
224
+ heap.release(state)
225
+ return
226
+
227
+ close_poll_handle(state)
228
+
229
+
230
+ function poll_take_result(frame: ptr[void]) -> Result[int, Error]:
231
+ let state = poll_state(frame)
232
+ unsafe:
233
+ if state.status_code == 0:
234
+ return Result[int, Error].success(value = state.revents)
235
+
236
+ let error = state.error
237
+ state.error = empty_error()
238
+ state.error_owned = false
239
+ return Result[int, Error].failure(error = error)
240
+
241
+
242
+ function poll_callback(handle: ptr[NativePollHandle], status_code: int, events: int) -> void:
243
+ let state_raw = libuv.handle_get_data(poll_as_handle(handle)) else:
244
+ return
245
+
246
+ let state = unsafe: ptr[PollState]<-state_raw
247
+ if status_code != 0:
248
+ finish_poll_failure(state, libuv_error(status_code), status_code)
249
+ return
250
+
251
+ finish_poll_success(state, events)
252
+
253
+
254
+ function alloc_poll_handle() -> ptr[NativePollHandle]:
255
+ let handle_size = libuv.handle_size(libuv.uv_handle_type.UV_POLL)
256
+ return unsafe: ptr[NativePollHandle]<-heap.must_alloc_zeroed_bytes(1, handle_size)
257
+
258
+
259
+ function poll_events_for_status(status_code: int) -> int:
260
+ if status_code == tls_io_want_read:
261
+ return int<-(libuv.uv_poll_event.UV_READABLE | libuv.uv_poll_event.UV_DISCONNECT)
262
+
263
+ if status_code == tls_io_want_write:
264
+ return int<-libuv.uv_poll_event.UV_WRITABLE
265
+
266
+ fatal(c"tls.poll_events_for_status requires WANT_READ or WANT_WRITE")
267
+
268
+
269
+ function poll_on(runtime: aio.Runtime, fd: int, events: int) -> Task[Result[int, Error]]:
270
+ let loop = aio_backend.runtime_loop(runtime)
271
+ let state = heap.must_alloc_zeroed[PollState](1)
272
+ let poll = alloc_poll_handle()
273
+
274
+ unsafe:
275
+ state.ready = false
276
+ state.status_code = 0
277
+ state.revents = 0
278
+ state.error = empty_error()
279
+ state.error_owned = false
280
+ state.waiter_frame = null
281
+ state.waiter = noop_waiter
282
+ state.waiter_registered = false
283
+ state.handle = poll
284
+ state.closing = false
285
+ state.closed = false
286
+ state.released = false
287
+
288
+ let init_status = libuv.poll_init(loop, poll, fd)
289
+ if init_status != 0:
290
+ unsafe:
291
+ heap.release_bytes(ptr[void]<-poll)
292
+ state.handle = null
293
+ state.closed = true
294
+ finish_poll_failure(state, libuv_error(init_status), init_status)
295
+ return poll_task(state)
296
+
297
+ unsafe:
298
+ libuv.handle_set_data(poll_as_handle(poll), ptr[void]<-state)
299
+
300
+ let start_status = libuv.poll_start(poll, events, poll_callback)
301
+ if start_status != 0:
302
+ finish_poll_failure(state, libuv_error(start_status), start_status)
303
+
304
+ return poll_task(state)
305
+
306
+
307
+ async function wait_for_io(runtime: aio.Runtime, fd: int, status_code: int) -> Result[bool, Error]:
308
+ let poll_result = await poll_on(runtime, fd, poll_events_for_status(status_code))
309
+ poll_result?
310
+ return Result[bool, Error].success(value = true)
311
+
312
+
313
+ function begin_stream_operation(state_raw: ptr[StreamState]?) -> Result[ptr[StreamState], Error]:
314
+ let state = state_raw else:
315
+ return Result[ptr[StreamState], Error].failure(error = tls_error("tls stream is released"))
316
+
317
+ unsafe:
318
+ if state.client == null:
319
+ return Result[ptr[StreamState], Error].failure(error = tls_error("tls stream is released"))
320
+
321
+ if state.pending_operation:
322
+ return Result[
323
+ ptr[StreamState],
324
+ Error
325
+ ].failure(error = tls_error("tls stream already has a pending operation"))
326
+
327
+ state.pending_operation = true
328
+
329
+ return Result[ptr[StreamState], Error].success(value = state)
330
+
331
+
332
+ function end_stream_operation(state: ptr[StreamState]) -> void:
333
+ unsafe: state.pending_operation = false
334
+
335
+
336
+ async function handshake_on(runtime: aio.Runtime, state_raw: ptr[StreamState]?) -> Result[bool, Error]:
337
+ let state = begin_stream_operation(state_raw)?
338
+ defer end_stream_operation(state)
339
+
340
+ while true:
341
+ let client = unsafe: read(state).client else:
342
+ return Result[bool, Error].failure(error = tls_error("tls stream is released"))
343
+
344
+ var raw_error = zero[c.mt_tls_error]
345
+ let status_code = c.mt_tls_client_handshake(client, raw_error)
346
+ if status_code == tls_io_ready:
347
+ return Result[bool, Error].success(value = true)
348
+
349
+ if status_code == tls_io_want_read or status_code == tls_io_want_write:
350
+ let wait_result = await wait_for_io(runtime, unsafe: read(state).fd, status_code)
351
+ wait_result?
352
+ continue
353
+
354
+ if status_code == tls_io_eof:
355
+ return Result[bool, Error].failure(error = tls_error("tls stream closed during handshake"))
356
+
357
+ return Result[bool, Error].failure(error = take_error(raw_error, "tls connect failed"))
358
+
359
+
360
+ async function write_on(
361
+ runtime: aio.Runtime,
362
+ state_raw: ptr[StreamState]?,
363
+ content: span[ubyte]
364
+ ) -> Result[ptr_uint, Error]:
365
+ if content.len == 0:
366
+ return Result[ptr_uint, Error].success(value = 0)
367
+
368
+ let state = begin_stream_operation(state_raw)?
369
+ defer end_stream_operation(state)
370
+
371
+ var offset: ptr_uint = 0
372
+ while offset < content.len:
373
+ let client = unsafe: read(state).client else:
374
+ return Result[ptr_uint, Error].failure(error = tls_error("tls stream is released"))
375
+
376
+ var transferred: ptr_uint = 0
377
+ var raw_error = zero[c.mt_tls_error]
378
+ let status_code = c.mt_tls_client_write(
379
+ client,
380
+ unsafe: content.data + offset,
381
+ content.len - offset,
382
+ transferred,
383
+ raw_error
384
+ )
385
+ if status_code == tls_io_ready:
386
+ if transferred == 0:
387
+ return Result[ptr_uint, Error].failure(error = tls_error("tls write made no progress"))
388
+
389
+ offset += transferred
390
+ continue
391
+
392
+ if status_code == tls_io_want_read or status_code == tls_io_want_write:
393
+ let wait_result = await wait_for_io(runtime, unsafe: read(state).fd, status_code)
394
+ wait_result?
395
+ continue
396
+
397
+ if status_code == tls_io_eof:
398
+ return Result[ptr_uint, Error].failure(error = tls_error("tls stream closed during write"))
399
+
400
+ return Result[ptr_uint, Error].failure(error = take_error(raw_error, "tls write failed"))
401
+
402
+ return Result[ptr_uint, Error].success(value = offset)
403
+
404
+
405
+ async function read_once_on(
406
+ runtime: aio.Runtime,
407
+ state_raw: ptr[StreamState]?,
408
+ max_bytes: ptr_uint
409
+ ) -> Result[bytes.Bytes, Error]:
410
+ if max_bytes == 0:
411
+ return Result[bytes.Bytes, Error].failure(error = tls_error("tls read requires max_bytes > 0"))
412
+
413
+ let state = begin_stream_operation(state_raw)?
414
+ defer end_stream_operation(state)
415
+
416
+ let buffer = heap.must_alloc[ubyte](max_bytes)
417
+ while true:
418
+ let client = unsafe: read(state).client else:
419
+ unsafe: heap.release(buffer)
420
+ return Result[bytes.Bytes, Error].failure(error = tls_error("tls stream is released"))
421
+
422
+ var transferred: ptr_uint = 0
423
+ var raw_error = zero[c.mt_tls_error]
424
+ let status_code = c.mt_tls_client_read(client, buffer, max_bytes, transferred, raw_error)
425
+ if status_code == tls_io_ready:
426
+ if transferred == 0:
427
+ heap.release(buffer)
428
+ return Result[bytes.Bytes, Error].success(value = bytes.Bytes.empty())
429
+
430
+ return Result[bytes.Bytes, Error].success(value = bytes.Bytes(data = buffer, len = transferred))
431
+
432
+ if status_code == tls_io_eof:
433
+ heap.release(buffer)
434
+ return Result[bytes.Bytes, Error].success(value = bytes.Bytes.empty())
435
+
436
+ if status_code == tls_io_want_read or status_code == tls_io_want_write:
437
+ let wait_result = await wait_for_io(runtime, unsafe: read(state).fd, status_code)
438
+ match wait_result:
439
+ Result.failure as wait_error_payload:
440
+ heap.release(buffer)
441
+ return Result[bytes.Bytes, Error].failure(error = wait_error_payload.error)
442
+ Result.success as wait_payload:
443
+ wait_payload.value
444
+ continue
445
+
446
+ heap.release(buffer)
447
+ return Result[bytes.Bytes, Error].failure(error = take_error(raw_error, "tls read failed"))
448
+
449
+
450
+ async function shutdown_on(runtime: aio.Runtime, state_raw: ptr[StreamState]?) -> Result[bool, Error]:
451
+ let state = begin_stream_operation(state_raw)?
452
+ defer end_stream_operation(state)
453
+
454
+ while true:
455
+ let client = unsafe: read(state).client else:
456
+ return Result[bool, Error].failure(error = tls_error("tls stream is released"))
457
+
458
+ var raw_error = zero[c.mt_tls_error]
459
+ let status_code = c.mt_tls_client_shutdown(client, raw_error)
460
+ if status_code == tls_io_ready:
461
+ return Result[bool, Error].success(value = true)
462
+
463
+ if status_code == tls_io_want_read or status_code == tls_io_want_write:
464
+ let wait_result = await wait_for_io(runtime, unsafe: read(state).fd, status_code)
465
+ wait_result?
466
+ continue
467
+
468
+ return Result[bool, Error].failure(error = take_error(raw_error, "tls shutdown failed"))
469
+
470
+
471
+ public async function connect_on(runtime: aio.Runtime, host: str, port: int) -> Result[Stream, Error]:
472
+ var service = fmt.to_string_int(port)
473
+ defer service.release()
474
+
475
+ let addresses_result = await net.resolve_all_on(runtime, host, service.as_str())
476
+ match addresses_result:
477
+ Result.failure as payload:
478
+ return Result[Stream, Error].failure(error = take_net_error(payload.error))
479
+ Result.success as payload:
480
+ var addresses = payload.value
481
+ defer release_socket_addresses(ref_of(addresses))
482
+
483
+ var last_error = tls_error("tls connect failed")
484
+ var last_error_owned = true
485
+ defer:
486
+ if last_error_owned:
487
+ last_error.release()
488
+
489
+ var index: ptr_uint = 0
490
+ while index < addresses.len:
491
+ let current = addresses.get(index) else:
492
+ fatal(c"tls.connect_on missing resolved address")
493
+
494
+ let connect_result = await net.connect_on(runtime, unsafe: read(current))
495
+ match connect_result:
496
+ Result.failure as connect_error_payload:
497
+ if last_error_owned:
498
+ last_error.release()
499
+ last_error = take_net_error(connect_error_payload.error)
500
+ last_error_owned = true
501
+ Result.success as connect_payload:
502
+ if last_error_owned:
503
+ last_error.release()
504
+ return await client_on(runtime, host, connect_payload.value)
505
+
506
+ index += 1
507
+
508
+ return Result[Stream, Error].failure(error = last_error)
509
+
510
+
511
+ public function connect(host: str, port: int) -> Task[Result[Stream, Error]]:
512
+ return connect_on(aio.current_runtime(), host, port)
513
+
514
+
515
+ public async function client_on(runtime: aio.Runtime, host: str, transport: net.TcpStream) -> Result[Stream, Error]:
516
+ var owned_transport = transport
517
+
518
+ let fd_result = owned_transport.socket_fd()
519
+ match fd_result:
520
+ Result.failure as payload:
521
+ owned_transport.release()
522
+ return Result[Stream, Error].failure(error = take_net_error(payload.error))
523
+ Result.success as payload:
524
+ var raw_client: ptr[c.mt_tls_client]? = null
525
+ var host_storage = arena.create(host.len + 1)
526
+ defer host_storage.release()
527
+
528
+ var raw_error = zero[c.mt_tls_error]
529
+ let create_status = c.mt_tls_client_create(host_storage.to_cstr(host), payload.value, raw_client, raw_error)
530
+ if create_status != 0:
531
+ owned_transport.release()
532
+ return Result[Stream, Error].failure(error = take_error(raw_error, "tls connect failed"))
533
+
534
+ let live_client = raw_client else:
535
+ owned_transport.release()
536
+ return Result[Stream, Error].failure(error = tls_error("tls connect failed"))
537
+
538
+ let state = heap.must_alloc_zeroed[StreamState](1)
539
+ unsafe:
540
+ state.client = live_client
541
+ state.tcp = owned_transport
542
+ state.fd = payload.value
543
+ state.pending_operation = false
544
+
545
+ var stream = Stream(state = state)
546
+ let handshake_result = await handshake_on(runtime, state)
547
+ match handshake_result:
548
+ Result.failure as handshake_payload:
549
+ stream.release()
550
+ return Result[Stream, Error].failure(error = handshake_payload.error)
551
+ Result.success as handshake_payload:
552
+ handshake_payload.value
553
+ return Result[Stream, Error].success(value = stream)
554
+
555
+
556
+ public function client(host: str, transport: net.TcpStream) -> Task[Result[Stream, Error]]:
557
+ return client_on(aio.current_runtime(), host, transport)
558
+
559
+
560
+ extending Error:
561
+ public editable function release() -> void:
562
+ this.message.release()
563
+
564
+
565
+ extending Stream:
566
+ public editable function release() -> void:
567
+ let state = this.state else:
568
+ return
569
+
570
+ unsafe:
571
+ if state.pending_operation:
572
+ fatal(c"tls stream released with a pending operation")
573
+
574
+ let client = state.client
575
+ if client != null[ptr[c.mt_tls_client]]:
576
+ c.mt_tls_client_release(client)
577
+ state.client = null
578
+
579
+ var transport = state.tcp
580
+ transport.release()
581
+ state.tcp = zero[net.TcpStream]
582
+
583
+ heap.release(state)
584
+ this.state = null
585
+
586
+
587
+ public function write_bytes(content: span[ubyte]) -> Task[Result[ptr_uint, Error]]:
588
+ return write_on(aio.current_runtime(), this.state, content)
589
+
590
+
591
+ public function read_once(max_bytes: ptr_uint) -> Task[Result[bytes.Bytes, Error]]:
592
+ return read_once_on(aio.current_runtime(), this.state, max_bytes)
593
+
594
+
595
+ public function shutdown() -> Task[Result[bool, Error]]:
596
+ return shutdown_on(aio.current_runtime(), this.state)
597
+
598
+
599
+ public function exchange(host: str, port: int, request: span[ubyte]) -> Result[bytes.Bytes, Error]:
600
+ var host_storage = arena.create(host.len + 1)
601
+ defer host_storage.release()
602
+
603
+ var raw_response = zero[c.mt_tls_bytes]
604
+ var raw_error = zero[c.mt_tls_error]
605
+ let status_code = c.mt_tls_exchange(
606
+ host_storage.to_cstr(host),
607
+ port,
608
+ request.data,
609
+ request.len,
610
+ raw_response,
611
+ raw_error
612
+ )
613
+ if status_code != 0:
614
+ return Result[bytes.Bytes, Error].failure(error = take_error(raw_error, "tls exchange failed"))
615
+
616
+ return Result[bytes.Bytes, Error].success(value = take_owned_bytes(raw_response.data, raw_response.len))