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.
- checksums.yaml +4 -4
- data/docs/index.html +4 -3
- data/lib/milk_tea/base.rb +1 -1
- data/std/asset_pack.mt +267 -0
- data/std/async/libuv_runtime.mt +539 -0
- data/std/async/mailbox.mt +191 -0
- data/std/async/runtime.mt +87 -0
- data/std/async.mt +87 -0
- data/std/base64.mt +185 -0
- data/std/behavior_tree.mt +396 -0
- data/std/binary.mt +314 -0
- data/std/binary_heap.mt +157 -0
- data/std/bitset.mt +239 -0
- data/std/box2d.mt +535 -0
- data/std/bytes.mt +46 -0
- data/std/c/box2d.mt +1254 -0
- data/std/c/cgltf.mt +647 -0
- data/std/c/cjson.mt +106 -0
- data/std/c/crypto.mt +11 -0
- data/std/c/crypto_support.h +51 -0
- data/std/c/ctype.mt +19 -0
- data/std/c/ctype_bindgen.h +29 -0
- data/std/c/curl.mt +1223 -0
- data/std/c/enet.mt +473 -0
- data/std/c/errno.mt +41 -0
- data/std/c/errno_bindgen.h +53 -0
- data/std/c/flecs.mt +2945 -0
- data/std/c/fs.linux.mt +43 -0
- data/std/c/fs.windows.mt +43 -0
- data/std/c/fs_support.h +954 -0
- data/std/c/gl.mt +2065 -0
- data/std/c/gl_registry_helpers.h +10748 -0
- data/std/c/glfw.mt +499 -0
- data/std/c/libc.mt +167 -0
- data/std/c/libuv.mt +1491 -0
- data/std/c/math.mt +22 -0
- data/std/c/math_bindgen.h +31 -0
- data/std/c/miniaudio.mt +3420 -0
- data/std/c/pcre2.mt +735 -0
- data/std/c/process.mt +58 -0
- data/std/c/process_support.h +1147 -0
- data/std/c/raygui.mt +1602 -0
- data/std/c/raylib.mt +1245 -0
- data/std/c/raymath.mt +163 -0
- data/std/c/rlgl.mt +434 -0
- data/std/c/rpng.mt +60 -0
- data/std/c/rres.mt +187 -0
- data/std/c/sdl3.mt +4132 -0
- data/std/c/sqlite3.mt +951 -0
- data/std/c/stb_image.mt +52 -0
- data/std/c/stb_image_resize2.mt +128 -0
- data/std/c/stb_image_write.mt +19 -0
- data/std/c/stb_rect_pack.mt +38 -0
- data/std/c/stb_truetype.mt +175 -0
- data/std/c/stb_vorbis.mt +31 -0
- data/std/c/stdio.mt +90 -0
- data/std/c/steamworks.h +5769 -0
- data/std/c/steamworks.mt +4771 -0
- data/std/c/string.mt +16 -0
- data/std/c/string_bindgen.h +36 -0
- data/std/c/sync.mt +33 -0
- data/std/c/sync_support.h +219 -0
- data/std/c/terminal.mt +24 -0
- data/std/c/terminal_support.h +408 -0
- data/std/c/time.mt +26 -0
- data/std/c/tls.mt +24 -0
- data/std/c/tls_support.h +626 -0
- data/std/c/tracy.mt +53 -0
- data/std/c/zlib.mt +20 -0
- data/std/c/zlib_support.h +239 -0
- data/std/c/zstd.mt +231 -0
- data/std/cell.mt +60 -0
- data/std/cgltf.mt +115 -0
- data/std/cjson.mt +90 -0
- data/std/cli.mt +768 -0
- data/std/cookie.mt +198 -0
- data/std/counter.mt +160 -0
- data/std/crypto.mt +74 -0
- data/std/cstring.mt +13 -0
- data/std/ctype.mt +52 -0
- data/std/curl/runtime.mt +261 -0
- data/std/curl.mt +38 -0
- data/std/deque.mt +348 -0
- data/std/encoding.mt +93 -0
- data/std/enet.mt +133 -0
- data/std/env.mt +41 -0
- data/std/errno.mt +47 -0
- data/std/flecs.mt +978 -0
- data/std/fmt.mt +271 -0
- data/std/fs.linux.mt +696 -0
- data/std/fs.windows.mt +711 -0
- data/std/fsm.mt +267 -0
- data/std/gl.mt +2062 -0
- data/std/glfw.mt +471 -0
- data/std/goap.mt +342 -0
- data/std/graph.mt +521 -0
- data/std/gzip.mt +77 -0
- data/std/hash.mt +429 -0
- data/std/http/server.mt +810 -0
- data/std/http.mt +1227 -0
- data/std/intern.mt +53 -0
- data/std/jobs.mt +288 -0
- data/std/json.mt +627 -0
- data/std/libc.mt +34 -0
- data/std/libuv.mt +554 -0
- data/std/linear_algebra.mt +243 -0
- data/std/linked_map.mt +372 -0
- data/std/linked_map_view.mt +49 -0
- data/std/linked_set.mt +117 -0
- data/std/log.mt +69 -0
- data/std/map.mt +418 -0
- data/std/math.mt +24 -0
- data/std/mem/arena.mt +137 -0
- data/std/mem/endian.mt +51 -0
- data/std/mem/heap.mt +298 -0
- data/std/mem/pool.mt +164 -0
- data/std/mem/stack.mt +47 -0
- data/std/mem/tracking.mt +119 -0
- data/std/miniaudio.mt +1299 -0
- data/std/multiset.mt +191 -0
- data/std/net/channel.mt +727 -0
- data/std/net/clock.mt +237 -0
- data/std/net/discovery.mt +277 -0
- data/std/net/lobby.mt +813 -0
- data/std/net/manager.mt +539 -0
- data/std/net/mux.mt +839 -0
- data/std/net/nat.mt +122 -0
- data/std/net/packet.mt +219 -0
- data/std/net/punch.mt +162 -0
- data/std/net/rpc.mt +119 -0
- data/std/net/session.mt +1157 -0
- data/std/net/stun.mt +252 -0
- data/std/net/sync.mt +183 -0
- data/std/net/turn.mt +459 -0
- data/std/net.mt +2944 -0
- data/std/oauth2.mt +408 -0
- data/std/option.mt +51 -0
- data/std/ordered_map.mt +497 -0
- data/std/ordered_set.mt +348 -0
- data/std/path.mt +368 -0
- data/std/pcre2/runtime.mt +35 -0
- data/std/pcre2.mt +78 -0
- data/std/priority_queue.mt +55 -0
- data/std/process.mt +837 -0
- data/std/queue.mt +55 -0
- data/std/random.mt +146 -0
- data/std/raygui.mt +99 -0
- data/std/raylib/debug_console.mt +71 -0
- data/std/raylib/easing.mt +388 -0
- data/std/raylib/packed_assets.mt +255 -0
- data/std/raylib/runtime.mt +30 -0
- data/std/raylib/tracy_gpu.mt +37 -0
- data/std/raylib.mt +1510 -0
- data/std/raymath.mt +153 -0
- data/std/result.mt +89 -0
- data/std/rlgl.mt +268 -0
- data/std/rpng.mt +46 -0
- data/std/rres.mt +36 -0
- data/std/sdl3/runtime.mt +54 -0
- data/std/sdl3.mt +1731 -0
- data/std/serialize.mt +68 -0
- data/std/set.mt +124 -0
- data/std/spatial.mt +176 -0
- data/std/sqlite3.mt +151 -0
- data/std/stack.mt +55 -0
- data/std/stb_image.mt +47 -0
- data/std/stb_image_resize2.mt +41 -0
- data/std/stb_image_write.mt +17 -0
- data/std/stb_rect_pack.mt +15 -0
- data/std/stb_truetype.mt +77 -0
- data/std/stb_vorbis.mt +16 -0
- data/std/stdio.mt +88 -0
- data/std/steamworks.mt +1542 -0
- data/std/str.mt +293 -0
- data/std/string.mt +234 -0
- data/std/sync.mt +194 -0
- data/std/tar.mt +704 -0
- data/std/terminal.mt +1002 -0
- data/std/testing.mt +266 -0
- data/std/thread.mt +120 -0
- data/std/time.mt +105 -0
- data/std/tls.mt +616 -0
- data/std/toml.mt +1310 -0
- data/std/tracy.mt +42 -0
- data/std/uri.mt +118 -0
- data/std/url.mt +372 -0
- data/std/vec.mt +433 -0
- data/std/zstd.mt +94 -0
- metadata +187 -2
data/std/testing.mt
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
# Standard library: testing core (T0 prototype)
|
|
2
|
+
#
|
|
3
|
+
# Minimal, in-language unit-testing surface — see docs/testing.md (§5, T0).
|
|
4
|
+
# A test function returns `Check` and propagates the first failure with `?`:
|
|
5
|
+
#
|
|
6
|
+
# import std.testing as t
|
|
7
|
+
#
|
|
8
|
+
# function test_math() -> t.Check:
|
|
9
|
+
# t.expect_equal_int(2 + 2, 4)?
|
|
10
|
+
# return t.ok()
|
|
11
|
+
#
|
|
12
|
+
# A hand-written runner (see docs/testing.md §6 for future compiler-driven
|
|
13
|
+
# discovery) calls `record` per test and `summarize` at the end:
|
|
14
|
+
#
|
|
15
|
+
# function main() -> int:
|
|
16
|
+
# var stats = t.Stats.create()
|
|
17
|
+
# stats = t.record(stats, "math", test_math())
|
|
18
|
+
# return t.summarize(stats)
|
|
19
|
+
|
|
20
|
+
import std.string as string
|
|
21
|
+
import std.fmt as fmt
|
|
22
|
+
import std.stdio as stdio
|
|
23
|
+
import std.str
|
|
24
|
+
import std.hash
|
|
25
|
+
|
|
26
|
+
# A test outcome: success carries no meaningful value; failure carries a
|
|
27
|
+
# `Failure`. `Result` is used (not a bespoke variant) so `?` propagation works.
|
|
28
|
+
|
|
29
|
+
# A failed (or skipped) expectation. `message` is owned and must be released by
|
|
30
|
+
# whoever consumes it (the runner does this in `record`). `is_skip` distinguishes
|
|
31
|
+
# a skip from a real assertion failure.
|
|
32
|
+
public struct Failure:
|
|
33
|
+
message: string.String
|
|
34
|
+
is_skip: bool
|
|
35
|
+
|
|
36
|
+
public type Check = Result[bool, Failure]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# Tally of outcomes for a run. Value type; `record` returns an updated copy.
|
|
40
|
+
public struct Stats:
|
|
41
|
+
passed: int
|
|
42
|
+
failed: int
|
|
43
|
+
skipped: int
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
extending Stats:
|
|
47
|
+
public static function create() -> Stats:
|
|
48
|
+
return Stats(passed = 0, failed = 0, skipped = 0)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# ── Outcome constructors ──────────────────────────────────────────────────
|
|
52
|
+
|
|
53
|
+
public function ok() -> Check:
|
|
54
|
+
return Result[bool, Failure].success(value = true)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
public function fail(message: str) -> Check:
|
|
58
|
+
return Result[bool, Failure].failure(error = Failure(message = string.String.from_str(message), is_skip = false))
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
public function skip(reason: str) -> Check:
|
|
62
|
+
return Result[bool, Failure].failure(error = Failure(message = string.String.from_str(reason), is_skip = true))
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
# ── Expectations ──────────────────────────────────────────────────────────
|
|
66
|
+
|
|
67
|
+
public function expect(condition: bool, message: str) -> Check:
|
|
68
|
+
if condition:
|
|
69
|
+
return ok()
|
|
70
|
+
|
|
71
|
+
return fail(message)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
public function expect_true(condition: bool) -> Check:
|
|
75
|
+
return expect(condition, "expected true")
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
public function expect_false(condition: bool) -> Check:
|
|
79
|
+
return expect(not condition, "expected false")
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
public function expect_equal_int(actual: int, expected: int) -> Check:
|
|
83
|
+
if actual == expected:
|
|
84
|
+
return ok()
|
|
85
|
+
|
|
86
|
+
var message = string.String.create()
|
|
87
|
+
message.append("expected ")
|
|
88
|
+
fmt.append_int(ref_of(message), expected)
|
|
89
|
+
message.append(", got ")
|
|
90
|
+
fmt.append_int(ref_of(message), actual)
|
|
91
|
+
return Result[bool, Failure].failure(error = Failure(message = message, is_skip = false))
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
public function expect_equal_str(actual: str, expected: str) -> Check:
|
|
95
|
+
var actual_string = string.String.from_str(actual)
|
|
96
|
+
var expected_string = string.String.from_str(expected)
|
|
97
|
+
let same = actual_string.equal(expected_string)
|
|
98
|
+
actual_string.release()
|
|
99
|
+
expected_string.release()
|
|
100
|
+
if same:
|
|
101
|
+
return ok()
|
|
102
|
+
|
|
103
|
+
var message = string.String.create()
|
|
104
|
+
message.append("expected [")
|
|
105
|
+
message.append(expected)
|
|
106
|
+
message.append("], got [")
|
|
107
|
+
message.append(actual)
|
|
108
|
+
message.append("]")
|
|
109
|
+
return Result[bool, Failure].failure(error = Failure(message = message, is_skip = false))
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
public function expect_equal_bool(actual: bool, expected: bool) -> Check:
|
|
113
|
+
if actual == expected:
|
|
114
|
+
return ok()
|
|
115
|
+
|
|
116
|
+
var message = string.String.create()
|
|
117
|
+
message.append("expected ")
|
|
118
|
+
fmt.append_bool(ref_of(message), expected)
|
|
119
|
+
message.append(", got ")
|
|
120
|
+
fmt.append_bool(ref_of(message), actual)
|
|
121
|
+
return Result[bool, Failure].failure(error = Failure(message = message, is_skip = false))
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
public function expect_not_equal_int(actual: int, expected: int) -> Check:
|
|
125
|
+
if actual != expected:
|
|
126
|
+
return ok()
|
|
127
|
+
|
|
128
|
+
var message = string.String.create()
|
|
129
|
+
message.append("expected not ")
|
|
130
|
+
fmt.append_int(ref_of(message), expected)
|
|
131
|
+
message.append(", got ")
|
|
132
|
+
fmt.append_int(ref_of(message), actual)
|
|
133
|
+
return Result[bool, Failure].failure(error = Failure(message = message, is_skip = false))
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
public function expect_not_equal_str(actual: str, expected: str) -> Check:
|
|
137
|
+
var actual_string = string.String.from_str(actual)
|
|
138
|
+
var expected_string = string.String.from_str(expected)
|
|
139
|
+
let same = actual_string.equal(expected_string)
|
|
140
|
+
actual_string.release()
|
|
141
|
+
expected_string.release()
|
|
142
|
+
if not same:
|
|
143
|
+
return ok()
|
|
144
|
+
|
|
145
|
+
var message = string.String.create()
|
|
146
|
+
message.append("expected not [")
|
|
147
|
+
message.append(expected)
|
|
148
|
+
message.append("], got [")
|
|
149
|
+
message.append(actual)
|
|
150
|
+
message.append("]")
|
|
151
|
+
return Result[bool, Failure].failure(error = Failure(message = message, is_skip = false))
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
public function expect_not_equal_bool(actual: bool, expected: bool) -> Check:
|
|
155
|
+
if actual != expected:
|
|
156
|
+
return ok()
|
|
157
|
+
|
|
158
|
+
var message = string.String.create()
|
|
159
|
+
message.append("expected not ")
|
|
160
|
+
fmt.append_bool(ref_of(message), expected)
|
|
161
|
+
message.append(", got ")
|
|
162
|
+
fmt.append_bool(ref_of(message), actual)
|
|
163
|
+
return Result[bool, Failure].failure(error = Failure(message = message, is_skip = false))
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
# Generic equality over any type with a canonical `T.equal` hook: primitives
|
|
167
|
+
# (import std.hash), `str` (import std.str), and user structs that define `equal`
|
|
168
|
+
# (or delegate to std.hash.equal_struct). On failure the actual/expected values
|
|
169
|
+
# are rendered via `std.fmt.format_value`, so `T` must be a primitive or a struct
|
|
170
|
+
# whose fields are themselves `format_value`-renderable.
|
|
171
|
+
public function expect_equal[T](actual: T, expected: T) -> Check:
|
|
172
|
+
if equal[T](actual, expected):
|
|
173
|
+
return ok()
|
|
174
|
+
|
|
175
|
+
var message = string.String.create()
|
|
176
|
+
message.append("expected ")
|
|
177
|
+
fmt.format_value[T](ref_of(message), const_ptr_of(expected))
|
|
178
|
+
message.append(", got ")
|
|
179
|
+
fmt.format_value[T](ref_of(message), const_ptr_of(actual))
|
|
180
|
+
return Result[bool, Failure].failure(error = Failure(message = message, is_skip = false))
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
public function expect_some[T](option: Option[T]) -> Check:
|
|
184
|
+
if option.is_some():
|
|
185
|
+
return ok()
|
|
186
|
+
|
|
187
|
+
return fail("expected Option.some, got Option.none")
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
public function expect_none[T](option: Option[T]) -> Check:
|
|
191
|
+
if option.is_none():
|
|
192
|
+
return ok()
|
|
193
|
+
|
|
194
|
+
return fail("expected Option.none, got Option.some")
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
public function expect_null[T](pointer: const_ptr[T]?) -> Check:
|
|
198
|
+
if pointer == null:
|
|
199
|
+
return ok()
|
|
200
|
+
|
|
201
|
+
return fail("expected null pointer, got non-null")
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
public function expect_not_null[T](pointer: const_ptr[T]?) -> Check:
|
|
205
|
+
if pointer != null:
|
|
206
|
+
return ok()
|
|
207
|
+
|
|
208
|
+
return fail("expected non-null pointer, got null")
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
public function expect_error[T, E](result: Result[T, E]) -> Check:
|
|
212
|
+
if result.is_failure():
|
|
213
|
+
return ok()
|
|
214
|
+
|
|
215
|
+
return fail("expected Result.failure, got Result.success")
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
# ── Runner (hand-written; compiler discovery is a later phase) ─────────────
|
|
219
|
+
|
|
220
|
+
public function record(stats: Stats, name: str, outcome: Check) -> Stats:
|
|
221
|
+
match outcome:
|
|
222
|
+
Result.success:
|
|
223
|
+
var line = string.String.create()
|
|
224
|
+
line.append("ok - ")
|
|
225
|
+
line.append(name)
|
|
226
|
+
stdio.print_line(line.as_str())
|
|
227
|
+
line.release()
|
|
228
|
+
return Stats(passed = stats.passed + 1, failed = stats.failed, skipped = stats.skipped)
|
|
229
|
+
Result.failure as payload:
|
|
230
|
+
let failure = payload.error
|
|
231
|
+
var line = string.String.create()
|
|
232
|
+
if failure.is_skip:
|
|
233
|
+
line.append("skip - ")
|
|
234
|
+
else:
|
|
235
|
+
line.append("FAIL - ")
|
|
236
|
+
|
|
237
|
+
line.append(name)
|
|
238
|
+
line.append(": ")
|
|
239
|
+
line.append(failure.message.as_str())
|
|
240
|
+
stdio.print_line(line.as_str())
|
|
241
|
+
line.release()
|
|
242
|
+
|
|
243
|
+
var owned_message = failure.message
|
|
244
|
+
owned_message.release()
|
|
245
|
+
|
|
246
|
+
if failure.is_skip:
|
|
247
|
+
return Stats(passed = stats.passed, failed = stats.failed, skipped = stats.skipped + 1)
|
|
248
|
+
|
|
249
|
+
return Stats(passed = stats.passed, failed = stats.failed + 1, skipped = stats.skipped)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
public function summarize(stats: Stats) -> int:
|
|
253
|
+
var line = string.String.create()
|
|
254
|
+
line.append("passed=")
|
|
255
|
+
fmt.append_int(ref_of(line), stats.passed)
|
|
256
|
+
line.append(" failed=")
|
|
257
|
+
fmt.append_int(ref_of(line), stats.failed)
|
|
258
|
+
line.append(" skipped=")
|
|
259
|
+
fmt.append_int(ref_of(line), stats.skipped)
|
|
260
|
+
stdio.print_line(line.as_str())
|
|
261
|
+
line.release()
|
|
262
|
+
|
|
263
|
+
if stats.failed > 0:
|
|
264
|
+
return 1
|
|
265
|
+
|
|
266
|
+
return 0
|
data/std/thread.mt
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import std.libuv as libuv
|
|
2
|
+
import std.mem.heap as heap
|
|
3
|
+
import std.str as text
|
|
4
|
+
import std.string as string
|
|
5
|
+
|
|
6
|
+
public type NativeThreadHandle = libuv.uv_thread_t
|
|
7
|
+
|
|
8
|
+
public struct Error:
|
|
9
|
+
code: int
|
|
10
|
+
message: string.String
|
|
11
|
+
|
|
12
|
+
public struct Thread:
|
|
13
|
+
handle: ptr[NativeThreadHandle]?
|
|
14
|
+
|
|
15
|
+
struct RawStartState:
|
|
16
|
+
entry: fn(arg: ptr[void]) -> void
|
|
17
|
+
arg: ptr[void]
|
|
18
|
+
|
|
19
|
+
struct VoidStartState:
|
|
20
|
+
run: fn() -> void
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
function libuv_error(code: int) -> Error:
|
|
24
|
+
return Error(code = code, message = string.String.from_str(text.cstr_as_str(libuv.strerror(code))))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
function thread_handle(handle: ptr[NativeThreadHandle]?) -> ptr[NativeThreadHandle]:
|
|
28
|
+
let live_handle = handle else:
|
|
29
|
+
fatal(c"thread handle is released")
|
|
30
|
+
|
|
31
|
+
return live_handle
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
function thread_entry_raw(frame: ptr[void]) -> void:
|
|
35
|
+
let state = unsafe: ptr[RawStartState]<-frame
|
|
36
|
+
let entry = unsafe: read(state).entry
|
|
37
|
+
let arg = unsafe: read(state).arg
|
|
38
|
+
heap.release(state)
|
|
39
|
+
entry(arg)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
function thread_entry_void(frame: ptr[void]) -> void:
|
|
43
|
+
let state = unsafe: ptr[VoidStartState]<-frame
|
|
44
|
+
let run = unsafe: read(state).run
|
|
45
|
+
heap.release(state)
|
|
46
|
+
run()
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
public function spawn_raw(entry: fn(arg: ptr[void]) -> void, arg: ptr[void]) -> Result[Thread, Error]:
|
|
50
|
+
let handle = heap.must_alloc_zeroed[NativeThreadHandle](1)
|
|
51
|
+
let state = heap.must_alloc_zeroed[RawStartState](1)
|
|
52
|
+
unsafe:
|
|
53
|
+
state.entry = entry
|
|
54
|
+
state.arg = arg
|
|
55
|
+
|
|
56
|
+
let status_code = libuv.thread_create(handle, thread_entry_raw, unsafe: ptr[void]<-state)
|
|
57
|
+
if status_code != 0:
|
|
58
|
+
heap.release(state)
|
|
59
|
+
heap.release(handle)
|
|
60
|
+
return Result[Thread, Error].failure(error = libuv_error(status_code))
|
|
61
|
+
|
|
62
|
+
return Result[Thread, Error].success(value = Thread(handle = handle))
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
public function spawn(run: fn() -> void) -> Result[Thread, Error]:
|
|
66
|
+
let handle = heap.must_alloc_zeroed[NativeThreadHandle](1)
|
|
67
|
+
let state = heap.must_alloc_zeroed[VoidStartState](1)
|
|
68
|
+
unsafe: state.run = run
|
|
69
|
+
|
|
70
|
+
let status_code = libuv.thread_create(handle, thread_entry_void, unsafe: ptr[void]<-state)
|
|
71
|
+
if status_code != 0:
|
|
72
|
+
heap.release(state)
|
|
73
|
+
heap.release(handle)
|
|
74
|
+
return Result[Thread, Error].failure(error = libuv_error(status_code))
|
|
75
|
+
|
|
76
|
+
return Result[Thread, Error].success(value = Thread(handle = handle))
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
extending Error:
|
|
80
|
+
public editable function release() -> void:
|
|
81
|
+
this.message.release()
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
extending Thread:
|
|
85
|
+
public editable function release() -> void:
|
|
86
|
+
let handle = this.handle else:
|
|
87
|
+
return
|
|
88
|
+
|
|
89
|
+
let status_code = libuv.thread_detach(handle)
|
|
90
|
+
if status_code != 0:
|
|
91
|
+
fatal(c"thread release detach failed")
|
|
92
|
+
|
|
93
|
+
heap.release(handle)
|
|
94
|
+
this.handle = null
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
public function joinable() -> bool:
|
|
98
|
+
return this.handle != null[ptr[NativeThreadHandle]]
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
public editable function join() -> Result[bool, Error]:
|
|
102
|
+
let handle = this.handle else:
|
|
103
|
+
return Result[bool, Error].failure(error = Error(
|
|
104
|
+
code = -1,
|
|
105
|
+
message = string.String.from_str("thread handle is released")
|
|
106
|
+
))
|
|
107
|
+
|
|
108
|
+
let status_code = libuv.thread_join(handle)
|
|
109
|
+
if status_code != 0:
|
|
110
|
+
return Result[bool, Error].failure(error = libuv_error(status_code))
|
|
111
|
+
|
|
112
|
+
heap.release(handle)
|
|
113
|
+
this.handle = null
|
|
114
|
+
return Result[bool, Error].success(value = true)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
public function sleep_ms(milliseconds: uint) -> void:
|
|
118
|
+
usleep(milliseconds * 1000u)
|
|
119
|
+
|
|
120
|
+
external function usleep(__useconds: uint) -> int
|
data/std/time.mt
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import std.c.time as c
|
|
2
|
+
|
|
3
|
+
public type Timestamp = c.time_t
|
|
4
|
+
public type ClockId = c.clockid_t
|
|
5
|
+
public type DateTime = c.tm
|
|
6
|
+
public type TimeSpec = c.timespec
|
|
7
|
+
|
|
8
|
+
public const REALTIME_CLOCK: ClockId = c.CLOCK_REALTIME
|
|
9
|
+
public const MONOTONIC_CLOCK: ClockId = c.CLOCK_MONOTONIC
|
|
10
|
+
public const NANOSECONDS_PER_SECOND: ptr_uint = 1000000000
|
|
11
|
+
public const NANOSECONDS_PER_MILLISECOND: ptr_uint = 1000000
|
|
12
|
+
|
|
13
|
+
public foreign function current_timestamp(out value: Timestamp) -> Timestamp = c.time
|
|
14
|
+
public foreign function timestamp_from_local_time(value: ptr[DateTime]) -> Timestamp = c.mktime
|
|
15
|
+
public foreign function seconds_between(left: Timestamp, right: Timestamp) -> double = c.difftime
|
|
16
|
+
public foreign function format_date_time(buffer: ptr[char], max_size: ptr_uint, format: str as cstr, value: ptr[DateTime]) -> ptr_uint = c.strftime
|
|
17
|
+
public foreign function clock_resolution_into(clock_id: ClockId, out resolution: TimeSpec) -> int = c.clock_getres
|
|
18
|
+
public foreign function clock_time_into(clock_id: ClockId, out value: TimeSpec) -> int = c.clock_gettime
|
|
19
|
+
public foreign function sleep_for(duration: const_ptr[TimeSpec], remaining: ptr[TimeSpec]?) -> int = c.nanosleep
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
public function now() -> Timestamp:
|
|
23
|
+
return c.time(null)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
public function local_time_ptr(value: Timestamp) -> ptr[DateTime]?:
|
|
27
|
+
var copy = value
|
|
28
|
+
return c.localtime(ptr_of(copy))
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
public function utc_time_ptr(value: Timestamp) -> ptr[DateTime]?:
|
|
32
|
+
var copy = value
|
|
33
|
+
return c.gmtime(ptr_of(copy))
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
public function format_into(buffer: ptr[char], max_size: ptr_uint, format: str, value: ptr[DateTime]?) -> ptr_uint:
|
|
37
|
+
if value == null:
|
|
38
|
+
return 0
|
|
39
|
+
|
|
40
|
+
return format_date_time(buffer, max_size, format, value)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
public function format_local_time_into(
|
|
44
|
+
buffer: ptr[char],
|
|
45
|
+
max_size: ptr_uint,
|
|
46
|
+
format: str,
|
|
47
|
+
value: Timestamp
|
|
48
|
+
) -> ptr_uint:
|
|
49
|
+
return format_into(buffer, max_size, format, local_time_ptr(value))
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
public function format_utc_time_into(buffer: ptr[char], max_size: ptr_uint, format: str, value: Timestamp) -> ptr_uint:
|
|
53
|
+
return format_into(buffer, max_size, format, utc_time_ptr(value))
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
public function clock_resolution(clock_id: ClockId, resolution: ref[TimeSpec]) -> int:
|
|
57
|
+
return c.clock_getres(clock_id, ptr_of(resolution))
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
public function clock_time(clock_id: ClockId, value: ref[TimeSpec]) -> int:
|
|
61
|
+
return c.clock_gettime(clock_id, ptr_of(value))
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
public function realtime(value: ref[TimeSpec]) -> int:
|
|
65
|
+
return clock_time(REALTIME_CLOCK, value)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
public function monotonic(value: ref[TimeSpec]) -> int:
|
|
69
|
+
return clock_time(MONOTONIC_CLOCK, value)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
public function seconds(value: ptr_int) -> TimeSpec:
|
|
73
|
+
return c.timespec(tv_sec = value, tv_nsec = 0)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
public function milliseconds(value: ptr_uint) -> TimeSpec:
|
|
77
|
+
let seconds_part = ptr_int<-(value / 1000z)
|
|
78
|
+
let nanoseconds_part = ptr_int<-((value % 1000z) * NANOSECONDS_PER_MILLISECOND)
|
|
79
|
+
return c.timespec(tv_sec = seconds_part, tv_nsec = nanoseconds_part)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
public function nanoseconds(value: ptr_uint) -> TimeSpec:
|
|
83
|
+
let seconds_part = ptr_int<-(value / NANOSECONDS_PER_SECOND)
|
|
84
|
+
let nanoseconds_part = ptr_int<-(value % NANOSECONDS_PER_SECOND)
|
|
85
|
+
return c.timespec(tv_sec = seconds_part, tv_nsec = nanoseconds_part)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
public function sleep(duration: TimeSpec) -> int:
|
|
89
|
+
var requested = duration
|
|
90
|
+
return sleep_for(ptr_of(requested), null)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
public function sleep_seconds(value: ptr_uint) -> int:
|
|
94
|
+
var requested = seconds(ptr_int<-value)
|
|
95
|
+
return sleep_for(ptr_of(requested), null)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
public function sleep_milliseconds(value: ptr_uint) -> int:
|
|
99
|
+
var requested = milliseconds(value)
|
|
100
|
+
return sleep_for(ptr_of(requested), null)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
public function sleep_nanoseconds(value: ptr_uint) -> int:
|
|
104
|
+
var requested = nanoseconds(value)
|
|
105
|
+
return sleep_for(ptr_of(requested), null)
|