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/tracy.mt
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# generated by mtc imported-bindings from std.c.tracy using bindings/imported/tracy.binding.json
|
|
2
|
+
|
|
3
|
+
import std.c.tracy as c
|
|
4
|
+
|
|
5
|
+
public type Zone = c.TracyCZoneCtx
|
|
6
|
+
public type SourceLocation = c.TracyCSourceLocation
|
|
7
|
+
public type GpuTime = c.TracyCGpuTime
|
|
8
|
+
public type GpuZoneName = c.TracyCGpuZoneName
|
|
9
|
+
|
|
10
|
+
public foreign function zone_begin(srcloc: const_ptr[SourceLocation]?, active: int) -> Zone = c.tracy_emit_zone_begin
|
|
11
|
+
public foreign function emit_zone_begin_callstack(srcloc: const_ptr[SourceLocation]?, depth: int, active: int) -> Zone = c.tracy_emit_zone_begin_callstack
|
|
12
|
+
public foreign function zone_end(zone: Zone) -> void = c.tracy_emit_zone_end
|
|
13
|
+
public foreign function zone_text(zone: const_ptr[Zone], text: str as cstr, size: ptr_uint) -> void = c.tracy_emit_zone_text
|
|
14
|
+
public foreign function zone_name(zone: const_ptr[Zone], name: str as cstr, size: ptr_uint) -> void = c.tracy_emit_zone_name
|
|
15
|
+
public foreign function emit_zone_color(ctx: Zone, color: uint) -> void = c.tracy_emit_zone_color
|
|
16
|
+
public foreign function zone_value(zone: const_ptr[Zone], value: long) -> void = c.tracy_emit_zone_value
|
|
17
|
+
public foreign function emit_gpu_zone_begin(srcloc: const_ptr[SourceLocation]?, active: int) -> Zone = c.tracy_emit_gpu_zone_begin
|
|
18
|
+
public foreign function emit_gpu_zone_begin_callstack(srcloc: const_ptr[SourceLocation]?, depth: int, active: int) -> Zone = c.tracy_emit_gpu_zone_begin_callstack
|
|
19
|
+
public foreign function emit_gpu_zone_end(ctx: Zone) -> void = c.tracy_emit_gpu_zone_end
|
|
20
|
+
public foreign function emit_gpu_zone_name(ctx: Zone, name: str as cstr, size: ptr_uint) -> void = c.tracy_emit_gpu_zone_name
|
|
21
|
+
public foreign function emit_gpu_zone_value(ctx: Zone, value: long) -> void = c.tracy_emit_gpu_zone_value
|
|
22
|
+
public foreign function emit_gpu_new_context(ctx: Zone) -> void = c.tracy_emit_gpu_new_context
|
|
23
|
+
public foreign function emit_gpu_context_name(ctx: Zone, name: str as cstr, size: ptr_uint) -> void = c.tracy_emit_gpu_context_name
|
|
24
|
+
public foreign function emit_gpu_calibration(ctx: Zone) -> void = c.tracy_emit_gpu_calibration
|
|
25
|
+
public foreign function emit_gpu_time(data: const_ptr[GpuTime]) -> void = c.tracy_emit_gpu_time
|
|
26
|
+
public foreign function emit_gpu_time_sync(data: const_ptr[GpuTime]) -> void = c.tracy_emit_gpu_time_sync
|
|
27
|
+
public foreign function frame_mark(name: str as cstr) -> void = c.tracy_emit_frame_mark
|
|
28
|
+
public foreign function frame_mark_start(name: str as cstr) -> void = c.tracy_emit_frame_mark_start
|
|
29
|
+
public foreign function frame_mark_end(name: str as cstr) -> void = c.tracy_emit_frame_mark_end
|
|
30
|
+
public foreign function plot(name: str as cstr, value: double) -> void = c.tracy_emit_plot
|
|
31
|
+
public foreign function emit_plot_config(name: str as cstr, format_type: int, step: int, fill: int, color: uint) -> void = c.tracy_emit_plot_config
|
|
32
|
+
public foreign function plot_float(name: str as cstr, value: float) -> void = c.tracy_emit_plot_float
|
|
33
|
+
public foreign function plot_int(name: str as cstr, value: long) -> void = c.tracy_emit_plot_int
|
|
34
|
+
public foreign function message(text: str as cstr, size: ptr_uint, callstack: int) -> void = c.tracy_emit_message
|
|
35
|
+
public foreign function emit_message_color(text: str as cstr, size: ptr_uint, color: uint, callstack: int) -> void = c.tracy_emit_message_color
|
|
36
|
+
public foreign function message_l(text: str as cstr, callstack: int) -> void = c.tracy_emit_message_l
|
|
37
|
+
public foreign function message_lc(text: str as cstr, color: uint, callstack: int) -> void = c.tracy_emit_message_lc
|
|
38
|
+
public foreign function is_connected() -> int = c.tracy_connected
|
|
39
|
+
public foreign function fiber_enter(fiber: str as cstr) -> void = c.tracy_fiber_enter
|
|
40
|
+
public foreign function fiber_leave() -> void = c.tracy_fiber_leave
|
|
41
|
+
public foreign function startup() -> void = c.tracy_startup_profiler
|
|
42
|
+
public foreign function shutdown() -> void = c.tracy_shutdown_profiler
|
data/std/uri.mt
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import std.path as path
|
|
2
|
+
import std.str as text
|
|
3
|
+
import std.string as string
|
|
4
|
+
|
|
5
|
+
const FILE_URI_PREFIX: str = "file://"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
public function file_uri_from_path(path_text: str) -> string.String:
|
|
9
|
+
var normalized = path.normalize_separators(path_text)
|
|
10
|
+
defer normalized.release()
|
|
11
|
+
|
|
12
|
+
var result = string.String.from_str(FILE_URI_PREFIX)
|
|
13
|
+
append_percent_encoded_path(ref_of(result), normalized.as_str())
|
|
14
|
+
return result
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
public function path_from_file_uri(uri: str) -> Option[string.String]:
|
|
18
|
+
if not uri.starts_with(FILE_URI_PREFIX):
|
|
19
|
+
return Option[string.String].none
|
|
20
|
+
|
|
21
|
+
let encoded_path = uri.slice(FILE_URI_PREFIX.len, uri.len - FILE_URI_PREFIX.len)
|
|
22
|
+
var decoded = percent_decode(encoded_path)?
|
|
23
|
+
match owned_utf8_view(decoded):
|
|
24
|
+
Option.none:
|
|
25
|
+
decoded.release()
|
|
26
|
+
return Option[string.String].none
|
|
27
|
+
Option.some as view_payload:
|
|
28
|
+
let decoded_path = view_payload.value
|
|
29
|
+
if leading_slash_drive_path(decoded_path):
|
|
30
|
+
let normalized = string.String.from_str(decoded_path.slice(1, decoded_path.len - 1))
|
|
31
|
+
decoded.release()
|
|
32
|
+
return Option[string.String].some(value= normalized)
|
|
33
|
+
|
|
34
|
+
return Option[string.String].some(value= decoded)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
public function percent_decode(text_value: str) -> Option[string.String]:
|
|
38
|
+
var result = string.String.with_capacity(text_value.len)
|
|
39
|
+
|
|
40
|
+
var index: ptr_uint = 0
|
|
41
|
+
while index < text_value.len:
|
|
42
|
+
let value = text_value.byte_at(index)
|
|
43
|
+
if value != 37:
|
|
44
|
+
result.push_byte(value)
|
|
45
|
+
index += 1
|
|
46
|
+
continue
|
|
47
|
+
|
|
48
|
+
if index + 2 >= text_value.len:
|
|
49
|
+
result.release()
|
|
50
|
+
return Option[string.String].none
|
|
51
|
+
|
|
52
|
+
let high = hex_digit_value(text_value.byte_at(index + 1))
|
|
53
|
+
let low = hex_digit_value(text_value.byte_at(index + 2))
|
|
54
|
+
if high < 0 or low < 0:
|
|
55
|
+
result.release()
|
|
56
|
+
return Option[string.String].none
|
|
57
|
+
|
|
58
|
+
result.push_byte(ubyte<-(high * 16 + low))
|
|
59
|
+
index += 3
|
|
60
|
+
|
|
61
|
+
return Option[string.String].some(value= result)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
function append_percent_encoded_path(output: ref[string.String], path_text: str) -> void:
|
|
65
|
+
var index: ptr_uint = 0
|
|
66
|
+
while index < path_text.len:
|
|
67
|
+
let value = path_text.byte_at(index)
|
|
68
|
+
if value == 47:
|
|
69
|
+
output.push_byte(value)
|
|
70
|
+
else if safe_path_byte(value):
|
|
71
|
+
output.push_byte(value)
|
|
72
|
+
else:
|
|
73
|
+
append_percent_encoded_byte(output, value)
|
|
74
|
+
index += 1
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
function append_percent_encoded_byte(output: ref[string.String], value: ubyte) -> void:
|
|
78
|
+
output.push_byte(37)
|
|
79
|
+
output.push_byte(hex_digit(value >> 4))
|
|
80
|
+
output.push_byte(hex_digit(value & 0x0F))
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
function hex_digit(value: ubyte) -> ubyte:
|
|
84
|
+
if value < 10:
|
|
85
|
+
return (48 + value)
|
|
86
|
+
|
|
87
|
+
return (65 + (value - 10))
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
function hex_digit_value(value: ubyte) -> int:
|
|
91
|
+
if value >= 48 and value <= 57:
|
|
92
|
+
return (value - 48ub)
|
|
93
|
+
if value >= 65 and value <= 70:
|
|
94
|
+
return 10 + int<-(value - 65ub)
|
|
95
|
+
if value >= 97 and value <= 102:
|
|
96
|
+
return 10 + int<-(value - 97ub)
|
|
97
|
+
|
|
98
|
+
return -1
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
function safe_path_byte(value: ubyte) -> bool:
|
|
102
|
+
return ascii_letter(value) or ascii_digit(value) or value == 95 or value == 46 or value == 45 or value == 42
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
function ascii_letter(value: ubyte) -> bool:
|
|
106
|
+
return (value >= 65 and value <= 90) or (value >= 97 and value <= 122)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
function ascii_digit(value: ubyte) -> bool:
|
|
110
|
+
return value >= 48 and value <= 57
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
function leading_slash_drive_path(path_text: str) -> bool:
|
|
114
|
+
return path_text.len >= 3 and path_text.byte_at(0) == 47 and ascii_letter(path_text.byte_at(1)) and path_text.byte_at(2) == 58
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
function owned_utf8_view(value: string.String) -> Option[str]:
|
|
118
|
+
return text.utf8_byte_span_as_str(unsafe: span[ubyte](data = ptr[ubyte]<-value.data, len = value.len))
|
data/std/url.mt
ADDED
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
import std.str as text
|
|
2
|
+
import std.string as string
|
|
3
|
+
import std.vec as vec
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
function is_unreserved(value: ubyte) -> bool:
|
|
7
|
+
return (
|
|
8
|
+
(value >= 48 and value <= 57)
|
|
9
|
+
or (value >= 65 and value <= 90)
|
|
10
|
+
or (value >= 97 and value <= 122)
|
|
11
|
+
or value == 45
|
|
12
|
+
or value == 46
|
|
13
|
+
or value == 95
|
|
14
|
+
or value == 126
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
function hex_digit(value: ubyte) -> ubyte:
|
|
19
|
+
if value < 10:
|
|
20
|
+
return 48 + value
|
|
21
|
+
|
|
22
|
+
return 65 + (value - 10)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
function hex_value(value: ubyte) -> int:
|
|
26
|
+
if value >= 48 and value <= 57:
|
|
27
|
+
return (value - 48ub)
|
|
28
|
+
if value >= 65 and value <= 70:
|
|
29
|
+
return 10 + int<-(value - 65ub)
|
|
30
|
+
if value >= 97 and value <= 102:
|
|
31
|
+
return 10 + int<-(value - 97ub)
|
|
32
|
+
|
|
33
|
+
return -1
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
function find_byte_from(data: str, target: ubyte, start: ptr_uint) -> Option[ptr_uint]:
|
|
37
|
+
var index = start
|
|
38
|
+
while index < data.len:
|
|
39
|
+
if data.byte_at(index) == target:
|
|
40
|
+
return Option[ptr_uint].some(value = index)
|
|
41
|
+
index += 1
|
|
42
|
+
|
|
43
|
+
return Option[ptr_uint].none
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
public function percent_encode(text_value: str) -> string.String:
|
|
47
|
+
var result = string.String.with_capacity(text_value.len * 3)
|
|
48
|
+
var index: ptr_uint = 0
|
|
49
|
+
while index < text_value.len:
|
|
50
|
+
let value = text_value.byte_at(index)
|
|
51
|
+
if is_unreserved(value):
|
|
52
|
+
result.push_byte(value)
|
|
53
|
+
else:
|
|
54
|
+
result.push_byte(37)
|
|
55
|
+
result.push_byte(hex_digit(value >> 4))
|
|
56
|
+
result.push_byte(hex_digit(value & 0x0F))
|
|
57
|
+
index += 1
|
|
58
|
+
|
|
59
|
+
return result
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
public function percent_decode(text_value: str) -> Option[string.String]:
|
|
63
|
+
var result = string.String.with_capacity(text_value.len)
|
|
64
|
+
var index: ptr_uint = 0
|
|
65
|
+
while index < text_value.len:
|
|
66
|
+
let value = text_value.byte_at(index)
|
|
67
|
+
if value != 37:
|
|
68
|
+
result.push_byte(value)
|
|
69
|
+
index += 1
|
|
70
|
+
continue
|
|
71
|
+
|
|
72
|
+
if index + 2 >= text_value.len:
|
|
73
|
+
result.release()
|
|
74
|
+
return Option[string.String].none
|
|
75
|
+
|
|
76
|
+
let high = hex_value(text_value.byte_at(index + 1))
|
|
77
|
+
let low = hex_value(text_value.byte_at(index + 2))
|
|
78
|
+
if high < 0 or low < 0:
|
|
79
|
+
result.release()
|
|
80
|
+
return Option[string.String].none
|
|
81
|
+
|
|
82
|
+
let decoded = ubyte<-(high * 16 + low)
|
|
83
|
+
result.push_byte(decoded)
|
|
84
|
+
index += 3
|
|
85
|
+
|
|
86
|
+
return Option[string.String].some(value = result)
|
|
87
|
+
|
|
88
|
+
public struct QueryParam:
|
|
89
|
+
key: string.String
|
|
90
|
+
value: string.String
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
public function parse_query(url: str) -> Result[vec.Vec[QueryParam], string.String]:
|
|
94
|
+
var params = vec.Vec[QueryParam].create()
|
|
95
|
+
|
|
96
|
+
let question = url.find_byte(63)
|
|
97
|
+
var rest: str = zero[str]
|
|
98
|
+
match question:
|
|
99
|
+
Option.none:
|
|
100
|
+
return Result[vec.Vec[QueryParam], string.String].success(value = params)
|
|
101
|
+
Option.some as q:
|
|
102
|
+
rest = url.slice(q.value + 1, url.len - q.value - 1)
|
|
103
|
+
|
|
104
|
+
let fragment = rest.find_byte(35)
|
|
105
|
+
match fragment:
|
|
106
|
+
Option.none:
|
|
107
|
+
pass
|
|
108
|
+
Option.some as f:
|
|
109
|
+
rest = rest.slice(0, f.value)
|
|
110
|
+
|
|
111
|
+
if rest.len == 0:
|
|
112
|
+
return Result[vec.Vec[QueryParam], string.String].success(value = params)
|
|
113
|
+
|
|
114
|
+
var start: ptr_uint = 0
|
|
115
|
+
while start < rest.len:
|
|
116
|
+
let amp = find_byte_from(rest, 38, start)
|
|
117
|
+
match amp:
|
|
118
|
+
Option.none:
|
|
119
|
+
let pair_text = rest.slice(start, rest.len - start)
|
|
120
|
+
let pair_result = parse_query_pair(pair_text)
|
|
121
|
+
match pair_result:
|
|
122
|
+
Result.failure as payload:
|
|
123
|
+
release_params(ref_of(params))
|
|
124
|
+
return Result[
|
|
125
|
+
vec.Vec[QueryParam],
|
|
126
|
+
string.String
|
|
127
|
+
].failure(error = payload.error)
|
|
128
|
+
Result.success as payload:
|
|
129
|
+
params.push(payload.value)
|
|
130
|
+
|
|
131
|
+
start = rest.len
|
|
132
|
+
Option.some as a:
|
|
133
|
+
let pair_text = rest.slice(start, a.value - start)
|
|
134
|
+
let pair_result = parse_query_pair(pair_text)
|
|
135
|
+
match pair_result:
|
|
136
|
+
Result.failure as payload:
|
|
137
|
+
release_params(ref_of(params))
|
|
138
|
+
return Result[
|
|
139
|
+
vec.Vec[QueryParam],
|
|
140
|
+
string.String
|
|
141
|
+
].failure(error = payload.error)
|
|
142
|
+
Result.success as payload:
|
|
143
|
+
params.push(payload.value)
|
|
144
|
+
|
|
145
|
+
start = a.value + 1
|
|
146
|
+
|
|
147
|
+
return Result[vec.Vec[QueryParam], string.String].success(value = params)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
function parse_query_pair(text_value: str) -> Result[QueryParam, string.String]:
|
|
151
|
+
let eq = text_value.find_byte(61)
|
|
152
|
+
match eq:
|
|
153
|
+
Option.none:
|
|
154
|
+
let decoded_key = percent_decode(text_value) else:
|
|
155
|
+
return Result[
|
|
156
|
+
QueryParam,
|
|
157
|
+
string.String
|
|
158
|
+
].failure(error = string.String.from_str("url: invalid percent-encoding in query key"))
|
|
159
|
+
|
|
160
|
+
return Result[QueryParam, string.String].success(
|
|
161
|
+
value = QueryParam(key = decoded_key, value = string.String.create())
|
|
162
|
+
)
|
|
163
|
+
Option.some as e:
|
|
164
|
+
let key_text = text_value.slice(0, e.value)
|
|
165
|
+
let value_text = text_value.slice(e.value + 1, text_value.len - e.value - 1)
|
|
166
|
+
|
|
167
|
+
let decoded_key = percent_decode(key_text) else:
|
|
168
|
+
return Result[
|
|
169
|
+
QueryParam,
|
|
170
|
+
string.String
|
|
171
|
+
].failure(error = string.String.from_str("url: invalid percent-encoding in query key"))
|
|
172
|
+
|
|
173
|
+
let decoded_value = percent_decode(value_text) else:
|
|
174
|
+
var owned_key = decoded_key
|
|
175
|
+
owned_key.release()
|
|
176
|
+
return Result[
|
|
177
|
+
QueryParam,
|
|
178
|
+
string.String
|
|
179
|
+
].failure(error = string.String.from_str("url: invalid percent-encoding in query value"))
|
|
180
|
+
|
|
181
|
+
return Result[QueryParam, string.String].success(
|
|
182
|
+
value = QueryParam(key = decoded_key, value = decoded_value)
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
public function build_query(params: span[QueryParam]) -> string.String:
|
|
187
|
+
var result = string.String.create()
|
|
188
|
+
|
|
189
|
+
var index: ptr_uint = 0
|
|
190
|
+
while index < params.len:
|
|
191
|
+
if index > 0:
|
|
192
|
+
result.push_byte(38)
|
|
193
|
+
|
|
194
|
+
let param = unsafe: read(params.data + index)
|
|
195
|
+
var encoded_key = percent_encode(param.key.as_str())
|
|
196
|
+
var encoded_value = percent_encode(param.value.as_str())
|
|
197
|
+
|
|
198
|
+
result.append(encoded_key.as_str())
|
|
199
|
+
result.push_byte(61)
|
|
200
|
+
result.append(encoded_value.as_str())
|
|
201
|
+
|
|
202
|
+
encoded_key.release()
|
|
203
|
+
encoded_value.release()
|
|
204
|
+
|
|
205
|
+
index += 1
|
|
206
|
+
|
|
207
|
+
return result
|
|
208
|
+
|
|
209
|
+
public struct FormField:
|
|
210
|
+
key: str
|
|
211
|
+
value: str
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
public function encode_form(fields: span[FormField]) -> string.String:
|
|
215
|
+
var result = string.String.create()
|
|
216
|
+
|
|
217
|
+
var index: ptr_uint = 0
|
|
218
|
+
while index < fields.len:
|
|
219
|
+
if index > 0:
|
|
220
|
+
result.push_byte(38)
|
|
221
|
+
|
|
222
|
+
let field = unsafe: read(fields.data + index)
|
|
223
|
+
append_form_encoded(ref_of(result), field.key)
|
|
224
|
+
result.push_byte(61)
|
|
225
|
+
append_form_encoded(ref_of(result), field.value)
|
|
226
|
+
|
|
227
|
+
index += 1
|
|
228
|
+
|
|
229
|
+
return result
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
function append_form_encoded(output: ref[string.String], text_value: str) -> void:
|
|
233
|
+
var index: ptr_uint = 0
|
|
234
|
+
while index < text_value.len:
|
|
235
|
+
let value = text_value.byte_at(index)
|
|
236
|
+
if value == 32:
|
|
237
|
+
output.push_byte(43)
|
|
238
|
+
else if is_unreserved(value):
|
|
239
|
+
output.push_byte(value)
|
|
240
|
+
else:
|
|
241
|
+
output.push_byte(37)
|
|
242
|
+
output.push_byte(hex_digit(value >> 4))
|
|
243
|
+
output.push_byte(hex_digit(value & 0x0F))
|
|
244
|
+
index += 1
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
public function decode_form(body: str) -> Result[vec.Vec[QueryParam], string.String]:
|
|
248
|
+
var params = vec.Vec[QueryParam].create()
|
|
249
|
+
|
|
250
|
+
if body.len == 0:
|
|
251
|
+
return Result[vec.Vec[QueryParam], string.String].success(value = params)
|
|
252
|
+
|
|
253
|
+
var start: ptr_uint = 0
|
|
254
|
+
while start < body.len:
|
|
255
|
+
let amp = find_byte_from(body, 38, start)
|
|
256
|
+
match amp:
|
|
257
|
+
Option.none:
|
|
258
|
+
let pair_text = body.slice(start, body.len - start)
|
|
259
|
+
let pair_result = parse_form_pair(pair_text)
|
|
260
|
+
match pair_result:
|
|
261
|
+
Result.failure as payload:
|
|
262
|
+
release_params(ref_of(params))
|
|
263
|
+
return Result[
|
|
264
|
+
vec.Vec[QueryParam],
|
|
265
|
+
string.String
|
|
266
|
+
].failure(error = payload.error)
|
|
267
|
+
Result.success as payload:
|
|
268
|
+
params.push(payload.value)
|
|
269
|
+
|
|
270
|
+
start = body.len
|
|
271
|
+
Option.some as a:
|
|
272
|
+
let pair_text = body.slice(start, a.value - start)
|
|
273
|
+
let pair_result = parse_form_pair(pair_text)
|
|
274
|
+
match pair_result:
|
|
275
|
+
Result.failure as payload:
|
|
276
|
+
release_params(ref_of(params))
|
|
277
|
+
return Result[
|
|
278
|
+
vec.Vec[QueryParam],
|
|
279
|
+
string.String
|
|
280
|
+
].failure(error = payload.error)
|
|
281
|
+
Result.success as payload:
|
|
282
|
+
params.push(payload.value)
|
|
283
|
+
|
|
284
|
+
start = a.value + 1
|
|
285
|
+
|
|
286
|
+
return Result[vec.Vec[QueryParam], string.String].success(value = params)
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
function parse_form_pair(text_value: str) -> Result[QueryParam, string.String]:
|
|
290
|
+
let eq = text_value.find_byte(61)
|
|
291
|
+
match eq:
|
|
292
|
+
Option.none:
|
|
293
|
+
let decoded_key = form_percent_decode(text_value) else:
|
|
294
|
+
return Result[
|
|
295
|
+
QueryParam,
|
|
296
|
+
string.String
|
|
297
|
+
].failure(error = string.String.from_str("url: invalid percent-encoding in form key"))
|
|
298
|
+
|
|
299
|
+
return Result[QueryParam, string.String].success(
|
|
300
|
+
value = QueryParam(key = decoded_key, value = string.String.create())
|
|
301
|
+
)
|
|
302
|
+
Option.some as e:
|
|
303
|
+
let key_text = text_value.slice(0, e.value)
|
|
304
|
+
let value_text = text_value.slice(e.value + 1, text_value.len - e.value - 1)
|
|
305
|
+
|
|
306
|
+
let decoded_key = form_percent_decode(key_text) else:
|
|
307
|
+
return Result[
|
|
308
|
+
QueryParam,
|
|
309
|
+
string.String
|
|
310
|
+
].failure(error = string.String.from_str("url: invalid percent-encoding in form key"))
|
|
311
|
+
|
|
312
|
+
let decoded_value = form_percent_decode(value_text) else:
|
|
313
|
+
var owned_key = decoded_key
|
|
314
|
+
owned_key.release()
|
|
315
|
+
return Result[
|
|
316
|
+
QueryParam,
|
|
317
|
+
string.String
|
|
318
|
+
].failure(error = string.String.from_str("url: invalid percent-encoding in form value"))
|
|
319
|
+
|
|
320
|
+
return Result[QueryParam, string.String].success(
|
|
321
|
+
value = QueryParam(key = decoded_key, value = decoded_value)
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
function form_percent_decode(text_value: str) -> Option[string.String]:
|
|
326
|
+
var result = string.String.with_capacity(text_value.len)
|
|
327
|
+
var index: ptr_uint = 0
|
|
328
|
+
while index < text_value.len:
|
|
329
|
+
let value = text_value.byte_at(index)
|
|
330
|
+
if value == 43:
|
|
331
|
+
result.push_byte(32)
|
|
332
|
+
index += 1
|
|
333
|
+
else if value != 37:
|
|
334
|
+
result.push_byte(value)
|
|
335
|
+
index += 1
|
|
336
|
+
else:
|
|
337
|
+
if index + 2 >= text_value.len:
|
|
338
|
+
result.release()
|
|
339
|
+
return Option[string.String].none
|
|
340
|
+
|
|
341
|
+
let high = hex_value(text_value.byte_at(index + 1))
|
|
342
|
+
let low = hex_value(text_value.byte_at(index + 2))
|
|
343
|
+
if high < 0 or low < 0:
|
|
344
|
+
result.release()
|
|
345
|
+
return Option[string.String].none
|
|
346
|
+
|
|
347
|
+
let decoded = ubyte<-(high * 16 + low)
|
|
348
|
+
result.push_byte(decoded)
|
|
349
|
+
index += 3
|
|
350
|
+
|
|
351
|
+
return Option[string.String].some(value = result)
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
function release_params(params: ref[vec.Vec[QueryParam]]) -> void:
|
|
355
|
+
var index: ptr_uint = 0
|
|
356
|
+
while index < params.len():
|
|
357
|
+
let current = params.get(index) else:
|
|
358
|
+
fatal(c"url.release_params missing value")
|
|
359
|
+
|
|
360
|
+
unsafe:
|
|
361
|
+
var param = read(current)
|
|
362
|
+
param.release()
|
|
363
|
+
|
|
364
|
+
index += 1
|
|
365
|
+
|
|
366
|
+
params.release()
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
extending QueryParam:
|
|
370
|
+
public editable function release() -> void:
|
|
371
|
+
this.key.release()
|
|
372
|
+
this.value.release()
|