toilscript 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +94 -0
  3. package/README.md +114 -0
  4. package/bin/asc.js +35 -0
  5. package/bin/asinit.js +468 -0
  6. package/dist/asc.d.ts +4 -0
  7. package/dist/toilscript.d.ts +4 -0
  8. package/dist/transform.cjs +1 -0
  9. package/dist/transform.d.ts +1 -0
  10. package/dist/transform.js +1 -0
  11. package/lib/binaryen.d.ts +2 -0
  12. package/lib/binaryen.js +2 -0
  13. package/package.json +114 -0
  14. package/std/README.md +6 -0
  15. package/std/assembly/array.ts +550 -0
  16. package/std/assembly/arraybuffer.ts +77 -0
  17. package/std/assembly/atomics.ts +127 -0
  18. package/std/assembly/bindings/asyncify.ts +16 -0
  19. package/std/assembly/bindings/dom.ts +291 -0
  20. package/std/assembly/bindings/node.ts +6 -0
  21. package/std/assembly/bitflags.ts +53 -0
  22. package/std/assembly/builtins.ts +2650 -0
  23. package/std/assembly/byteslice.ts +177 -0
  24. package/std/assembly/compat.ts +2 -0
  25. package/std/assembly/console.ts +42 -0
  26. package/std/assembly/crypto.ts +9 -0
  27. package/std/assembly/dataview.ts +181 -0
  28. package/std/assembly/date.ts +375 -0
  29. package/std/assembly/diagnostics.ts +11 -0
  30. package/std/assembly/encoding.ts +151 -0
  31. package/std/assembly/endian.ts +45 -0
  32. package/std/assembly/error.ts +44 -0
  33. package/std/assembly/fixedarray.ts +173 -0
  34. package/std/assembly/fixedmap.ts +326 -0
  35. package/std/assembly/fixedset.ts +275 -0
  36. package/std/assembly/function.ts +42 -0
  37. package/std/assembly/index.d.ts +2891 -0
  38. package/std/assembly/iterator.ts +35 -0
  39. package/std/assembly/map.ts +269 -0
  40. package/std/assembly/math.ts +3289 -0
  41. package/std/assembly/memory.ts +123 -0
  42. package/std/assembly/number.ts +388 -0
  43. package/std/assembly/object.ts +36 -0
  44. package/std/assembly/performance.ts +9 -0
  45. package/std/assembly/pointer.ts +80 -0
  46. package/std/assembly/polyfills.ts +27 -0
  47. package/std/assembly/process.ts +50 -0
  48. package/std/assembly/reference.ts +48 -0
  49. package/std/assembly/regexp.ts +12 -0
  50. package/std/assembly/rt/README.md +83 -0
  51. package/std/assembly/rt/common.ts +81 -0
  52. package/std/assembly/rt/index-incremental.ts +2 -0
  53. package/std/assembly/rt/index-memory.ts +1 -0
  54. package/std/assembly/rt/index-minimal.ts +2 -0
  55. package/std/assembly/rt/index-stub.ts +1 -0
  56. package/std/assembly/rt/index.d.ts +37 -0
  57. package/std/assembly/rt/itcms.ts +419 -0
  58. package/std/assembly/rt/memory-runtime.ts +94 -0
  59. package/std/assembly/rt/rtrace.ts +15 -0
  60. package/std/assembly/rt/stub.ts +133 -0
  61. package/std/assembly/rt/tcms.ts +254 -0
  62. package/std/assembly/rt/tlsf.ts +592 -0
  63. package/std/assembly/rt.ts +90 -0
  64. package/std/assembly/set.ts +225 -0
  65. package/std/assembly/shared/feature.ts +68 -0
  66. package/std/assembly/shared/runtime.ts +13 -0
  67. package/std/assembly/shared/target.ts +11 -0
  68. package/std/assembly/shared/tsconfig.json +11 -0
  69. package/std/assembly/shared/typeinfo.ts +72 -0
  70. package/std/assembly/staticarray.ts +423 -0
  71. package/std/assembly/string.ts +850 -0
  72. package/std/assembly/symbol.ts +114 -0
  73. package/std/assembly/table.ts +16 -0
  74. package/std/assembly/tsconfig.json +6 -0
  75. package/std/assembly/typedarray.ts +1954 -0
  76. package/std/assembly/uri.ts +17 -0
  77. package/std/assembly/util/bytes.ts +107 -0
  78. package/std/assembly/util/casemap.ts +497 -0
  79. package/std/assembly/util/error.ts +58 -0
  80. package/std/assembly/util/hash.ts +117 -0
  81. package/std/assembly/util/math.ts +1922 -0
  82. package/std/assembly/util/memory.ts +290 -0
  83. package/std/assembly/util/number.ts +873 -0
  84. package/std/assembly/util/sort.ts +313 -0
  85. package/std/assembly/util/string.ts +1202 -0
  86. package/std/assembly/util/uri.ts +275 -0
  87. package/std/assembly/vector.ts +4 -0
  88. package/std/assembly.json +16 -0
  89. package/std/portable/index.d.ts +461 -0
  90. package/std/portable/index.js +416 -0
  91. package/std/portable.json +11 -0
  92. package/std/types/assembly/index.d.ts +1 -0
  93. package/std/types/assembly/package.json +3 -0
  94. package/std/types/portable/index.d.ts +1 -0
  95. package/std/types/portable/package.json +3 -0
  96. package/tsconfig-base.json +13 -0
  97. package/util/README.md +23 -0
  98. package/util/browser/fs.js +1 -0
  99. package/util/browser/module.js +5 -0
  100. package/util/browser/path.js +520 -0
  101. package/util/browser/process.js +59 -0
  102. package/util/browser/url.js +23 -0
  103. package/util/cpu.d.ts +9 -0
  104. package/util/cpu.js +42 -0
  105. package/util/find.d.ts +6 -0
  106. package/util/find.js +20 -0
  107. package/util/node.d.ts +21 -0
  108. package/util/node.js +34 -0
  109. package/util/options.d.ts +70 -0
  110. package/util/options.js +262 -0
  111. package/util/terminal.d.ts +52 -0
  112. package/util/terminal.js +35 -0
  113. package/util/text.d.ts +26 -0
  114. package/util/text.js +114 -0
  115. package/util/tsconfig.json +9 -0
  116. package/util/web.d.ts +11 -0
  117. package/util/web.js +33 -0
@@ -0,0 +1,375 @@
1
+ import { E_INVALIDDATE } from "util/error";
2
+ import { Date as Date_binding } from "./bindings/dom";
3
+
4
+ // @ts-ignore: decorator
5
+ @inline const
6
+ MILLIS_PER_DAY = 1000 * 60 * 60 * 24,
7
+ MILLIS_PER_HOUR = 1000 * 60 * 60,
8
+ MILLIS_PER_MINUTE = 1000 * 60,
9
+ MILLIS_PER_SECOND = 1000,
10
+
11
+ YEARS_PER_EPOCH = 400,
12
+ DAYS_PER_EPOCH = 146097,
13
+ EPOCH_OFFSET = 719468, // Jan 1, 1970
14
+ MILLIS_LIMIT = 8640000000000000;
15
+
16
+ // ymdFromEpochDays returns values via globals to avoid allocations
17
+ // @ts-ignore: decorator
18
+ @lazy let _month: i32, _day: i32;
19
+
20
+ export class Date {
21
+ private year: i32 = 0;
22
+ private month: i32 = 0;
23
+ private day: i32 = 0;
24
+
25
+ @inline static UTC(
26
+ year: i32,
27
+ month: i32 = 0,
28
+ day: i32 = 1,
29
+ hour: i32 = 0,
30
+ minute: i32 = 0,
31
+ second: i32 = 0,
32
+ millisecond: i32 = 0
33
+ ): i64 {
34
+ if (year >= 0 && year <= 99) year += 1900;
35
+ let ms = epochMillis(year, month + 1, day, hour, minute, second, millisecond);
36
+ if (invalidDate(ms)) throw new RangeError(E_INVALIDDATE);
37
+ return ms;
38
+ }
39
+
40
+ @inline static now(): i64 {
41
+ return <i64>Date_binding.now();
42
+ }
43
+
44
+ // It can parse only ISO 8601 inputs like YYYY-MM-DDTHH:MM:SS.000Z
45
+ @inline static parse(dateString: string): Date {
46
+ return this.fromString(dateString);
47
+ }
48
+
49
+ static fromString(dateTimeString: string): Date {
50
+ if (!dateTimeString.length) throw new RangeError(E_INVALIDDATE);
51
+ var
52
+ hour: i32 = 0,
53
+ min: i32 = 0,
54
+ sec: i32 = 0,
55
+ ms: i32 = 0,
56
+ offsetMs: i32 = 0;
57
+
58
+ let dateString = dateTimeString;
59
+ let posT = dateTimeString.indexOf("T");
60
+ if (~posT) {
61
+ // includes a time component
62
+ let timeString: string;
63
+ dateString = dateTimeString.substring(0, posT);
64
+ timeString = dateTimeString.substring(posT + 1);
65
+
66
+ // might end with an offset ("Z", "+05:30", "-08:00", etc.)
67
+ for (let i = timeString.length - 1; i >= 0; i--) {
68
+ let c = timeString.charCodeAt(i);
69
+ if (c == 90) { // Z
70
+ timeString = timeString.substring(0, i);
71
+ break;
72
+ } else if (c == 43 || c == 45) { // + or -
73
+ if (i == timeString.length - 1) {
74
+ throw new RangeError(E_INVALIDDATE);
75
+ }
76
+
77
+ let posColon = timeString.indexOf(":", i + 1);
78
+ if (~posColon) {
79
+ let offsetHours = i32.parse(timeString.substring(i + 1, posColon));
80
+ let offsetMinutes = i32.parse(timeString.substring(posColon + 1));
81
+ offsetMs = (offsetHours * 60 + offsetMinutes) * MILLIS_PER_MINUTE;
82
+ } else {
83
+ let offsetHours = i32.parse(timeString.substring(i + 1));
84
+ offsetMs = offsetHours * MILLIS_PER_HOUR;
85
+ }
86
+
87
+ if (c == 45) offsetMs = -offsetMs; // negative offset
88
+ timeString = timeString.substring(0, i);
89
+ break;
90
+ }
91
+ }
92
+
93
+ // parse the HH:MM:SS component
94
+ let timeParts = timeString.split(":");
95
+ let len = timeParts.length;
96
+ if (len <= 1) throw new RangeError(E_INVALIDDATE);
97
+
98
+ hour = i32.parse(timeParts[0]);
99
+ min = i32.parse(timeParts[1]);
100
+ if (len >= 3) {
101
+ let secAndFrac = timeParts[2];
102
+ let posDot = secAndFrac.indexOf(".");
103
+ if (~posDot) {
104
+ // includes fractional seconds (truncate to milliseconds)
105
+ sec = i32.parse(secAndFrac.substring(0, posDot));
106
+ ms = i32.parse(secAndFrac.substr(posDot + 1, 3).padEnd(3, "0"));
107
+ } else {
108
+ sec = i32.parse(secAndFrac);
109
+ }
110
+ }
111
+ }
112
+
113
+ // parse the YYYY-MM-DD component
114
+ let parts = dateString.split("-");
115
+ let year = i32.parse(parts[0]);
116
+ let month = 1, day = 1;
117
+ let len = parts.length;
118
+ if (len >= 2) {
119
+ month = i32.parse(parts[1]);
120
+ if (len >= 3) {
121
+ day = i32.parse(parts[2]);
122
+ }
123
+ }
124
+
125
+ return new Date(epochMillis(year, month, day, hour, min, sec, ms) - offsetMs);
126
+ }
127
+
128
+ constructor(private epochMillis: i64) {
129
+ // this differs from JavaScript which prefer return NaN or "Invalid Date" string
130
+ // instead throwing exception.
131
+ if (invalidDate(epochMillis)) throw new RangeError(E_INVALIDDATE);
132
+
133
+ this.year = dateFromEpoch(epochMillis);
134
+ this.month = _month;
135
+ this.day = _day;
136
+ }
137
+
138
+ @inline getTime(): i64 {
139
+ return this.epochMillis;
140
+ }
141
+
142
+ setTime(time: i64): i64 {
143
+ if (invalidDate(time)) throw new RangeError(E_INVALIDDATE);
144
+
145
+ this.epochMillis = time;
146
+ this.year = dateFromEpoch(time);
147
+ this.month = _month;
148
+ this.day = _day;
149
+
150
+ return time;
151
+ }
152
+
153
+ @inline getUTCFullYear(): i32 {
154
+ return this.year;
155
+ }
156
+
157
+ @inline getUTCMonth(): i32 {
158
+ return this.month - 1;
159
+ }
160
+
161
+ @inline getUTCDate(): i32 {
162
+ return this.day;
163
+ }
164
+
165
+ @inline getUTCDay(): i32 {
166
+ return dayOfWeek(this.year, this.month, this.day);
167
+ }
168
+
169
+ getUTCHours(): i32 {
170
+ return i32(euclidRem(this.epochMillis, MILLIS_PER_DAY)) / MILLIS_PER_HOUR;
171
+ }
172
+
173
+ getUTCMinutes(): i32 {
174
+ return i32(euclidRem(this.epochMillis, MILLIS_PER_HOUR)) / MILLIS_PER_MINUTE;
175
+ }
176
+
177
+ getUTCSeconds(): i32 {
178
+ return i32(euclidRem(this.epochMillis, MILLIS_PER_MINUTE)) / MILLIS_PER_SECOND;
179
+ }
180
+
181
+ getUTCMilliseconds(): i32 {
182
+ return i32(euclidRem(this.epochMillis, MILLIS_PER_SECOND));
183
+ }
184
+
185
+ setUTCMilliseconds(millis: i32): void {
186
+ this.setTime(this.epochMillis + (millis - this.getUTCMilliseconds()));
187
+ }
188
+
189
+ setUTCSeconds(seconds: i32): void {
190
+ this.setTime(this.epochMillis + (seconds - this.getUTCSeconds()) * MILLIS_PER_SECOND);
191
+ }
192
+
193
+ setUTCMinutes(minutes: i32): void {
194
+ this.setTime(this.epochMillis + (minutes - this.getUTCMinutes()) * MILLIS_PER_MINUTE);
195
+ }
196
+
197
+ setUTCHours(hours: i32): void {
198
+ this.setTime(this.epochMillis + (hours - this.getUTCHours()) * MILLIS_PER_HOUR);
199
+ }
200
+
201
+ setUTCDate(day: i32): void {
202
+ if (this.day == day) return;
203
+ this.setTime(join(this.year, this.month, day, this.epochMillis));
204
+ }
205
+
206
+ setUTCMonth(month: i32, day: i32 = this.day): void {
207
+ if (this.month == month + 1) return;
208
+ this.setTime(join(this.year, month + 1, day, this.epochMillis));
209
+ }
210
+
211
+ setUTCFullYear(year: i32): void {
212
+ if (this.year == year) return;
213
+ this.setTime(join(year, this.month, this.day, this.epochMillis));
214
+ }
215
+
216
+ toISOString(): string {
217
+ // TODO: add more low-level helper which combine toString and padStart without extra allocation
218
+
219
+ let yr = this.year;
220
+ let isNeg = yr < 0;
221
+ let year = (isNeg || yr >= 10000)
222
+ ? (isNeg ? "-" : "+") + stringify(abs(yr), 6)
223
+ : stringify(yr, 4);
224
+ let month = stringify(this.month, 2);
225
+ let day = stringify(this.day);
226
+ let hours = stringify(this.getUTCHours());
227
+ let mins = stringify(this.getUTCMinutes());
228
+ let secs = stringify(this.getUTCSeconds());
229
+ let ms = stringify(this.getUTCMilliseconds(), 3);
230
+
231
+ return `${year}-${month}-${day}T${hours}:${mins}:${secs}.${ms}Z`;
232
+ }
233
+
234
+ toUTCString(): string {
235
+ const
236
+ weeks: StaticArray<string> = [
237
+ "Sun, ", "Mon, ", "Tue, ", "Wed, ", "Thu, ", "Fri, ", "Sat, "
238
+ ],
239
+ months: StaticArray<string> = [
240
+ " Jan ", " Feb ", " Mar ", " Apr ", " May ", " Jun ",
241
+ " Jul ", " Aug ", " Sep ", " Oct ", " Nov ", " Dec "
242
+ ];
243
+
244
+ let mo = this.month;
245
+ let da = this.day;
246
+ let yr = this.year;
247
+ let wd = dayOfWeek(yr, mo, da);
248
+ let year = stringify(abs(yr), 4);
249
+ let month = unchecked(months[mo - 1]);
250
+ let week = unchecked(weeks[wd]);
251
+ let day = stringify(da);
252
+ let hours = stringify(this.getUTCHours());
253
+ let mins = stringify(this.getUTCMinutes());
254
+ let secs = stringify(this.getUTCSeconds());
255
+
256
+ return `${week}${day}${month}${yr < 0 ? "-" : ""}${year} ${hours}:${mins}:${secs} GMT`;
257
+ }
258
+
259
+ toDateString(): string {
260
+ // TODO: use u64 static data instead 4 chars
261
+ // also use stream itoa variants.
262
+ const
263
+ weeks: StaticArray<string> = [
264
+ "Sun ", "Mon ", "Tue ", "Wed ", "Thu ", "Fri ", "Sat "
265
+ ],
266
+ months: StaticArray<string> = [
267
+ "Jan ", "Feb ", "Mar ", "Apr ", "May ", "Jun ",
268
+ "Jul ", "Aug ", "Sep ", "Oct ", "Nov ", "Dec "
269
+ ];
270
+
271
+ let mo = this.month;
272
+ let da = this.day;
273
+ let yr = this.year;
274
+ let wd = dayOfWeek(yr, mo, da);
275
+ let year = stringify(abs(yr), 4);
276
+ let month = unchecked(months[mo - 1]);
277
+ let week = unchecked(weeks[wd]);
278
+ let day = stringify(da);
279
+
280
+ return `${week}${month}${day}${yr < 0 ? " -" : " "}${year}`;
281
+ }
282
+
283
+ // Note: it uses UTC time instead local time (without timezone offset)
284
+ toTimeString(): string {
285
+ let hours = stringify(this.getUTCHours());
286
+ let mins = stringify(this.getUTCMinutes());
287
+ let secs = stringify(this.getUTCSeconds());
288
+ // TODO: add timezone
289
+ return `${hours}:${mins}:${secs}`;
290
+ }
291
+
292
+ // Note: it uses UTC datetime instead local datetime (without timezone offset)
293
+ toString(): string {
294
+ return `${this.toDateString()} ${this.toTimeString()}`;
295
+ }
296
+ }
297
+
298
+ function epochMillis(
299
+ year: i32,
300
+ month: i32,
301
+ day: i32,
302
+ hour: i32,
303
+ minute: i32,
304
+ second: i32,
305
+ milliseconds: i32
306
+ ): i64 {
307
+ return (
308
+ daysSinceEpoch(year, month, day) * MILLIS_PER_DAY +
309
+ hour * MILLIS_PER_HOUR +
310
+ minute * MILLIS_PER_MINUTE +
311
+ second * MILLIS_PER_SECOND +
312
+ milliseconds
313
+ );
314
+ }
315
+
316
+ // @ts-ignore: decorator
317
+ @inline function floorDiv<T extends number>(a: T, b: T): T {
318
+ return (a - (a < 0 ? b - 1 : 0)) / b as T;
319
+ }
320
+
321
+ // @ts-ignore: decorator
322
+ @inline function euclidRem<T extends number>(a: T, b: T): T {
323
+ let m = a % b;
324
+ return m + (m < 0 ? b : 0) as T;
325
+ }
326
+
327
+ function invalidDate(millis: i64): bool {
328
+ // @ts-ignore
329
+ return (millis < -MILLIS_LIMIT) | (millis > MILLIS_LIMIT);
330
+ }
331
+
332
+ // Based on "Euclidean Affine Functions and Applications to Calendar Algorithms"
333
+ // Paper: https://arxiv.org/pdf/2102.06959.pdf
334
+ function dateFromEpoch(ms: i64): i32 {
335
+ let da = (<i32>floorDiv(ms, MILLIS_PER_DAY) * 4 + EPOCH_OFFSET * 4) | 3;
336
+ let q0 = floorDiv(da, DAYS_PER_EPOCH); // [0, 146096]
337
+ let r1 = <u32>da - q0 * DAYS_PER_EPOCH;
338
+ let u1 = u64(r1 | 3) * 2939745;
339
+ let dm1 = <u32>u1 / 11758980;
340
+ let n1 = 2141 * dm1 + 197913;
341
+ let year = 100 * q0 + i32(u1 >>> 32);
342
+ let mo = n1 >>> 16;
343
+ _day = (n1 & 0xFFFF) / 2141 + 1; // [1, 31]
344
+ if (dm1 >= 306) { mo -= 12; ++year; }
345
+ _month = mo; // [1, 12]
346
+ return year;
347
+ }
348
+
349
+ // http://howardhinnant.github.io/date_algorithms.html#days_from_civil
350
+ function daysSinceEpoch(y: i32, m: i32, d: i32): i64 {
351
+ y -= i32(m <= 2);
352
+ let era = <u32>floorDiv(y, YEARS_PER_EPOCH);
353
+ let yoe = <u32>y - era * YEARS_PER_EPOCH; // [0, 399]
354
+ let doy = <u32>(153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1; // [0, 365]
355
+ let doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; // [0, 146096]
356
+ return <i64><i32>(era * 146097 + doe - EPOCH_OFFSET);
357
+ }
358
+
359
+ // TomohikoSakamoto algorithm from https://en.wikipedia.org/wiki/Determination_of_the_day_of_the_week
360
+ function dayOfWeek(year: i32, month: i32, day: i32): i32 {
361
+ const tab = memory.data<u8>([0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4]);
362
+
363
+ year -= i32(month < 3);
364
+ year += floorDiv(year, 4) - floorDiv(year, 100) + floorDiv(year, YEARS_PER_EPOCH);
365
+ month = <i32>load<u8>(tab + month - 1);
366
+ return euclidRem(year + month + day, 7);
367
+ }
368
+
369
+ function stringify(value: i32, padding: i32 = 2): string {
370
+ return value.toString().padStart(padding, "0");
371
+ }
372
+
373
+ function join(year: i32, month: i32, day: i32, ms: i64): i64 {
374
+ return daysSinceEpoch(year, month, day) * MILLIS_PER_DAY + euclidRem(ms, MILLIS_PER_DAY);
375
+ }
@@ -0,0 +1,11 @@
1
+ // @ts-ignore: decorator
2
+ @builtin
3
+ export declare function ERROR(message?: string): void;
4
+
5
+ // @ts-ignore: decorator
6
+ @builtin
7
+ export declare function WARNING(message?: string): void;
8
+
9
+ // @ts-ignore: decorator
10
+ @builtin
11
+ export declare function INFO(message?: string): void;
@@ -0,0 +1,151 @@
1
+ import { Pointer } from "./pointer";
2
+
3
+ // Hex and varint encoding utilities.
4
+ // Inline functions for zero-overhead encoding/decoding.
5
+
6
+ export namespace Encoding {
7
+
8
+ export namespace Hex {
9
+ /** Encode bytes at `src` (length `srcLen`) to hex chars at `dst`. Returns chars written (srcLen * 2). */
10
+ @inline export function encode(src: usize, srcLen: i32, dst: usize): i32 {
11
+ for (let i: i32 = 0; i < srcLen; ++i) {
12
+ encodeByte(load<u8>(src + <usize>i), dst + <usize>(i << 1));
13
+ }
14
+ return srcLen << 1;
15
+ }
16
+
17
+ /** Decode hex chars at `src` (length `srcLen`, must be even) to bytes at `dst`. Returns bytes written, or -1 on error. */
18
+ @inline export function decode(src: usize, srcLen: i32, dst: usize): i32 {
19
+ if (srcLen & 1) return -1; // odd length
20
+ let outLen = srcLen >> 1;
21
+ for (let i: i32 = 0; i < outLen; ++i) {
22
+ let b = decodeByte(src + <usize>(i << 1));
23
+ if (b < 0) return -1;
24
+ store<u8>(dst + <usize>i, <u8>b);
25
+ }
26
+ return outLen;
27
+ }
28
+
29
+ /** Encode a single byte to 2 hex chars at `dst`. */
30
+ @inline export function encodeByte(value: u8, dst: usize): void {
31
+ let hi = (value >>> 4) & 0x0F;
32
+ let lo = value & 0x0F;
33
+ store<u8>(dst, hi < 10 ? hi + 48 : hi + 87); // '0'-'9' or 'a'-'f'
34
+ store<u8>(dst + 1, lo < 10 ? lo + 48 : lo + 87);
35
+ }
36
+
37
+ /** Decode 2 hex chars at `src` to a byte value. Returns -1 on invalid input. */
38
+ @inline export function decodeByte(src: usize): i32 {
39
+ let hi = decodeNibble(load<u8>(src));
40
+ let lo = decodeNibble(load<u8>(src + 1));
41
+ if ((hi | lo) < 0) return -1;
42
+ return (hi << 4) | lo;
43
+ }
44
+
45
+ // Internal nibble decoder
46
+ @inline function decodeNibble(c: u8): i32 {
47
+ if (c >= 48 && c <= 57) return <i32>(c - 48); // '0'-'9'
48
+ if (c >= 97 && c <= 102) return <i32>(c - 87); // 'a'-'f'
49
+ if (c >= 65 && c <= 70) return <i32>(c - 55); // 'A'-'F'
50
+ return -1;
51
+ }
52
+ }
53
+
54
+ export namespace Varint {
55
+ /** Encode a u32 as unsigned LEB128 at `dst`. Returns bytes written. */
56
+ @inline export function encodeU32(value: u32, dst: usize): i32 {
57
+ let i: i32 = 0;
58
+ while (value >= 0x80) {
59
+ store<u8>(dst + <usize>i, <u8>((value & 0x7F) | 0x80));
60
+ value >>= 7;
61
+ ++i;
62
+ }
63
+ store<u8>(dst + <usize>i, <u8>value);
64
+ return i + 1;
65
+ }
66
+
67
+ /** Encode a u64 as unsigned LEB128 at `dst`. Returns bytes written. */
68
+ @inline export function encodeU64(value: u64, dst: usize): i32 {
69
+ let i: i32 = 0;
70
+ while (value >= 0x80) {
71
+ store<u8>(dst + <usize>i, <u8>((<u32>(value & 0x7F)) | 0x80));
72
+ value >>= 7;
73
+ ++i;
74
+ }
75
+ store<u8>(dst + <usize>i, <u8><u32>value);
76
+ return i + 1;
77
+ }
78
+
79
+ /** Decode an unsigned LEB128-encoded u32 from `src`. Writes bytes consumed to `bytesRead`. Max 5 bytes. */
80
+ @inline export function decodeU32(src: usize, bytesRead: Pointer<i32>): u32 {
81
+ let result: u32 = 0;
82
+ let shift: u32 = 0;
83
+ let i: i32 = 0;
84
+ let b: u8;
85
+ do {
86
+ b = load<u8>(src + <usize>i);
87
+ result |= <u32>(b & 0x7F) << shift;
88
+ shift += 7;
89
+ ++i;
90
+ if (i >= 5) break; // u32 needs at most 5 LEB128 bytes
91
+ } while (b & 0x80);
92
+ bytesRead.value = i;
93
+ return result;
94
+ }
95
+
96
+ /** Decode an unsigned LEB128-encoded u64 from `src`. Writes bytes consumed to `bytesRead`. Max 10 bytes. */
97
+ @inline export function decodeU64(src: usize, bytesRead: Pointer<i32>): u64 {
98
+ let result: u64 = 0;
99
+ let shift: u64 = 0;
100
+ let i: i32 = 0;
101
+ let b: u8;
102
+ do {
103
+ b = load<u8>(src + <usize>i);
104
+ result |= <u64>(b & 0x7F) << shift;
105
+ shift += 7;
106
+ ++i;
107
+ if (i >= 10) break; // u64 needs at most 10 LEB128 bytes
108
+ } while (b & 0x80);
109
+ bytesRead.value = i;
110
+ return result;
111
+ }
112
+
113
+ /** Encode a u64 as Bitcoin CompactSize at `dst`. Returns bytes written. */
114
+ @inline export function encodeCompact(value: u64, dst: usize): i32 {
115
+ if (value < 0xFD) {
116
+ store<u8>(dst, <u8><u32>value);
117
+ return 1;
118
+ } else if (value <= 0xFFFF) {
119
+ store<u8>(dst, 0xFD);
120
+ store<u16>(dst + 1, <u16><u32>value); // LE
121
+ return 3;
122
+ } else if (value <= 0xFFFFFFFF) {
123
+ store<u8>(dst, 0xFE);
124
+ store<u32>(dst + 1, <u32>value); // LE
125
+ return 5;
126
+ } else {
127
+ store<u8>(dst, 0xFF);
128
+ store<u64>(dst + 1, value); // LE
129
+ return 9;
130
+ }
131
+ }
132
+
133
+ /** Decode a Bitcoin CompactSize from `src`. Writes bytes consumed to `bytesRead`. */
134
+ @inline export function decodeCompact(src: usize, bytesRead: Pointer<i32>): u64 {
135
+ let first = load<u8>(src);
136
+ if (first < 0xFD) {
137
+ bytesRead.value = 1;
138
+ return <u64>first;
139
+ } else if (first == 0xFD) {
140
+ bytesRead.value = 3;
141
+ return <u64>load<u16>(src + 1);
142
+ } else if (first == 0xFE) {
143
+ bytesRead.value = 5;
144
+ return <u64>load<u32>(src + 1);
145
+ } else {
146
+ bytesRead.value = 9;
147
+ return load<u64>(src + 1);
148
+ }
149
+ }
150
+ }
151
+ }
@@ -0,0 +1,45 @@
1
+ // Zero-overhead endian conversion utilities.
2
+ // Wasm is little-endian; protocols (Bitcoin, networking) often need big-endian.
3
+
4
+ export namespace Endian {
5
+
6
+ /** Load a value from memory in big-endian byte order. */
7
+ @inline export function loadBE<T>(ptr: usize, offset: usize = 0): T {
8
+ return bswap<T>(load<T>(ptr + offset));
9
+ }
10
+
11
+ /** Store a value to memory in big-endian byte order. */
12
+ @inline export function storeBE<T>(ptr: usize, value: T, offset: usize = 0): void {
13
+ store<T>(ptr + offset, bswap<T>(value));
14
+ }
15
+
16
+ /** Load a value from memory in little-endian byte order (identity on wasm). */
17
+ @inline export function loadLE<T>(ptr: usize, offset: usize = 0): T {
18
+ return load<T>(ptr + offset);
19
+ }
20
+
21
+ /** Store a value to memory in little-endian byte order (identity on wasm). */
22
+ @inline export function storeLE<T>(ptr: usize, value: T, offset: usize = 0): void {
23
+ store<T>(ptr + offset, value);
24
+ }
25
+
26
+ /** Convert a value to big-endian byte order (bswap on wasm). */
27
+ @inline export function toBE<T>(value: T): T {
28
+ return bswap<T>(value);
29
+ }
30
+
31
+ /** Convert a value from big-endian byte order (bswap on wasm). */
32
+ @inline export function fromBE<T>(value: T): T {
33
+ return bswap<T>(value);
34
+ }
35
+
36
+ /** Convert a value to little-endian byte order (identity on wasm). */
37
+ @inline export function toLE<T>(value: T): T {
38
+ return value;
39
+ }
40
+
41
+ /** Convert a value from little-endian byte order (identity on wasm). */
42
+ @inline export function fromLE<T>(value: T): T {
43
+ return value;
44
+ }
45
+ }
@@ -0,0 +1,44 @@
1
+ export class Error {
2
+
3
+ name: string = "Error";
4
+ stack: string = ""; // TODO
5
+
6
+ constructor(
7
+ public message: string = ""
8
+ ) {}
9
+
10
+ toString(): string {
11
+ let message = this.message;
12
+ return message.length
13
+ ? this.name + ": " + message
14
+ : this.name;
15
+ }
16
+ }
17
+
18
+ export class RangeError extends Error {
19
+ constructor(message: string = "") {
20
+ super(message);
21
+ this.name = "RangeError";
22
+ }
23
+ }
24
+
25
+ export class TypeError extends Error {
26
+ constructor(message: string = "") {
27
+ super(message);
28
+ this.name = "TypeError";
29
+ }
30
+ }
31
+
32
+ export class SyntaxError extends Error {
33
+ constructor(message: string = "") {
34
+ super(message);
35
+ this.name = "SyntaxError";
36
+ }
37
+ }
38
+
39
+ export class URIError extends Error {
40
+ constructor(message: string = "") {
41
+ super(message);
42
+ this.name = "URIError";
43
+ }
44
+ }