create-mendix-widget-gleam 2.0.14 → 2.0.16
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.
- package/README.md +1 -1
- package/package.json +5 -1
- package/src/index.mjs +32 -12
- package/template/gleam.toml +1 -1
- package/tui/build/dev/javascript/etch/_gleam_artefacts/etch@command.cache +0 -0
- package/tui/build/dev/javascript/etch/_gleam_artefacts/etch@command.cache_inline +0 -0
- package/tui/build/dev/javascript/etch/_gleam_artefacts/etch@command.cache_meta +0 -0
- package/tui/build/dev/javascript/etch/_gleam_artefacts/etch@cursor.cache +0 -0
- package/tui/build/dev/javascript/etch/_gleam_artefacts/etch@cursor.cache_inline +0 -0
- package/tui/build/dev/javascript/etch/_gleam_artefacts/etch@cursor.cache_meta +0 -0
- package/tui/build/dev/javascript/etch/_gleam_artefacts/etch@event.cache +0 -0
- package/tui/build/dev/javascript/etch/_gleam_artefacts/etch@event.cache_inline +0 -0
- package/tui/build/dev/javascript/etch/_gleam_artefacts/etch@event.cache_meta +0 -0
- package/tui/build/dev/javascript/etch/_gleam_artefacts/etch@internal@consts.cache +0 -0
- package/tui/build/dev/javascript/etch/_gleam_artefacts/etch@internal@consts.cache_inline +0 -0
- package/tui/build/dev/javascript/etch/_gleam_artefacts/etch@internal@consts.cache_meta +0 -0
- package/tui/build/dev/javascript/etch/_gleam_artefacts/etch@stdout.cache +0 -0
- package/tui/build/dev/javascript/etch/_gleam_artefacts/etch@stdout.cache_inline +0 -0
- package/tui/build/dev/javascript/etch/_gleam_artefacts/etch@stdout.cache_meta +0 -0
- package/tui/build/dev/javascript/etch/_gleam_artefacts/etch@style.cache +0 -0
- package/tui/build/dev/javascript/etch/_gleam_artefacts/etch@style.cache_inline +0 -0
- package/tui/build/dev/javascript/etch/_gleam_artefacts/etch@style.cache_meta +0 -0
- package/tui/build/dev/javascript/etch/_gleam_artefacts/etch@terminal.cache +0 -0
- package/tui/build/dev/javascript/etch/_gleam_artefacts/etch@terminal.cache_inline +0 -0
- package/tui/build/dev/javascript/etch/_gleam_artefacts/etch@terminal.cache_meta +0 -0
- package/tui/build/dev/javascript/etch/etch/command.mjs +479 -0
- package/tui/build/dev/javascript/etch/etch/cursor.mjs +164 -0
- package/tui/build/dev/javascript/etch/etch/event.mjs +2399 -0
- package/tui/build/dev/javascript/etch/etch/internal/consts.mjs +3 -0
- package/tui/build/dev/javascript/etch/etch/stdout.mjs +375 -0
- package/tui/build/dev/javascript/etch/etch/style.mjs +741 -0
- package/tui/build/dev/javascript/etch/etch/terminal.mjs +137 -0
- package/tui/build/dev/javascript/etch/gleam.mjs +1 -0
- package/tui/build/dev/javascript/etch/input/event_ffi.erl +73 -0
- package/tui/build/dev/javascript/etch/input/input_ffi.mjs +192 -0
- package/tui/build/dev/javascript/etch/input/signal_handler.erl +33 -0
- package/tui/build/dev/javascript/etch/terminal/terminal_ffi.erl +22 -0
- package/tui/build/dev/javascript/etch/terminal/terminal_ffi.mjs +37 -0
- package/tui/build/dev/javascript/etch/terminal/tty_state.erl +29 -0
- package/tui/build/dev/javascript/gleam_erlang/_gleam_artefacts/gleam@erlang@application.cache +0 -0
- package/tui/build/dev/javascript/gleam_erlang/_gleam_artefacts/gleam@erlang@application.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_erlang/_gleam_artefacts/gleam@erlang@application.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_erlang/_gleam_artefacts/gleam@erlang@atom.cache +0 -0
- package/tui/build/dev/javascript/gleam_erlang/_gleam_artefacts/gleam@erlang@atom.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_erlang/_gleam_artefacts/gleam@erlang@atom.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_erlang/_gleam_artefacts/gleam@erlang@charlist.cache +0 -0
- package/tui/build/dev/javascript/gleam_erlang/_gleam_artefacts/gleam@erlang@charlist.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_erlang/_gleam_artefacts/gleam@erlang@charlist.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_erlang/_gleam_artefacts/gleam@erlang@node.cache +0 -0
- package/tui/build/dev/javascript/gleam_erlang/_gleam_artefacts/gleam@erlang@node.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_erlang/_gleam_artefacts/gleam@erlang@node.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_erlang/_gleam_artefacts/gleam@erlang@port.cache +0 -0
- package/tui/build/dev/javascript/gleam_erlang/_gleam_artefacts/gleam@erlang@port.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_erlang/_gleam_artefacts/gleam@erlang@port.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_erlang/_gleam_artefacts/gleam@erlang@process.cache +0 -0
- package/tui/build/dev/javascript/gleam_erlang/_gleam_artefacts/gleam@erlang@process.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_erlang/_gleam_artefacts/gleam@erlang@process.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_erlang/_gleam_artefacts/gleam@erlang@reference.cache +0 -0
- package/tui/build/dev/javascript/gleam_erlang/_gleam_artefacts/gleam@erlang@reference.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_erlang/_gleam_artefacts/gleam@erlang@reference.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_erlang/gleam/erlang/application.mjs +38 -0
- package/tui/build/dev/javascript/gleam_erlang/gleam/erlang/atom.mjs +2 -0
- package/tui/build/dev/javascript/gleam_erlang/gleam/erlang/charlist.mjs +1 -0
- package/tui/build/dev/javascript/gleam_erlang/gleam/erlang/node.mjs +12 -0
- package/tui/build/dev/javascript/gleam_erlang/gleam/erlang/port.mjs +1 -0
- package/tui/build/dev/javascript/gleam_erlang/gleam/erlang/process.mjs +161 -0
- package/tui/build/dev/javascript/gleam_erlang/gleam/erlang/reference.mjs +1 -0
- package/tui/build/dev/javascript/gleam_erlang/gleam.mjs +1 -0
- package/tui/build/dev/javascript/gleam_erlang/gleam@erlang@application.erl +43 -0
- package/tui/build/dev/javascript/gleam_erlang/gleam@erlang@atom.erl +94 -0
- package/tui/build/dev/javascript/gleam_erlang/gleam@erlang@charlist.erl +42 -0
- package/tui/build/dev/javascript/gleam_erlang/gleam@erlang@node.erl +80 -0
- package/tui/build/dev/javascript/gleam_erlang/gleam@erlang@port.erl +8 -0
- package/tui/build/dev/javascript/gleam_erlang/gleam@erlang@process.erl +868 -0
- package/tui/build/dev/javascript/gleam_erlang/gleam@erlang@reference.erl +21 -0
- package/tui/build/dev/javascript/gleam_erlang/gleam_erlang_ffi.erl +164 -0
- package/tui/build/dev/javascript/gleam_javascript/_gleam_artefacts/gleam@javascript@array.cache +0 -0
- package/tui/build/dev/javascript/gleam_javascript/_gleam_artefacts/gleam@javascript@array.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_javascript/_gleam_artefacts/gleam@javascript@array.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_javascript/_gleam_artefacts/gleam@javascript@promise.cache +0 -0
- package/tui/build/dev/javascript/gleam_javascript/_gleam_artefacts/gleam@javascript@promise.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_javascript/_gleam_artefacts/gleam@javascript@promise.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_javascript/_gleam_artefacts/gleam@javascript@symbol.cache +0 -0
- package/tui/build/dev/javascript/gleam_javascript/_gleam_artefacts/gleam@javascript@symbol.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_javascript/_gleam_artefacts/gleam@javascript@symbol.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_javascript/gleam/javascript/array.mjs +24 -0
- package/tui/build/dev/javascript/gleam_javascript/gleam/javascript/promise.mjs +105 -0
- package/tui/build/dev/javascript/gleam_javascript/gleam/javascript/symbol.mjs +7 -0
- package/tui/build/dev/javascript/gleam_javascript/gleam.mjs +1 -0
- package/tui/build/dev/javascript/gleam_javascript/gleam_javascript_ffi.mjs +133 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bit_array.cache +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bit_array.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bit_array.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bool.cache +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bool.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bool.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bytes_tree.cache +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bytes_tree.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bytes_tree.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dict.cache +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dict.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dict.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dynamic.cache +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dynamic.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dynamic.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dynamic@decode.cache +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dynamic@decode.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dynamic@decode.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@float.cache +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@float.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@float.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@function.cache +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@function.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@function.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@int.cache +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@int.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@int.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@io.cache +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@io.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@io.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@list.cache +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@list.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@list.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@option.cache +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@option.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@option.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@order.cache +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@order.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@order.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@pair.cache +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@pair.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@pair.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@result.cache +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@result.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@result.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@set.cache +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@set.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@set.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@string.cache +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@string.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@string.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@string_tree.cache +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@string_tree.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@string_tree.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@uri.cache +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@uri.cache_inline +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@uri.cache_meta +0 -0
- package/tui/build/dev/javascript/gleam_stdlib/dict.mjs +710 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam/bit_array.mjs +286 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam/bool.mjs +295 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam/bytes_tree.mjs +225 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam/dict.mjs +455 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam/dynamic/decode.mjs +993 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam/dynamic.mjs +35 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam/float.mjs +528 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam/function.mjs +6 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam/int.mjs +764 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam/io.mjs +8 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam/list.mjs +3063 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam/option.mjs +386 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam/order.mjs +166 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam/pair.mjs +96 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam/result.mjs +448 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam/set.mjs +413 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam/string.mjs +695 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam/string_tree.mjs +128 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam/uri.mjs +1151 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam.mjs +1 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam@bit_array.erl +347 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam@bool.erl +334 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam@bytes_tree.erl +211 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam@dict.erl +513 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam@dynamic.erl +105 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam@dynamic@decode.erl +1114 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam@float.erl +711 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam@function.erl +18 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam@int.erl +972 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam@io.erl +76 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam@list.erl +2735 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam@option.erl +381 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam@order.erl +188 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam@pair.erl +104 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam@result.erl +500 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam@set.erl +430 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam@string.erl +964 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam@string_tree.erl +202 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam@uri.erl +1042 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam_stdlib.erl +534 -0
- package/tui/build/dev/javascript/gleam_stdlib/gleam_stdlib.mjs +1133 -0
- package/tui/build/dev/javascript/gleam_version +1 -0
- package/tui/build/dev/javascript/prelude.mjs +1575 -0
- package/tui/build/dev/javascript/tui/_gleam_artefacts/tui.cache +0 -0
- package/tui/build/dev/javascript/tui/_gleam_artefacts/tui.cache_inline +0 -0
- package/tui/build/dev/javascript/tui/_gleam_artefacts/tui.cache_meta +0 -0
- package/tui/build/dev/javascript/tui/_gleam_artefacts/tui.cache_warnings +0 -0
- package/tui/build/dev/javascript/tui/_gleam_artefacts/tui@prompt.cache +0 -0
- package/tui/build/dev/javascript/tui/_gleam_artefacts/tui@prompt.cache_inline +0 -0
- package/tui/build/dev/javascript/tui/_gleam_artefacts/tui@prompt.cache_meta +0 -0
- package/tui/build/dev/javascript/tui/_gleam_artefacts/tui@prompt.cache_warnings +0 -0
- package/tui/build/dev/javascript/tui/gleam.mjs +1 -0
- package/tui/build/dev/javascript/tui/tui/prompt.mjs +521 -0
- package/tui/build/dev/javascript/tui/tui.mjs +334 -0
- package/tui/build/dev/javascript/tui/tui_ffi.mjs +32 -0
|
@@ -0,0 +1,1575 @@
|
|
|
1
|
+
export class CustomType {
|
|
2
|
+
withFields(fields) {
|
|
3
|
+
let properties = Object.keys(this).map((label) =>
|
|
4
|
+
label in fields ? fields[label] : this[label],
|
|
5
|
+
);
|
|
6
|
+
return new this.constructor(...properties);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class List {
|
|
11
|
+
static fromArray(array, tail) {
|
|
12
|
+
let t = tail || new Empty();
|
|
13
|
+
for (let i = array.length - 1; i >= 0; --i) {
|
|
14
|
+
t = new NonEmpty(array[i], t);
|
|
15
|
+
}
|
|
16
|
+
return t;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
[Symbol.iterator]() {
|
|
20
|
+
return new ListIterator(this);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
toArray() {
|
|
24
|
+
return [...this];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
atLeastLength(desired) {
|
|
28
|
+
let current = this;
|
|
29
|
+
while (desired-- > 0 && current) current = current.tail;
|
|
30
|
+
return current !== undefined;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
hasLength(desired) {
|
|
34
|
+
let current = this;
|
|
35
|
+
while (desired-- > 0 && current) current = current.tail;
|
|
36
|
+
return desired === -1 && current instanceof Empty;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
countLength() {
|
|
40
|
+
let current = this;
|
|
41
|
+
let length = 0;
|
|
42
|
+
while (current) {
|
|
43
|
+
current = current.tail;
|
|
44
|
+
length++;
|
|
45
|
+
}
|
|
46
|
+
return length - 1;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function prepend(element, tail) {
|
|
51
|
+
return new NonEmpty(element, tail);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function toList(elements, tail) {
|
|
55
|
+
return List.fromArray(elements, tail);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
class ListIterator {
|
|
59
|
+
#current;
|
|
60
|
+
|
|
61
|
+
constructor(current) {
|
|
62
|
+
this.#current = current;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
next() {
|
|
66
|
+
if (this.#current instanceof Empty) {
|
|
67
|
+
return { done: true };
|
|
68
|
+
} else {
|
|
69
|
+
let { head, tail } = this.#current;
|
|
70
|
+
this.#current = tail;
|
|
71
|
+
return { value: head, done: false };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export class Empty extends List {}
|
|
77
|
+
export const List$Empty = () => new Empty();
|
|
78
|
+
export const List$isEmpty = (value) => value instanceof Empty;
|
|
79
|
+
|
|
80
|
+
export class NonEmpty extends List {
|
|
81
|
+
constructor(head, tail) {
|
|
82
|
+
super();
|
|
83
|
+
this.head = head;
|
|
84
|
+
this.tail = tail;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
export const List$NonEmpty = (head, tail) => new NonEmpty(head, tail);
|
|
88
|
+
export const List$isNonEmpty = (value) => value instanceof NonEmpty;
|
|
89
|
+
|
|
90
|
+
export const List$NonEmpty$first = (value) => value.head;
|
|
91
|
+
export const List$NonEmpty$rest = (value) => value.tail;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* A bit array is a contiguous sequence of bits similar to Erlang's Binary type.
|
|
95
|
+
*/
|
|
96
|
+
export class BitArray {
|
|
97
|
+
/**
|
|
98
|
+
* The size in bits of this bit array's data.
|
|
99
|
+
*
|
|
100
|
+
* @type {number}
|
|
101
|
+
*/
|
|
102
|
+
bitSize;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* The size in bytes of this bit array's data. If this bit array doesn't store
|
|
106
|
+
* a whole number of bytes then this value is rounded up.
|
|
107
|
+
*
|
|
108
|
+
* @type {number}
|
|
109
|
+
*/
|
|
110
|
+
byteSize;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* The number of unused high bits in the first byte of this bit array's
|
|
114
|
+
* buffer prior to the start of its data. The value of any unused high bits is
|
|
115
|
+
* undefined.
|
|
116
|
+
*
|
|
117
|
+
* The bit offset will be in the range 0-7.
|
|
118
|
+
*
|
|
119
|
+
* @type {number}
|
|
120
|
+
*/
|
|
121
|
+
bitOffset;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* The raw bytes that hold this bit array's data.
|
|
125
|
+
*
|
|
126
|
+
* If `bitOffset` is not zero then there are unused high bits in the first
|
|
127
|
+
* byte of this buffer.
|
|
128
|
+
*
|
|
129
|
+
* If `bitOffset + bitSize` is not a multiple of 8 then there are unused low
|
|
130
|
+
* bits in the last byte of this buffer.
|
|
131
|
+
*
|
|
132
|
+
* @type {Uint8Array}
|
|
133
|
+
*/
|
|
134
|
+
rawBuffer;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Constructs a new bit array from a `Uint8Array`, an optional size in
|
|
138
|
+
* bits, and an optional bit offset.
|
|
139
|
+
*
|
|
140
|
+
* If no bit size is specified it is taken as `buffer.length * 8`, i.e. all
|
|
141
|
+
* bytes in the buffer make up the new bit array's data.
|
|
142
|
+
*
|
|
143
|
+
* If no bit offset is specified it defaults to zero, i.e. there are no unused
|
|
144
|
+
* high bits in the first byte of the buffer.
|
|
145
|
+
*
|
|
146
|
+
* @param {Uint8Array} buffer
|
|
147
|
+
* @param {number} [bitSize]
|
|
148
|
+
* @param {number} [bitOffset]
|
|
149
|
+
*/
|
|
150
|
+
constructor(buffer, bitSize, bitOffset) {
|
|
151
|
+
if (!(buffer instanceof Uint8Array)) {
|
|
152
|
+
throw globalThis.Error(
|
|
153
|
+
"BitArray can only be constructed from a Uint8Array",
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
this.bitSize = bitSize ?? buffer.length * 8;
|
|
158
|
+
this.byteSize = Math.trunc((this.bitSize + 7) / 8);
|
|
159
|
+
this.bitOffset = bitOffset ?? 0;
|
|
160
|
+
|
|
161
|
+
// Validate the bit size
|
|
162
|
+
if (this.bitSize < 0) {
|
|
163
|
+
throw globalThis.Error(`BitArray bit size is invalid: ${this.bitSize}`);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Validate the bit offset
|
|
167
|
+
if (this.bitOffset < 0 || this.bitOffset > 7) {
|
|
168
|
+
throw globalThis.Error(
|
|
169
|
+
`BitArray bit offset is invalid: ${this.bitOffset}`,
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Validate the length of the buffer
|
|
174
|
+
if (buffer.length !== Math.trunc((this.bitOffset + this.bitSize + 7) / 8)) {
|
|
175
|
+
throw globalThis.Error("BitArray buffer length is invalid");
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
this.rawBuffer = buffer;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Returns a specific byte in this bit array. If the byte index is out of
|
|
183
|
+
* range then `undefined` is returned.
|
|
184
|
+
*
|
|
185
|
+
* When returning the final byte of a bit array with a bit size that's not a
|
|
186
|
+
* multiple of 8, the content of the unused low bits are undefined.
|
|
187
|
+
*
|
|
188
|
+
* @param {number} index
|
|
189
|
+
* @returns {number | undefined}
|
|
190
|
+
*/
|
|
191
|
+
byteAt(index) {
|
|
192
|
+
if (index < 0 || index >= this.byteSize) {
|
|
193
|
+
return undefined;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return bitArrayByteAt(this.rawBuffer, this.bitOffset, index);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
equals(other) {
|
|
200
|
+
if (this.bitSize !== other.bitSize) {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const wholeByteCount = Math.trunc(this.bitSize / 8);
|
|
205
|
+
|
|
206
|
+
// If both bit offsets are zero do a byte-aligned equality check which is
|
|
207
|
+
// faster
|
|
208
|
+
if (this.bitOffset === 0 && other.bitOffset === 0) {
|
|
209
|
+
// Compare any whole bytes
|
|
210
|
+
for (let i = 0; i < wholeByteCount; i++) {
|
|
211
|
+
if (this.rawBuffer[i] !== other.rawBuffer[i]) {
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Compare any trailing bits, excluding unused low bits
|
|
217
|
+
const trailingBitsCount = this.bitSize % 8;
|
|
218
|
+
if (trailingBitsCount) {
|
|
219
|
+
const unusedLowBitCount = 8 - trailingBitsCount;
|
|
220
|
+
if (
|
|
221
|
+
this.rawBuffer[wholeByteCount] >> unusedLowBitCount !==
|
|
222
|
+
other.rawBuffer[wholeByteCount] >> unusedLowBitCount
|
|
223
|
+
) {
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
} else {
|
|
228
|
+
// Compare any whole bytes
|
|
229
|
+
for (let i = 0; i < wholeByteCount; i++) {
|
|
230
|
+
const a = bitArrayByteAt(this.rawBuffer, this.bitOffset, i);
|
|
231
|
+
const b = bitArrayByteAt(other.rawBuffer, other.bitOffset, i);
|
|
232
|
+
|
|
233
|
+
if (a !== b) {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Compare any trailing bits
|
|
239
|
+
const trailingBitsCount = this.bitSize % 8;
|
|
240
|
+
if (trailingBitsCount) {
|
|
241
|
+
const a = bitArrayByteAt(
|
|
242
|
+
this.rawBuffer,
|
|
243
|
+
this.bitOffset,
|
|
244
|
+
wholeByteCount,
|
|
245
|
+
);
|
|
246
|
+
const b = bitArrayByteAt(
|
|
247
|
+
other.rawBuffer,
|
|
248
|
+
other.bitOffset,
|
|
249
|
+
wholeByteCount,
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
const unusedLowBitCount = 8 - trailingBitsCount;
|
|
253
|
+
if (a >> unusedLowBitCount !== b >> unusedLowBitCount) {
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Returns this bit array's internal buffer.
|
|
264
|
+
*
|
|
265
|
+
* @deprecated Use `BitArray.byteAt()` or `BitArray.rawBuffer` instead.
|
|
266
|
+
*
|
|
267
|
+
* @returns {Uint8Array}
|
|
268
|
+
*/
|
|
269
|
+
get buffer() {
|
|
270
|
+
bitArrayPrintDeprecationWarning(
|
|
271
|
+
"buffer",
|
|
272
|
+
"Use BitArray.byteAt() or BitArray.rawBuffer instead",
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
if (this.bitOffset !== 0 || this.bitSize % 8 !== 0) {
|
|
276
|
+
throw new globalThis.Error(
|
|
277
|
+
"BitArray.buffer does not support unaligned bit arrays",
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return this.rawBuffer;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Returns the length in bytes of this bit array's internal buffer.
|
|
286
|
+
*
|
|
287
|
+
* @deprecated Use `BitArray.bitSize` or `BitArray.byteSize` instead.
|
|
288
|
+
*
|
|
289
|
+
* @returns {number}
|
|
290
|
+
*/
|
|
291
|
+
get length() {
|
|
292
|
+
bitArrayPrintDeprecationWarning(
|
|
293
|
+
"length",
|
|
294
|
+
"Use BitArray.bitSize or BitArray.byteSize instead",
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
if (this.bitOffset !== 0 || this.bitSize % 8 !== 0) {
|
|
298
|
+
throw new globalThis.Error(
|
|
299
|
+
"BitArray.length does not support unaligned bit arrays",
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return this.rawBuffer.length;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export const BitArray$BitArray = (buffer, bitSize, bitOffset) =>
|
|
308
|
+
new BitArray(buffer, bitSize, bitOffset);
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Returns the nth byte in the given buffer, after applying the specified bit
|
|
312
|
+
* offset. If the index is out of bounds then zero is returned.
|
|
313
|
+
*
|
|
314
|
+
* @param {Uint8Array} buffer
|
|
315
|
+
* @param {number} bitOffset
|
|
316
|
+
* @param {number} index
|
|
317
|
+
* @returns {number}
|
|
318
|
+
*/
|
|
319
|
+
function bitArrayByteAt(buffer, bitOffset, index) {
|
|
320
|
+
if (bitOffset === 0) {
|
|
321
|
+
return buffer[index] ?? 0;
|
|
322
|
+
} else {
|
|
323
|
+
const a = (buffer[index] << bitOffset) & 0xff;
|
|
324
|
+
const b = buffer[index + 1] >> (8 - bitOffset);
|
|
325
|
+
|
|
326
|
+
return a | b;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
export class UtfCodepoint {
|
|
331
|
+
constructor(value) {
|
|
332
|
+
this.value = value;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const isBitArrayDeprecationMessagePrinted = {};
|
|
337
|
+
function bitArrayPrintDeprecationWarning(name, message) {
|
|
338
|
+
if (isBitArrayDeprecationMessagePrinted[name]) {
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
console.warn(
|
|
343
|
+
`Deprecated BitArray.${name} property used in JavaScript FFI code. ${message}.`,
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
isBitArrayDeprecationMessagePrinted[name] = true;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Slices a bit array to produce a new bit array. If `end` is not supplied then
|
|
351
|
+
* all bits from `start` onward are returned.
|
|
352
|
+
*
|
|
353
|
+
* If the slice is out of bounds then an exception is thrown.
|
|
354
|
+
*
|
|
355
|
+
* @param {BitArray} bitArray
|
|
356
|
+
* @param {number} start
|
|
357
|
+
* @param {number} [end]
|
|
358
|
+
* @returns {BitArray}
|
|
359
|
+
*/
|
|
360
|
+
export function bitArraySlice(bitArray, start, end) {
|
|
361
|
+
end ??= bitArray.bitSize;
|
|
362
|
+
|
|
363
|
+
bitArrayValidateRange(bitArray, start, end);
|
|
364
|
+
|
|
365
|
+
// Handle zero-length slices
|
|
366
|
+
if (start === end) {
|
|
367
|
+
return new BitArray(new Uint8Array());
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Early return for slices that cover the whole bit array
|
|
371
|
+
if (start === 0 && end === bitArray.bitSize) {
|
|
372
|
+
return bitArray;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
start += bitArray.bitOffset;
|
|
376
|
+
end += bitArray.bitOffset;
|
|
377
|
+
|
|
378
|
+
const startByteIndex = Math.trunc(start / 8);
|
|
379
|
+
const endByteIndex = Math.trunc((end + 7) / 8);
|
|
380
|
+
const byteLength = endByteIndex - startByteIndex;
|
|
381
|
+
|
|
382
|
+
// Avoid creating a new Uint8Array if the view of the underlying ArrayBuffer
|
|
383
|
+
// is the same. This can occur when slicing off just the first or last bit of
|
|
384
|
+
// a bit array, i.e. when only the bit offset or bit size need to be updated.
|
|
385
|
+
let buffer;
|
|
386
|
+
if (startByteIndex === 0 && byteLength === bitArray.rawBuffer.byteLength) {
|
|
387
|
+
buffer = bitArray.rawBuffer;
|
|
388
|
+
} else {
|
|
389
|
+
buffer = new Uint8Array(
|
|
390
|
+
bitArray.rawBuffer.buffer,
|
|
391
|
+
bitArray.rawBuffer.byteOffset + startByteIndex,
|
|
392
|
+
byteLength,
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
return new BitArray(buffer, end - start, start % 8);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Interprets a slice of this bit array as a floating point number, either
|
|
401
|
+
* 32-bit or 64-bit, with the specified endianness.
|
|
402
|
+
*
|
|
403
|
+
* The value of `end - start` must be exactly 32 or 64, otherwise an exception
|
|
404
|
+
* will be thrown.
|
|
405
|
+
*
|
|
406
|
+
* @param {BitArray} bitArray
|
|
407
|
+
* @param {number} start
|
|
408
|
+
* @param {number} end
|
|
409
|
+
* @param {boolean} isBigEndian
|
|
410
|
+
* @returns {number}
|
|
411
|
+
*/
|
|
412
|
+
export function bitArraySliceToFloat(bitArray, start, end, isBigEndian) {
|
|
413
|
+
bitArrayValidateRange(bitArray, start, end);
|
|
414
|
+
|
|
415
|
+
const floatSize = end - start;
|
|
416
|
+
|
|
417
|
+
// Check size is valid
|
|
418
|
+
if (floatSize !== 16 && floatSize !== 32 && floatSize !== 64) {
|
|
419
|
+
const msg =
|
|
420
|
+
`Sized floats must be 16-bit, 32-bit or 64-bit, got size of ` +
|
|
421
|
+
`${floatSize} bits`;
|
|
422
|
+
throw new globalThis.Error(msg);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
start += bitArray.bitOffset;
|
|
426
|
+
|
|
427
|
+
const isStartByteAligned = start % 8 === 0;
|
|
428
|
+
|
|
429
|
+
// If the bit range is byte aligned then the float can be read directly out
|
|
430
|
+
// of the existing buffer
|
|
431
|
+
if (isStartByteAligned) {
|
|
432
|
+
const view = new DataView(
|
|
433
|
+
bitArray.rawBuffer.buffer,
|
|
434
|
+
bitArray.rawBuffer.byteOffset + start / 8,
|
|
435
|
+
);
|
|
436
|
+
|
|
437
|
+
if (floatSize === 64) {
|
|
438
|
+
return view.getFloat64(0, !isBigEndian);
|
|
439
|
+
} else if (floatSize === 32) {
|
|
440
|
+
return view.getFloat32(0, !isBigEndian);
|
|
441
|
+
} else if (floatSize === 16) {
|
|
442
|
+
return fp16UintToNumber(view.getUint16(0, !isBigEndian));
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// Copy the unaligned bytes into an aligned array so a DataView can be used
|
|
447
|
+
const alignedBytes = new Uint8Array(floatSize / 8);
|
|
448
|
+
const byteOffset = Math.trunc(start / 8);
|
|
449
|
+
for (let i = 0; i < alignedBytes.length; i++) {
|
|
450
|
+
alignedBytes[i] = bitArrayByteAt(
|
|
451
|
+
bitArray.rawBuffer,
|
|
452
|
+
start % 8,
|
|
453
|
+
byteOffset + i,
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Read the float out of the aligned buffer
|
|
458
|
+
const view = new DataView(alignedBytes.buffer);
|
|
459
|
+
if (floatSize === 64) {
|
|
460
|
+
return view.getFloat64(0, !isBigEndian);
|
|
461
|
+
} else if (floatSize === 32) {
|
|
462
|
+
return view.getFloat32(0, !isBigEndian);
|
|
463
|
+
} else {
|
|
464
|
+
return fp16UintToNumber(view.getUint16(0, !isBigEndian));
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Interprets a slice of this bit array as a signed or unsigned integer with the
|
|
470
|
+
* specified endianness.
|
|
471
|
+
*
|
|
472
|
+
* @param {BitArray} bitArray
|
|
473
|
+
* @param {number} start
|
|
474
|
+
* @param {number} end
|
|
475
|
+
* @param {boolean} isBigEndian
|
|
476
|
+
* @param {boolean} isSigned
|
|
477
|
+
* @returns {number}
|
|
478
|
+
*/
|
|
479
|
+
export function bitArraySliceToInt(
|
|
480
|
+
bitArray,
|
|
481
|
+
start,
|
|
482
|
+
end,
|
|
483
|
+
isBigEndian,
|
|
484
|
+
isSigned,
|
|
485
|
+
) {
|
|
486
|
+
bitArrayValidateRange(bitArray, start, end);
|
|
487
|
+
|
|
488
|
+
if (start === end) {
|
|
489
|
+
return 0;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
start += bitArray.bitOffset;
|
|
493
|
+
end += bitArray.bitOffset;
|
|
494
|
+
|
|
495
|
+
const isStartByteAligned = start % 8 === 0;
|
|
496
|
+
const isEndByteAligned = end % 8 === 0;
|
|
497
|
+
|
|
498
|
+
// If the slice is byte-aligned then there is no need to handle unaligned
|
|
499
|
+
// slices, meaning a simpler and faster implementation can be used instead
|
|
500
|
+
if (isStartByteAligned && isEndByteAligned) {
|
|
501
|
+
return intFromAlignedSlice(
|
|
502
|
+
bitArray,
|
|
503
|
+
start / 8,
|
|
504
|
+
end / 8,
|
|
505
|
+
isBigEndian,
|
|
506
|
+
isSigned,
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
const size = end - start;
|
|
511
|
+
|
|
512
|
+
const startByteIndex = Math.trunc(start / 8);
|
|
513
|
+
const endByteIndex = Math.trunc((end - 1) / 8);
|
|
514
|
+
|
|
515
|
+
// Handle the case of the slice being completely contained in a single byte
|
|
516
|
+
if (startByteIndex == endByteIndex) {
|
|
517
|
+
const mask = 0xff >> start % 8;
|
|
518
|
+
const unusedLowBitCount = (8 - (end % 8)) % 8;
|
|
519
|
+
|
|
520
|
+
let value =
|
|
521
|
+
(bitArray.rawBuffer[startByteIndex] & mask) >> unusedLowBitCount;
|
|
522
|
+
|
|
523
|
+
// For signed integers, if the high bit is set reinterpret as two's
|
|
524
|
+
// complement
|
|
525
|
+
if (isSigned) {
|
|
526
|
+
const highBit = 2 ** (size - 1);
|
|
527
|
+
if (value >= highBit) {
|
|
528
|
+
value -= highBit * 2;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
return value;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// The integer value to be read is not aligned and crosses at least one byte
|
|
536
|
+
// boundary in the input array
|
|
537
|
+
|
|
538
|
+
if (size <= 53) {
|
|
539
|
+
return intFromUnalignedSliceUsingNumber(
|
|
540
|
+
bitArray.rawBuffer,
|
|
541
|
+
start,
|
|
542
|
+
end,
|
|
543
|
+
isBigEndian,
|
|
544
|
+
isSigned,
|
|
545
|
+
);
|
|
546
|
+
} else {
|
|
547
|
+
return intFromUnalignedSliceUsingBigInt(
|
|
548
|
+
bitArray.rawBuffer,
|
|
549
|
+
start,
|
|
550
|
+
end,
|
|
551
|
+
isBigEndian,
|
|
552
|
+
isSigned,
|
|
553
|
+
);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* Joins the given segments into a new bit array, tightly packing them together.
|
|
559
|
+
* Each segment must be one of the following types:
|
|
560
|
+
*
|
|
561
|
+
* - A `number`: A single byte value in the range 0-255. Values outside this
|
|
562
|
+
* range will be wrapped.
|
|
563
|
+
* - A `Uint8Array`: A sequence of byte values of any length.
|
|
564
|
+
* - A `BitArray`: A sequence of bits of any length, which may not be byte
|
|
565
|
+
* aligned.
|
|
566
|
+
*
|
|
567
|
+
* The bit size of the returned bit array will be the sum of the size in bits
|
|
568
|
+
* of the input segments.
|
|
569
|
+
*
|
|
570
|
+
* @param {(number | Uint8Array | BitArray)[]} segments
|
|
571
|
+
* @returns {BitArray}
|
|
572
|
+
*/
|
|
573
|
+
export function toBitArray(segments) {
|
|
574
|
+
if (segments.length === 0) {
|
|
575
|
+
return new BitArray(new Uint8Array());
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
if (segments.length === 1) {
|
|
579
|
+
const segment = segments[0];
|
|
580
|
+
|
|
581
|
+
// When there is a single BitArray segment it can be returned as-is
|
|
582
|
+
if (segment instanceof BitArray) {
|
|
583
|
+
return segment;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// When there is a single Uint8Array segment, pass it directly to the bit
|
|
587
|
+
// array constructor to avoid a copy
|
|
588
|
+
if (segment instanceof Uint8Array) {
|
|
589
|
+
return new BitArray(segment);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
return new BitArray(new Uint8Array(/** @type {number[]} */ (segments)));
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// Count the total number of bits and check if all segments are numbers, i.e.
|
|
596
|
+
// single bytes
|
|
597
|
+
let bitSize = 0;
|
|
598
|
+
let areAllSegmentsNumbers = true;
|
|
599
|
+
for (const segment of segments) {
|
|
600
|
+
if (segment instanceof BitArray) {
|
|
601
|
+
bitSize += segment.bitSize;
|
|
602
|
+
areAllSegmentsNumbers = false;
|
|
603
|
+
} else if (segment instanceof Uint8Array) {
|
|
604
|
+
bitSize += segment.byteLength * 8;
|
|
605
|
+
areAllSegmentsNumbers = false;
|
|
606
|
+
} else {
|
|
607
|
+
bitSize += 8;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// If all segments are numbers then pass the segments array directly to the
|
|
612
|
+
// Uint8Array constructor
|
|
613
|
+
if (areAllSegmentsNumbers) {
|
|
614
|
+
return new BitArray(new Uint8Array(/** @type {number[]} */ (segments)));
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// Pack the segments into a Uint8Array
|
|
618
|
+
const buffer = new Uint8Array(Math.trunc((bitSize + 7) / 8));
|
|
619
|
+
|
|
620
|
+
// The current write position in bits into the above array. Byte-aligned
|
|
621
|
+
// segments, i.e. when the cursor is a multiple of 8, are able to be processed
|
|
622
|
+
// faster due to being able to copy bytes directly.
|
|
623
|
+
let cursor = 0;
|
|
624
|
+
|
|
625
|
+
for (let segment of segments) {
|
|
626
|
+
const isCursorByteAligned = cursor % 8 === 0;
|
|
627
|
+
|
|
628
|
+
if (segment instanceof BitArray) {
|
|
629
|
+
if (isCursorByteAligned && segment.bitOffset === 0) {
|
|
630
|
+
buffer.set(segment.rawBuffer, cursor / 8);
|
|
631
|
+
cursor += segment.bitSize;
|
|
632
|
+
|
|
633
|
+
// Zero any unused bits in the last byte of the buffer. Their content is
|
|
634
|
+
// undefined and shouldn't be included in the output.
|
|
635
|
+
const trailingBitsCount = segment.bitSize % 8;
|
|
636
|
+
if (trailingBitsCount !== 0) {
|
|
637
|
+
const lastByteIndex = Math.trunc(cursor / 8);
|
|
638
|
+
buffer[lastByteIndex] >>= 8 - trailingBitsCount;
|
|
639
|
+
buffer[lastByteIndex] <<= 8 - trailingBitsCount;
|
|
640
|
+
}
|
|
641
|
+
} else {
|
|
642
|
+
appendUnalignedBits(
|
|
643
|
+
segment.rawBuffer,
|
|
644
|
+
segment.bitSize,
|
|
645
|
+
segment.bitOffset,
|
|
646
|
+
);
|
|
647
|
+
}
|
|
648
|
+
} else if (segment instanceof Uint8Array) {
|
|
649
|
+
if (isCursorByteAligned) {
|
|
650
|
+
buffer.set(segment, cursor / 8);
|
|
651
|
+
cursor += segment.byteLength * 8;
|
|
652
|
+
} else {
|
|
653
|
+
appendUnalignedBits(segment, segment.byteLength * 8, 0);
|
|
654
|
+
}
|
|
655
|
+
} else {
|
|
656
|
+
if (isCursorByteAligned) {
|
|
657
|
+
buffer[cursor / 8] = segment;
|
|
658
|
+
cursor += 8;
|
|
659
|
+
} else {
|
|
660
|
+
appendUnalignedBits(new Uint8Array([segment]), 8, 0);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
function appendUnalignedBits(unalignedBits, size, offset) {
|
|
666
|
+
if (size === 0) {
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
const byteSize = Math.trunc(size + 7 / 8);
|
|
671
|
+
|
|
672
|
+
const highBitsCount = cursor % 8;
|
|
673
|
+
const lowBitsCount = 8 - highBitsCount;
|
|
674
|
+
|
|
675
|
+
let byteIndex = Math.trunc(cursor / 8);
|
|
676
|
+
|
|
677
|
+
for (let i = 0; i < byteSize; i++) {
|
|
678
|
+
let byte = bitArrayByteAt(unalignedBits, offset, i);
|
|
679
|
+
|
|
680
|
+
// If this is a partial byte then zero out the trailing bits as their
|
|
681
|
+
// content is undefined and shouldn't be included in the output
|
|
682
|
+
if (size < 8) {
|
|
683
|
+
byte >>= 8 - size;
|
|
684
|
+
byte <<= 8 - size;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// Copy the high bits of the input byte to the low bits of the current
|
|
688
|
+
// output byte
|
|
689
|
+
buffer[byteIndex] |= byte >> highBitsCount;
|
|
690
|
+
|
|
691
|
+
let appendedBitsCount = size - Math.max(0, size - lowBitsCount);
|
|
692
|
+
size -= appendedBitsCount;
|
|
693
|
+
cursor += appendedBitsCount;
|
|
694
|
+
|
|
695
|
+
if (size === 0) {
|
|
696
|
+
break;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
// Copy the low bits of the input byte to the high bits of the next output
|
|
700
|
+
// byte
|
|
701
|
+
buffer[++byteIndex] = byte << lowBitsCount;
|
|
702
|
+
appendedBitsCount = size - Math.max(0, size - highBitsCount);
|
|
703
|
+
size -= appendedBitsCount;
|
|
704
|
+
cursor += appendedBitsCount;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
return new BitArray(buffer, bitSize);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
/**
|
|
712
|
+
* Encodes a floating point value into a `Uint8Array`. This is used to create
|
|
713
|
+
* float segments that are part of bit array expressions.
|
|
714
|
+
*
|
|
715
|
+
* @param {number} value
|
|
716
|
+
* @param {number} size
|
|
717
|
+
* @param {boolean} isBigEndian
|
|
718
|
+
* @returns {Uint8Array}
|
|
719
|
+
*/
|
|
720
|
+
export function sizedFloat(value, size, isBigEndian) {
|
|
721
|
+
if (size !== 16 && size !== 32 && size !== 64) {
|
|
722
|
+
const msg = `Sized floats must be 16-bit, 32-bit or 64-bit, got size of ${size} bits`;
|
|
723
|
+
throw new globalThis.Error(msg);
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
if (size === 16) {
|
|
727
|
+
return numberToFp16Uint(value, isBigEndian);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
const buffer = new Uint8Array(size / 8);
|
|
731
|
+
|
|
732
|
+
const view = new DataView(buffer.buffer);
|
|
733
|
+
|
|
734
|
+
if (size == 64) {
|
|
735
|
+
view.setFloat64(0, value, !isBigEndian);
|
|
736
|
+
} else {
|
|
737
|
+
view.setFloat32(0, value, !isBigEndian);
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
return buffer;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
/**
|
|
744
|
+
* Encodes an integer value into a `Uint8Array`, or a `BitArray` if the size in
|
|
745
|
+
* bits is not a multiple of 8. This is used to create integer segments used in
|
|
746
|
+
* bit array expressions.
|
|
747
|
+
*
|
|
748
|
+
* @param {number} value
|
|
749
|
+
* @param {number} size
|
|
750
|
+
* @param {boolean} isBigEndian
|
|
751
|
+
* @returns {Uint8Array | BitArray}
|
|
752
|
+
*/
|
|
753
|
+
export function sizedInt(value, size, isBigEndian) {
|
|
754
|
+
if (size <= 0) {
|
|
755
|
+
return new Uint8Array();
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
// Fast path when size is 8 bits. This relies on the rounding behavior of the
|
|
759
|
+
// Uint8Array constructor.
|
|
760
|
+
if (size === 8) {
|
|
761
|
+
return new Uint8Array([value]);
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
// Fast path when size is less than 8 bits: shift the value up to the high
|
|
765
|
+
// bits
|
|
766
|
+
if (size < 8) {
|
|
767
|
+
value <<= 8 - size;
|
|
768
|
+
return new BitArray(new Uint8Array([value]), size);
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
// Allocate output buffer
|
|
772
|
+
const buffer = new Uint8Array(Math.trunc((size + 7) / 8));
|
|
773
|
+
|
|
774
|
+
// The number of trailing bits in the final byte. Will be zero if the size is
|
|
775
|
+
// an exact number of bytes.
|
|
776
|
+
const trailingBitsCount = size % 8;
|
|
777
|
+
|
|
778
|
+
// The number of unused bits in the final byte of the buffer
|
|
779
|
+
const unusedBitsCount = 8 - trailingBitsCount;
|
|
780
|
+
|
|
781
|
+
// For output sizes not exceeding 32 bits the number type is used. For larger
|
|
782
|
+
// output sizes the BigInt type is needed.
|
|
783
|
+
//
|
|
784
|
+
// The code in each of these two paths must be kept in sync.
|
|
785
|
+
if (size <= 32) {
|
|
786
|
+
if (isBigEndian) {
|
|
787
|
+
let i = buffer.length - 1;
|
|
788
|
+
|
|
789
|
+
// Set the trailing bits at the end of the output buffer
|
|
790
|
+
if (trailingBitsCount) {
|
|
791
|
+
buffer[i--] = (value << unusedBitsCount) & 0xff;
|
|
792
|
+
value >>= trailingBitsCount;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
for (; i >= 0; i--) {
|
|
796
|
+
buffer[i] = value;
|
|
797
|
+
value >>= 8;
|
|
798
|
+
}
|
|
799
|
+
} else {
|
|
800
|
+
let i = 0;
|
|
801
|
+
|
|
802
|
+
const wholeByteCount = Math.trunc(size / 8);
|
|
803
|
+
for (; i < wholeByteCount; i++) {
|
|
804
|
+
buffer[i] = value;
|
|
805
|
+
value >>= 8;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
// Set the trailing bits at the end of the output buffer
|
|
809
|
+
if (trailingBitsCount) {
|
|
810
|
+
buffer[i] = value << unusedBitsCount;
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
} else {
|
|
814
|
+
const bigTrailingBitsCount = BigInt(trailingBitsCount);
|
|
815
|
+
const bigUnusedBitsCount = BigInt(unusedBitsCount);
|
|
816
|
+
|
|
817
|
+
let bigValue = BigInt(value);
|
|
818
|
+
|
|
819
|
+
if (isBigEndian) {
|
|
820
|
+
let i = buffer.length - 1;
|
|
821
|
+
|
|
822
|
+
// Set the trailing bits at the end of the output buffer
|
|
823
|
+
if (trailingBitsCount) {
|
|
824
|
+
buffer[i--] = Number(bigValue << bigUnusedBitsCount);
|
|
825
|
+
bigValue >>= bigTrailingBitsCount;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
for (; i >= 0; i--) {
|
|
829
|
+
buffer[i] = Number(bigValue);
|
|
830
|
+
bigValue >>= 8n;
|
|
831
|
+
}
|
|
832
|
+
} else {
|
|
833
|
+
let i = 0;
|
|
834
|
+
|
|
835
|
+
const wholeByteCount = Math.trunc(size / 8);
|
|
836
|
+
for (; i < wholeByteCount; i++) {
|
|
837
|
+
buffer[i] = Number(bigValue);
|
|
838
|
+
bigValue >>= 8n;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
// Set the trailing bits at the end of the output buffer
|
|
842
|
+
if (trailingBitsCount) {
|
|
843
|
+
buffer[i] = Number(bigValue << bigUnusedBitsCount);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
// Integers that aren't a whole number of bytes are returned as a BitArray so
|
|
849
|
+
// their size in bits is tracked
|
|
850
|
+
if (trailingBitsCount) {
|
|
851
|
+
return new BitArray(buffer, size);
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
return buffer;
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
/**
|
|
858
|
+
* Reads an aligned slice of any size as an integer.
|
|
859
|
+
*
|
|
860
|
+
* @param {BitArray} bitArray
|
|
861
|
+
* @param {number} start
|
|
862
|
+
* @param {number} end
|
|
863
|
+
* @param {boolean} isBigEndian
|
|
864
|
+
* @param {boolean} isSigned
|
|
865
|
+
* @returns {number}
|
|
866
|
+
*/
|
|
867
|
+
function intFromAlignedSlice(bitArray, start, end, isBigEndian, isSigned) {
|
|
868
|
+
const byteSize = end - start;
|
|
869
|
+
|
|
870
|
+
if (byteSize <= 6) {
|
|
871
|
+
return intFromAlignedSliceUsingNumber(
|
|
872
|
+
bitArray.rawBuffer,
|
|
873
|
+
start,
|
|
874
|
+
end,
|
|
875
|
+
isBigEndian,
|
|
876
|
+
isSigned,
|
|
877
|
+
);
|
|
878
|
+
} else {
|
|
879
|
+
return intFromAlignedSliceUsingBigInt(
|
|
880
|
+
bitArray.rawBuffer,
|
|
881
|
+
start,
|
|
882
|
+
end,
|
|
883
|
+
isBigEndian,
|
|
884
|
+
isSigned,
|
|
885
|
+
);
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
/**
|
|
890
|
+
* Reads an aligned slice up to 48 bits in size as an integer. Uses the
|
|
891
|
+
* JavaScript `number` type internally.
|
|
892
|
+
*
|
|
893
|
+
* @param {Uint8Array} buffer
|
|
894
|
+
* @param {number} start
|
|
895
|
+
* @param {number} end
|
|
896
|
+
* @param {boolean} isBigEndian
|
|
897
|
+
* @param {boolean} isSigned
|
|
898
|
+
* @returns {number}
|
|
899
|
+
*/
|
|
900
|
+
function intFromAlignedSliceUsingNumber(
|
|
901
|
+
buffer,
|
|
902
|
+
start,
|
|
903
|
+
end,
|
|
904
|
+
isBigEndian,
|
|
905
|
+
isSigned,
|
|
906
|
+
) {
|
|
907
|
+
const byteSize = end - start;
|
|
908
|
+
|
|
909
|
+
let value = 0;
|
|
910
|
+
|
|
911
|
+
// Read bytes as an unsigned integer
|
|
912
|
+
if (isBigEndian) {
|
|
913
|
+
for (let i = start; i < end; i++) {
|
|
914
|
+
value *= 256;
|
|
915
|
+
value += buffer[i];
|
|
916
|
+
}
|
|
917
|
+
} else {
|
|
918
|
+
for (let i = end - 1; i >= start; i--) {
|
|
919
|
+
value *= 256;
|
|
920
|
+
value += buffer[i];
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
// For signed integers, if the high bit is set reinterpret as two's
|
|
925
|
+
// complement
|
|
926
|
+
if (isSigned) {
|
|
927
|
+
const highBit = 2 ** (byteSize * 8 - 1);
|
|
928
|
+
if (value >= highBit) {
|
|
929
|
+
value -= highBit * 2;
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
return value;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
/**
|
|
937
|
+
* Reads an aligned slice of any size as an integer. Uses the JavaScript
|
|
938
|
+
* `BigInt` type internally.
|
|
939
|
+
*
|
|
940
|
+
* @param {Uint8Array} buffer
|
|
941
|
+
* @param {number} start
|
|
942
|
+
* @param {number} end
|
|
943
|
+
* @param {boolean} isBigEndian
|
|
944
|
+
* @param {boolean} isSigned
|
|
945
|
+
* @returns {number}
|
|
946
|
+
*/
|
|
947
|
+
function intFromAlignedSliceUsingBigInt(
|
|
948
|
+
buffer,
|
|
949
|
+
start,
|
|
950
|
+
end,
|
|
951
|
+
isBigEndian,
|
|
952
|
+
isSigned,
|
|
953
|
+
) {
|
|
954
|
+
const byteSize = end - start;
|
|
955
|
+
|
|
956
|
+
let value = 0n;
|
|
957
|
+
|
|
958
|
+
// Read bytes as an unsigned integer value
|
|
959
|
+
if (isBigEndian) {
|
|
960
|
+
for (let i = start; i < end; i++) {
|
|
961
|
+
value *= 256n;
|
|
962
|
+
value += BigInt(buffer[i]);
|
|
963
|
+
}
|
|
964
|
+
} else {
|
|
965
|
+
for (let i = end - 1; i >= start; i--) {
|
|
966
|
+
value *= 256n;
|
|
967
|
+
value += BigInt(buffer[i]);
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
// For signed integers, if the high bit is set reinterpret as two's
|
|
972
|
+
// complement
|
|
973
|
+
if (isSigned) {
|
|
974
|
+
const highBit = 1n << BigInt(byteSize * 8 - 1);
|
|
975
|
+
if (value >= highBit) {
|
|
976
|
+
value -= highBit * 2n;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
// Convert the result into a JS number. This may cause quantizing/error on
|
|
981
|
+
// values outside JavaScript's safe integer range.
|
|
982
|
+
return Number(value);
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
/**
|
|
986
|
+
* Reads an unaligned slice up to 53 bits in size as an integer. Uses the
|
|
987
|
+
* JavaScript `number` type internally.
|
|
988
|
+
*
|
|
989
|
+
* This function assumes that the slice crosses at least one byte boundary in
|
|
990
|
+
* the input.
|
|
991
|
+
*
|
|
992
|
+
* @param {Uint8Array} buffer
|
|
993
|
+
* @param {number} start
|
|
994
|
+
* @param {number} end
|
|
995
|
+
* @param {boolean} isBigEndian
|
|
996
|
+
* @param {boolean} isSigned
|
|
997
|
+
* @returns {number}
|
|
998
|
+
*/
|
|
999
|
+
function intFromUnalignedSliceUsingNumber(
|
|
1000
|
+
buffer,
|
|
1001
|
+
start,
|
|
1002
|
+
end,
|
|
1003
|
+
isBigEndian,
|
|
1004
|
+
isSigned,
|
|
1005
|
+
) {
|
|
1006
|
+
const isStartByteAligned = start % 8 === 0;
|
|
1007
|
+
|
|
1008
|
+
let size = end - start;
|
|
1009
|
+
let byteIndex = Math.trunc(start / 8);
|
|
1010
|
+
|
|
1011
|
+
let value = 0;
|
|
1012
|
+
|
|
1013
|
+
if (isBigEndian) {
|
|
1014
|
+
// Read any leading bits
|
|
1015
|
+
if (!isStartByteAligned) {
|
|
1016
|
+
const leadingBitsCount = 8 - (start % 8);
|
|
1017
|
+
value = buffer[byteIndex++] & ((1 << leadingBitsCount) - 1);
|
|
1018
|
+
size -= leadingBitsCount;
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
// Read any whole bytes
|
|
1022
|
+
while (size >= 8) {
|
|
1023
|
+
value *= 256;
|
|
1024
|
+
value += buffer[byteIndex++];
|
|
1025
|
+
size -= 8;
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
// Read any trailing bits
|
|
1029
|
+
if (size > 0) {
|
|
1030
|
+
value *= 2 ** size;
|
|
1031
|
+
value += buffer[byteIndex] >> (8 - size);
|
|
1032
|
+
}
|
|
1033
|
+
} else {
|
|
1034
|
+
// For little endian, if the start is aligned then whole bytes can be read
|
|
1035
|
+
// directly out of the input array, with the trailing bits handled at the
|
|
1036
|
+
// end
|
|
1037
|
+
if (isStartByteAligned) {
|
|
1038
|
+
let size = end - start;
|
|
1039
|
+
let scale = 1;
|
|
1040
|
+
|
|
1041
|
+
// Read whole bytes
|
|
1042
|
+
while (size >= 8) {
|
|
1043
|
+
value += buffer[byteIndex++] * scale;
|
|
1044
|
+
scale *= 256;
|
|
1045
|
+
size -= 8;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
// Read trailing bits
|
|
1049
|
+
value += (buffer[byteIndex] >> (8 - size)) * scale;
|
|
1050
|
+
} else {
|
|
1051
|
+
// Read little endian data where the start is not byte-aligned. This is
|
|
1052
|
+
// done by reading whole bytes that cross a byte boundary in the input
|
|
1053
|
+
// data, then reading any trailing bits.
|
|
1054
|
+
|
|
1055
|
+
const highBitsCount = start % 8;
|
|
1056
|
+
const lowBitsCount = 8 - highBitsCount;
|
|
1057
|
+
|
|
1058
|
+
let size = end - start;
|
|
1059
|
+
let scale = 1;
|
|
1060
|
+
|
|
1061
|
+
// Extract whole bytes
|
|
1062
|
+
while (size >= 8) {
|
|
1063
|
+
const byte =
|
|
1064
|
+
(buffer[byteIndex] << highBitsCount) |
|
|
1065
|
+
(buffer[byteIndex + 1] >> lowBitsCount);
|
|
1066
|
+
|
|
1067
|
+
value += (byte & 0xff) * scale;
|
|
1068
|
+
|
|
1069
|
+
scale *= 256;
|
|
1070
|
+
size -= 8;
|
|
1071
|
+
byteIndex++;
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
// Read any trailing bits. These trailing bits may cross a byte boundary
|
|
1075
|
+
// in the input buffer.
|
|
1076
|
+
if (size > 0) {
|
|
1077
|
+
const lowBitsUsed = size - Math.max(0, size - lowBitsCount);
|
|
1078
|
+
|
|
1079
|
+
let trailingByte =
|
|
1080
|
+
(buffer[byteIndex] & ((1 << lowBitsCount) - 1)) >>
|
|
1081
|
+
(lowBitsCount - lowBitsUsed);
|
|
1082
|
+
|
|
1083
|
+
size -= lowBitsUsed;
|
|
1084
|
+
|
|
1085
|
+
if (size > 0) {
|
|
1086
|
+
trailingByte *= 2 ** size;
|
|
1087
|
+
trailingByte += buffer[byteIndex + 1] >> (8 - size);
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
value += trailingByte * scale;
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
// For signed integers, if the high bit is set reinterpret as two's
|
|
1096
|
+
// complement
|
|
1097
|
+
if (isSigned) {
|
|
1098
|
+
const highBit = 2 ** (end - start - 1);
|
|
1099
|
+
if (value >= highBit) {
|
|
1100
|
+
value -= highBit * 2;
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
return value;
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
/**
|
|
1108
|
+
* Reads an unaligned slice of any size as an integer. Uses the JavaScript
|
|
1109
|
+
* `BigInt` type internally.
|
|
1110
|
+
*
|
|
1111
|
+
* This function assumes that the slice crosses at least one byte boundary in
|
|
1112
|
+
* the input.
|
|
1113
|
+
*
|
|
1114
|
+
* @param {Uint8Array} buffer
|
|
1115
|
+
* @param {number} start
|
|
1116
|
+
* @param {number} end
|
|
1117
|
+
* @param {boolean} isBigEndian
|
|
1118
|
+
* @param {boolean} isSigned
|
|
1119
|
+
* @returns {number}
|
|
1120
|
+
*/
|
|
1121
|
+
function intFromUnalignedSliceUsingBigInt(
|
|
1122
|
+
buffer,
|
|
1123
|
+
start,
|
|
1124
|
+
end,
|
|
1125
|
+
isBigEndian,
|
|
1126
|
+
isSigned,
|
|
1127
|
+
) {
|
|
1128
|
+
const isStartByteAligned = start % 8 === 0;
|
|
1129
|
+
|
|
1130
|
+
let size = end - start;
|
|
1131
|
+
let byteIndex = Math.trunc(start / 8);
|
|
1132
|
+
|
|
1133
|
+
let value = 0n;
|
|
1134
|
+
|
|
1135
|
+
if (isBigEndian) {
|
|
1136
|
+
// Read any leading bits
|
|
1137
|
+
if (!isStartByteAligned) {
|
|
1138
|
+
const leadingBitsCount = 8 - (start % 8);
|
|
1139
|
+
value = BigInt(buffer[byteIndex++] & ((1 << leadingBitsCount) - 1));
|
|
1140
|
+
size -= leadingBitsCount;
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
// Read any whole bytes
|
|
1144
|
+
while (size >= 8) {
|
|
1145
|
+
value *= 256n;
|
|
1146
|
+
value += BigInt(buffer[byteIndex++]);
|
|
1147
|
+
size -= 8;
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
// Read any trailing bits
|
|
1151
|
+
if (size > 0) {
|
|
1152
|
+
value <<= BigInt(size);
|
|
1153
|
+
value += BigInt(buffer[byteIndex] >> (8 - size));
|
|
1154
|
+
}
|
|
1155
|
+
} else {
|
|
1156
|
+
// For little endian, if the start is aligned then whole bytes can be read
|
|
1157
|
+
// directly out of the input array, with the trailing bits handled at the
|
|
1158
|
+
// end
|
|
1159
|
+
if (isStartByteAligned) {
|
|
1160
|
+
let size = end - start;
|
|
1161
|
+
let shift = 0n;
|
|
1162
|
+
|
|
1163
|
+
// Read whole bytes
|
|
1164
|
+
while (size >= 8) {
|
|
1165
|
+
value += BigInt(buffer[byteIndex++]) << shift;
|
|
1166
|
+
shift += 8n;
|
|
1167
|
+
size -= 8;
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
// Read trailing bits
|
|
1171
|
+
value += BigInt(buffer[byteIndex] >> (8 - size)) << shift;
|
|
1172
|
+
} else {
|
|
1173
|
+
// Read little endian data where the start is not byte-aligned. This is
|
|
1174
|
+
// done by reading whole bytes that cross a byte boundary in the input
|
|
1175
|
+
// data, then reading any trailing bits.
|
|
1176
|
+
|
|
1177
|
+
const highBitsCount = start % 8;
|
|
1178
|
+
const lowBitsCount = 8 - highBitsCount;
|
|
1179
|
+
|
|
1180
|
+
let size = end - start;
|
|
1181
|
+
let shift = 0n;
|
|
1182
|
+
|
|
1183
|
+
// Extract whole bytes
|
|
1184
|
+
while (size >= 8) {
|
|
1185
|
+
const byte =
|
|
1186
|
+
(buffer[byteIndex] << highBitsCount) |
|
|
1187
|
+
(buffer[byteIndex + 1] >> lowBitsCount);
|
|
1188
|
+
|
|
1189
|
+
value += BigInt(byte & 0xff) << shift;
|
|
1190
|
+
|
|
1191
|
+
shift += 8n;
|
|
1192
|
+
size -= 8;
|
|
1193
|
+
byteIndex++;
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
// Read any trailing bits. These trailing bits may cross a byte boundary
|
|
1197
|
+
// in the input buffer.
|
|
1198
|
+
if (size > 0) {
|
|
1199
|
+
const lowBitsUsed = size - Math.max(0, size - lowBitsCount);
|
|
1200
|
+
|
|
1201
|
+
let trailingByte =
|
|
1202
|
+
(buffer[byteIndex] & ((1 << lowBitsCount) - 1)) >>
|
|
1203
|
+
(lowBitsCount - lowBitsUsed);
|
|
1204
|
+
|
|
1205
|
+
size -= lowBitsUsed;
|
|
1206
|
+
|
|
1207
|
+
if (size > 0) {
|
|
1208
|
+
trailingByte <<= size;
|
|
1209
|
+
trailingByte += buffer[byteIndex + 1] >> (8 - size);
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
value += BigInt(trailingByte) << shift;
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
// For signed integers, if the high bit is set reinterpret as two's
|
|
1218
|
+
// complement
|
|
1219
|
+
if (isSigned) {
|
|
1220
|
+
const highBit = 2n ** BigInt(end - start - 1);
|
|
1221
|
+
if (value >= highBit) {
|
|
1222
|
+
value -= highBit * 2n;
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
// Convert the result into a JS number. This may cause quantizing/error on
|
|
1227
|
+
// values outside JavaScript's safe integer range.
|
|
1228
|
+
return Number(value);
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
/**
|
|
1232
|
+
* Interprets a 16-bit unsigned integer value as a 16-bit floating point value.
|
|
1233
|
+
*
|
|
1234
|
+
* @param {number} intValue
|
|
1235
|
+
* @returns {number}
|
|
1236
|
+
*/
|
|
1237
|
+
function fp16UintToNumber(intValue) {
|
|
1238
|
+
const sign = intValue >= 0x8000 ? -1 : 1;
|
|
1239
|
+
const exponent = (intValue & 0x7c00) >> 10;
|
|
1240
|
+
const fraction = intValue & 0x03ff;
|
|
1241
|
+
|
|
1242
|
+
let value;
|
|
1243
|
+
if (exponent === 0) {
|
|
1244
|
+
value = 6.103515625e-5 * (fraction / 0x400);
|
|
1245
|
+
} else if (exponent === 0x1f) {
|
|
1246
|
+
value = fraction === 0 ? Infinity : NaN;
|
|
1247
|
+
} else {
|
|
1248
|
+
value = Math.pow(2, exponent - 15) * (1 + fraction / 0x400);
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
return sign * value;
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
/**
|
|
1255
|
+
* Converts a floating point number to bytes for a 16-bit floating point value.
|
|
1256
|
+
*
|
|
1257
|
+
* @param {number} intValue
|
|
1258
|
+
* @param {boolean} isBigEndian
|
|
1259
|
+
* @returns {Uint8Array}
|
|
1260
|
+
*/
|
|
1261
|
+
function numberToFp16Uint(value, isBigEndian) {
|
|
1262
|
+
const buffer = new Uint8Array(2);
|
|
1263
|
+
|
|
1264
|
+
if (isNaN(value)) {
|
|
1265
|
+
buffer[1] = 0x7e;
|
|
1266
|
+
} else if (value === Infinity) {
|
|
1267
|
+
buffer[1] = 0x7c;
|
|
1268
|
+
} else if (value === -Infinity) {
|
|
1269
|
+
buffer[1] = 0xfc;
|
|
1270
|
+
} else if (value === 0) {
|
|
1271
|
+
// Both values are already zero
|
|
1272
|
+
} else {
|
|
1273
|
+
const sign = value < 0 ? 1 : 0;
|
|
1274
|
+
value = Math.abs(value);
|
|
1275
|
+
|
|
1276
|
+
let exponent = Math.floor(Math.log2(value));
|
|
1277
|
+
let fraction = value / Math.pow(2, exponent) - 1;
|
|
1278
|
+
|
|
1279
|
+
exponent += 15;
|
|
1280
|
+
|
|
1281
|
+
if (exponent <= 0) {
|
|
1282
|
+
exponent = 0;
|
|
1283
|
+
fraction = value / Math.pow(2, -14);
|
|
1284
|
+
} else if (exponent >= 31) {
|
|
1285
|
+
exponent = 31;
|
|
1286
|
+
fraction = 0;
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
fraction = Math.round(fraction * 1024);
|
|
1290
|
+
|
|
1291
|
+
buffer[1] =
|
|
1292
|
+
(sign << 7) | ((exponent & 0x1f) << 2) | ((fraction >> 8) & 0x03);
|
|
1293
|
+
buffer[0] = fraction & 0xff;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
if (isBigEndian) {
|
|
1297
|
+
const a = buffer[0];
|
|
1298
|
+
buffer[0] = buffer[1];
|
|
1299
|
+
buffer[1] = a;
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
return buffer;
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
/**
|
|
1306
|
+
* Throws an exception if the given start and end values are out of bounds for
|
|
1307
|
+
* a bit array.
|
|
1308
|
+
*
|
|
1309
|
+
* @param {BitArray} bitArray
|
|
1310
|
+
* @param {number} start
|
|
1311
|
+
* @param {number} end
|
|
1312
|
+
*/
|
|
1313
|
+
function bitArrayValidateRange(bitArray, start, end) {
|
|
1314
|
+
if (
|
|
1315
|
+
start < 0 ||
|
|
1316
|
+
start > bitArray.bitSize ||
|
|
1317
|
+
end < start ||
|
|
1318
|
+
end > bitArray.bitSize
|
|
1319
|
+
) {
|
|
1320
|
+
const msg =
|
|
1321
|
+
`Invalid bit array slice: start = ${start}, end = ${end}, ` +
|
|
1322
|
+
`bit size = ${bitArray.bitSize}`;
|
|
1323
|
+
throw new globalThis.Error(msg);
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
/** @type {TextEncoder | undefined} */
|
|
1328
|
+
let utf8Encoder;
|
|
1329
|
+
|
|
1330
|
+
/**
|
|
1331
|
+
* Returns the UTF-8 bytes for a string.
|
|
1332
|
+
*
|
|
1333
|
+
* @param {string} string
|
|
1334
|
+
* @returns {Uint8Array}
|
|
1335
|
+
*/
|
|
1336
|
+
export function stringBits(string) {
|
|
1337
|
+
utf8Encoder ??= new TextEncoder();
|
|
1338
|
+
return utf8Encoder.encode(string);
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
/**
|
|
1342
|
+
* Returns the UTF-8 bytes for a single UTF codepoint.
|
|
1343
|
+
*
|
|
1344
|
+
* @param {UtfCodepoint} codepoint
|
|
1345
|
+
* @returns {Uint8Array}
|
|
1346
|
+
*/
|
|
1347
|
+
export function codepointBits(codepoint) {
|
|
1348
|
+
return stringBits(String.fromCodePoint(codepoint.value));
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
/**
|
|
1352
|
+
* Returns the UTF-16 bytes for a string.
|
|
1353
|
+
*
|
|
1354
|
+
* @param {string} string
|
|
1355
|
+
* @param {boolean} isBigEndian
|
|
1356
|
+
* @returns {Uint8Array}
|
|
1357
|
+
*/
|
|
1358
|
+
export function stringToUtf16(string, isBigEndian) {
|
|
1359
|
+
const buffer = new ArrayBuffer(string.length * 2);
|
|
1360
|
+
const bufferView = new DataView(buffer);
|
|
1361
|
+
|
|
1362
|
+
for (let i = 0; i < string.length; i++) {
|
|
1363
|
+
bufferView.setUint16(i * 2, string.charCodeAt(i), !isBigEndian);
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
return new Uint8Array(buffer);
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
/**
|
|
1370
|
+
* Returns the UTF-16 bytes for a single UTF codepoint.
|
|
1371
|
+
*
|
|
1372
|
+
* @param {UtfCodepoint} codepoint
|
|
1373
|
+
* @param {boolean} isBigEndian
|
|
1374
|
+
* @returns {Uint8Array}
|
|
1375
|
+
*/
|
|
1376
|
+
export function codepointToUtf16(codepoint, isBigEndian) {
|
|
1377
|
+
return stringToUtf16(String.fromCodePoint(codepoint.value), isBigEndian);
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
/**
|
|
1381
|
+
* Returns the UTF-32 bytes for a string.
|
|
1382
|
+
*
|
|
1383
|
+
* @param {string} string
|
|
1384
|
+
* @param {boolean} isBigEndian
|
|
1385
|
+
* @returns {Uint8Array}
|
|
1386
|
+
*/
|
|
1387
|
+
export function stringToUtf32(string, isBigEndian) {
|
|
1388
|
+
const buffer = new ArrayBuffer(string.length * 4);
|
|
1389
|
+
const bufferView = new DataView(buffer);
|
|
1390
|
+
let length = 0;
|
|
1391
|
+
|
|
1392
|
+
for (let i = 0; i < string.length; i++) {
|
|
1393
|
+
const codepoint = string.codePointAt(i);
|
|
1394
|
+
|
|
1395
|
+
bufferView.setUint32(length * 4, codepoint, !isBigEndian);
|
|
1396
|
+
length++;
|
|
1397
|
+
|
|
1398
|
+
if (codepoint > 0xffff) {
|
|
1399
|
+
i++;
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
return new Uint8Array(buffer.slice(0, length * 4));
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
/**
|
|
1407
|
+
* Returns the UTF-32 bytes for a single UTF codepoint.
|
|
1408
|
+
*
|
|
1409
|
+
* @param {UtfCodepoint} codepoint
|
|
1410
|
+
* @param {boolean} isBigEndian
|
|
1411
|
+
* @returns {Uint8Array}
|
|
1412
|
+
*/
|
|
1413
|
+
export function codepointToUtf32(codepoint, isBigEndian) {
|
|
1414
|
+
return stringToUtf32(String.fromCodePoint(codepoint.value), isBigEndian);
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
export class Result extends CustomType {
|
|
1418
|
+
static isResult(data) {
|
|
1419
|
+
return data instanceof Result;
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
export class Ok extends Result {
|
|
1424
|
+
constructor(value) {
|
|
1425
|
+
super();
|
|
1426
|
+
this[0] = value;
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
isOk() {
|
|
1430
|
+
return true;
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
export const Result$Ok = (value) => new Ok(value);
|
|
1434
|
+
export const Result$isOk = (value) => value instanceof Ok;
|
|
1435
|
+
export const Result$Ok$0 = (value) => value[0];
|
|
1436
|
+
|
|
1437
|
+
export class Error extends Result {
|
|
1438
|
+
constructor(detail) {
|
|
1439
|
+
super();
|
|
1440
|
+
this[0] = detail;
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
isOk() {
|
|
1444
|
+
return false;
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
export const Result$Error = (detail) => new Error(detail);
|
|
1448
|
+
export const Result$isError = (value) => value instanceof Error;
|
|
1449
|
+
export const Result$Error$0 = (value) => value[0];
|
|
1450
|
+
|
|
1451
|
+
export function isEqual(x, y) {
|
|
1452
|
+
let values = [x, y];
|
|
1453
|
+
|
|
1454
|
+
while (values.length) {
|
|
1455
|
+
let a = values.pop();
|
|
1456
|
+
let b = values.pop();
|
|
1457
|
+
if (a === b) continue;
|
|
1458
|
+
|
|
1459
|
+
if (!isObject(a) || !isObject(b)) return false;
|
|
1460
|
+
let unequal =
|
|
1461
|
+
!structurallyCompatibleObjects(a, b) ||
|
|
1462
|
+
unequalDates(a, b) ||
|
|
1463
|
+
unequalBuffers(a, b) ||
|
|
1464
|
+
unequalArrays(a, b) ||
|
|
1465
|
+
unequalMaps(a, b) ||
|
|
1466
|
+
unequalSets(a, b) ||
|
|
1467
|
+
unequalRegExps(a, b);
|
|
1468
|
+
if (unequal) return false;
|
|
1469
|
+
|
|
1470
|
+
const proto = Object.getPrototypeOf(a);
|
|
1471
|
+
if (proto !== null && typeof proto.equals === "function") {
|
|
1472
|
+
try {
|
|
1473
|
+
if (a.equals(b)) continue;
|
|
1474
|
+
else return false;
|
|
1475
|
+
} catch {}
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
let [keys, get] = getters(a);
|
|
1479
|
+
const ka = keys(a);
|
|
1480
|
+
const kb = keys(b);
|
|
1481
|
+
if (ka.length !== kb.length) return false;
|
|
1482
|
+
for (let k of ka) {
|
|
1483
|
+
values.push(get(a, k), get(b, k));
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
return true;
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
function getters(object) {
|
|
1491
|
+
if (object instanceof Map) {
|
|
1492
|
+
return [(x) => x.keys(), (x, y) => x.get(y)];
|
|
1493
|
+
} else {
|
|
1494
|
+
let extra = object instanceof globalThis.Error ? ["message"] : [];
|
|
1495
|
+
return [(x) => [...extra, ...Object.keys(x)], (x, y) => x[y]];
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
function unequalDates(a, b) {
|
|
1500
|
+
return a instanceof Date && (a > b || a < b);
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
function unequalBuffers(a, b) {
|
|
1504
|
+
return (
|
|
1505
|
+
!(a instanceof BitArray) &&
|
|
1506
|
+
a.buffer instanceof ArrayBuffer &&
|
|
1507
|
+
a.BYTES_PER_ELEMENT &&
|
|
1508
|
+
!(a.byteLength === b.byteLength && a.every((n, i) => n === b[i]))
|
|
1509
|
+
);
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
function unequalArrays(a, b) {
|
|
1513
|
+
return Array.isArray(a) && a.length !== b.length;
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
function unequalMaps(a, b) {
|
|
1517
|
+
return a instanceof Map && a.size !== b.size;
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
function unequalSets(a, b) {
|
|
1521
|
+
return (
|
|
1522
|
+
a instanceof Set && (a.size != b.size || [...a].some((e) => !b.has(e)))
|
|
1523
|
+
);
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
function unequalRegExps(a, b) {
|
|
1527
|
+
return a instanceof RegExp && (a.source !== b.source || a.flags !== b.flags);
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
function isObject(a) {
|
|
1531
|
+
return typeof a === "object" && a !== null;
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
function structurallyCompatibleObjects(a, b) {
|
|
1535
|
+
if (typeof a !== "object" && typeof b !== "object" && (!a || !b))
|
|
1536
|
+
return false;
|
|
1537
|
+
|
|
1538
|
+
let nonstructural = [Promise, WeakSet, WeakMap, Function];
|
|
1539
|
+
if (nonstructural.some((c) => a instanceof c)) return false;
|
|
1540
|
+
|
|
1541
|
+
return a.constructor === b.constructor;
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
export function remainderInt(a, b) {
|
|
1545
|
+
if (b === 0) {
|
|
1546
|
+
return 0;
|
|
1547
|
+
} else {
|
|
1548
|
+
return a % b;
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
export function divideInt(a, b) {
|
|
1553
|
+
return Math.trunc(divideFloat(a, b));
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
export function divideFloat(a, b) {
|
|
1557
|
+
if (b === 0) {
|
|
1558
|
+
return 0;
|
|
1559
|
+
} else {
|
|
1560
|
+
return a / b;
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
export function makeError(variant, file, module, line, fn, message, extra) {
|
|
1565
|
+
let error = new globalThis.Error(message);
|
|
1566
|
+
error.gleam_error = variant;
|
|
1567
|
+
error.file = file;
|
|
1568
|
+
error.module = module;
|
|
1569
|
+
error.line = line;
|
|
1570
|
+
error.function = fn;
|
|
1571
|
+
// TODO: Remove this with Gleam v2.0.0
|
|
1572
|
+
error.fn = fn;
|
|
1573
|
+
for (let k in extra) error[k] = extra[k];
|
|
1574
|
+
return error;
|
|
1575
|
+
}
|