json-as 1.0.0-alpha.3 → 1.0.0-alpha.4

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/CHANGELOG CHANGED
@@ -1,5 +1,19 @@
1
1
  # Change Log
2
2
 
3
+ ## 2025-02-13 - 1.0.0-alpha.4
4
+
5
+ - feat: reintroduce support for `Box<T>`-wrapped primitive types
6
+ - tests: add extensive tests to all supported types
7
+ - fix: 6-byte keys being recognized on deserialize
8
+ - perf: take advantage of aligned memory to use a single 64-bit load on 6-byte keys
9
+ - fix: `bs.proposeSize()` should increment `stackSize` by `size` instead of setting it
10
+ - fix: allow runtime to manage `bs.buffer`
11
+ - fix: memory leaks in `bs` module
12
+ - fix: add (possibly temporary) `JSON.Memory.shrink()` to shrink memory in `bs`
13
+ - perf: prefer growing memory by `nextPowerOf2(size + 64)` for less reallocations
14
+ - tests: add boolean tests to `Box<T>`
15
+ - fix: serialization of non-growable data types should grow `bs.stackSize`
16
+
3
17
  ## 2025-01-31 - 1.0.0-alpha.3
4
18
 
5
19
  - fix: write to proper offset when deserializing string with \u0000-type escapes
package/README.md CHANGED
@@ -6,10 +6,21 @@
6
6
  ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
7
7
  █████ ███████ ██████ ██ ████ ██ ██ ███████
8
8
  </span>
9
- AssemblyScript - v1.0.0-alpha.3
9
+ AssemblyScript - v1.0.0-alpha.4
10
10
  </pre>
11
11
  </h5>
12
12
 
13
+ ## Contents
14
+ - [About](#about)
15
+ - [Installation](#installation)
16
+ - [Usage](#usage)
17
+ - [Examples](#examples)
18
+ - [Performance](#performance)
19
+ - [License](#license)
20
+ - [Contact](#contact)
21
+
22
+ ## About
23
+
13
24
  ## Installation
14
25
 
15
26
  ```bash
@@ -40,7 +51,6 @@ If you'd like to see the code that the transform generates, run with `JSON_DEBUG
40
51
  ```js
41
52
  import { JSON } from "json-as";
42
53
 
43
- // @json or @serializable work here
44
54
  @json
45
55
  class Vec3 {
46
56
  x: f32 = 0.0;
@@ -55,8 +65,7 @@ class Player {
55
65
  lastName!: string;
56
66
  lastActive!: i32[];
57
67
  // Drop in a code block, function, or expression that evaluates to a boolean
58
- @omitif((age) => age < 18)
59
- @omitif('this.age <= 0')
68
+ @omitif((self: Player) => self.age < 18)
60
69
  age!: i32;
61
70
  @omitnull()
62
71
  pos!: Vec3 | null;
@@ -64,10 +73,10 @@ class Player {
64
73
  }
65
74
 
66
75
  const player: Player = {
67
- firstName: "Emmet",
68
- lastName: "West",
69
- lastActive: [8, 27, 2022],
70
- age: 23,
76
+ firstName: "Jairus",
77
+ lastName: "Tanaka",
78
+ lastActive: [2, 7, 2025],
79
+ age: 18,
71
80
  pos: {
72
81
  x: 3.4,
73
82
  y: 1.2,
@@ -76,11 +85,15 @@ const player: Player = {
76
85
  isVerified: true
77
86
  };
78
87
 
79
- const stringified = JSON.stringify<Player>(player);
88
+ const serialized = JSON.stringify<Player>(player);
89
+ const parsed = JSON.parse<Player>(serialized);
80
90
 
81
- const parsed = JSON.parse<Player>(stringified);
91
+ console.log("Serialized: " + serialized);
92
+ console.log("Parsed: " + JSON.stringify(parsed));
82
93
  ```
83
94
 
95
+ ## Examples
96
+
84
97
  Classes can even have inheritance. Here's a nasty example
85
98
 
86
99
  ```js
@@ -124,16 +137,15 @@ You can also add it to your `asconfig.json`
124
137
 
125
138
  If you use this project in your codebase, consider dropping a [star](https://github.com/JairusSW/as-json). I would really appreciate it!
126
139
 
127
- ## Notes
128
-
129
- If you want a feature, drop an issue (and again, maybe a star). I'll likely add it in less than 7 days.
140
+ ## 📃 License
130
141
 
131
- ## Contact
142
+ This project is distributed under an open source license. You can view the full license using the following link: [License](./LICENSE)
132
143
 
133
- - [Email](mailto:me@jairus.dev)
134
- - [GitHub](https://github.com/JairusSW)
135
- - [Discord](discord.com/users/600700584038760448)
144
+ ## 📫 Contact
136
145
 
137
- ## Issues
146
+ Please send all issues to [GitHub Issues](https://github.com/JairusSW/as-json/issues) and to converse, please send me an email at [me@jairus.dev](mailto:me@jairus.dev)
138
147
 
139
- Please submit an issue to https://github.com/JairusSW/as-json/issues if you find anything wrong with this library
148
+ - **Email:** Send me inquiries, questions, or requests at [me@jairus.dev](mailto:me@jairus.dev)
149
+ - **GitHub:** Visit the official GitHub repository [Here](https://github.com/JairusSW/as-json)
150
+ - **Website:** Visit my official website at [jairus.dev](https://jairus.dev/)
151
+ - **Discord:** Converse with me on [My Discord](discord.com/users/600700584038760448) or on the [AssemblyScript Discord Server](https://discord.gg/assemblyscript/)
@@ -0,0 +1,37 @@
1
+ import { JSON } from "..";
2
+ import { describe, expect } from "../../modules/test/assembly";
3
+
4
+ describe("Should serialize JSON.Box<T>", () => {
5
+ expect(JSON.stringify<JSON.Box<i32> | null>(null))
6
+ .toBe("null");
7
+
8
+ expect(JSON.stringify<JSON.Box<i32> | null>(new JSON.Box<i32>(0)))
9
+ .toBe("0");
10
+
11
+ expect(JSON.stringify<JSON.Box<i32> | null>(new JSON.Box<i32>(1)))
12
+ .toBe("1");
13
+
14
+ expect(JSON.stringify<JSON.Box<boolean> | null>(new JSON.Box<boolean>(false)))
15
+ .toBe("false");
16
+
17
+ expect(JSON.stringify<JSON.Box<boolean> | null>(new JSON.Box<boolean>(true)))
18
+ .toBe("true");
19
+ });
20
+
21
+ // This is somewhat clumsy to use. Perhaps I can redesign it or use some transform to make it more transparent.
22
+ describe("Should deserialize JSON.Box<T>", () => {
23
+ expect((JSON.parse<JSON.Box<i32> | null>("null") == null).toString())
24
+ .toBe("true");
25
+
26
+ expect(JSON.parse<JSON.Box<i32> | null>("0")!.value.toString())
27
+ .toBe("0");
28
+
29
+ expect(JSON.parse<JSON.Box<i32> | null>("1")!.value.toString())
30
+ .toBe("1");
31
+
32
+ expect(JSON.parse<JSON.Box<boolean> | null>("false")!.value.toString())
33
+ .toBe("false");
34
+
35
+ expect(JSON.parse<JSON.Box<boolean> | null>("true")!.value.toString())
36
+ .toBe("true");
37
+ });
@@ -0,0 +1,38 @@
1
+ import { JSON } from "..";
2
+ import { describe, expect } from "../../modules/test/assembly";
3
+
4
+ describe("Should serialize Date", () => {
5
+ expect(JSON.stringify<Date>(new Date(0)))
6
+ .toBe('"1970-01-01T00:00:00.000Z"');
7
+ expect(JSON.stringify<Date>(new Date(1738618120525)))
8
+ .toBe('"2025-02-03T21:28:40.525Z"');
9
+ });
10
+
11
+ describe("Should deserialize booleans", () => {
12
+ // const date = JSON.parse<Date>('"2025-02-03T21:28:40.525Z"');
13
+ // console.log("Year: " + date.getUTCFullYear().toString());
14
+ // console.log("Month: " + date.getUTCMonth().toString());
15
+ // console.log("Day: " + date.getUTCDay().toString());
16
+ // console.log("Hours: " + date.getUTCHours().toString());
17
+ // console.log("Minutes: " + date.getUTCMinutes().toString());
18
+ // console.log("Seconds: " + date.getUTCSeconds().toString());
19
+ // console.log("Milliseconds: " + date.getUTCMilliseconds().toString());
20
+
21
+ const date1 = JSON.parse<Date>('"1970-01-01T00:00:00.000Z"');
22
+ expect(date1.getUTCFullYear().toString()).toBe("1970");
23
+ expect(date1.getUTCMonth().toString()).toBe("0");
24
+ expect(date1.getUTCDay().toString()).toBe("4");
25
+ expect(date1.getUTCHours().toString()).toBe("0");
26
+ expect(date1.getUTCMinutes().toString()).toBe("0");
27
+ expect(date1.getUTCSeconds().toString()).toBe("0");
28
+ expect(date1.getUTCMilliseconds().toString()).toBe("0");
29
+
30
+ const date2 = JSON.parse<Date>('"2025-02-03T21:28:40.525Z"');
31
+ expect(date2.getUTCFullYear().toString()).toBe("2025");
32
+ expect(date2.getUTCMonth().toString()).toBe("1");
33
+ expect(date2.getUTCDay().toString()).toBe("1");
34
+ expect(date2.getUTCHours().toString()).toBe("21");
35
+ expect(date2.getUTCMinutes().toString()).toBe("28");
36
+ expect(date2.getUTCSeconds().toString()).toBe("40");
37
+ expect(date2.getUTCMilliseconds().toString()).toBe("525");
38
+ });
@@ -1,9 +1,6 @@
1
- import { CHAR_F, CHAR_T } from "../../custom/chars";
2
-
3
1
  export function deserializeBoolean(srcStart: usize, srcEnd: usize): boolean {
4
- const srcSize = srcEnd - srcStart;
5
- const firstChar = load<u16>(srcStart);
6
- if (firstChar == CHAR_T && load<u64>(srcStart) == 28429475166421108) return true;
7
- else if (firstChar == CHAR_F && load<u64>(srcSize, 2) == 28429466576093281) return false;
2
+ const block = load<u64>(srcStart);
3
+ if (block == 28429475166421108) return true;
4
+ else if (block == 32370086184550502 && load<u16>(srcStart, 8) == 101) return false;
8
5
  return false; //throw new Error(`Expected to find boolean, but found "${data.slice(0, 100)}" instead!`);
9
- }
6
+ }
@@ -2,10 +2,10 @@ import { ptrToStr } from "../../util/ptrToStr";
2
2
 
3
3
  export function deserializeDate(srcStart: usize, srcEnd: usize): Date {
4
4
  // Use AssemblyScript's date parser
5
- const d = Date.fromString(ptrToStr(srcStart, srcEnd));
5
+ const d = Date.fromString(ptrToStr(srcStart + 2, srcEnd - 2));
6
6
 
7
7
  // Return a new object instead of the one that the parser returned.
8
- // This may seem redundant, but addreses the issue when Date
8
+ // This may seem redundant, but it addresses the issue when Date
9
9
  // is globally aliased to wasi_Date (or some other superclass).
10
10
  return new Date(d.getTime());
11
11
  }
@@ -1,5 +1,7 @@
1
+ import { JSON } from "../..";
1
2
  import { BACK_SLASH, COMMA, CHAR_F, BRACE_LEFT, BRACKET_LEFT, CHAR_N, QUOTE, BRACE_RIGHT, BRACKET_RIGHT, CHAR_T } from "../../custom/chars";
2
3
  import { isSpace } from "../../util";
4
+ import { ptrToStr } from "../../util/ptrToStr";
3
5
 
4
6
  export function deserializeObject<T>(srcStart: usize, srcEnd: usize, dst: usize): T {
5
7
  const out = changetype<nonnull<T>>(dst || __new(offsetof<T>(), idof<T>()));
@@ -60,9 +62,9 @@ export function deserializeObject<T>(srcStart: usize, srcEnd: usize, dst: usize)
60
62
  while (srcStart < srcEnd) {
61
63
  const code = load<u16>(srcStart);
62
64
  if (code == COMMA || code == BRACE_RIGHT || isSpace(code)) {
65
+ // console.log("Value (number): " + ptrToStr(lastIndex, srcStart));
63
66
  // @ts-ignore: exists
64
67
  out.__DESERIALIZE(keyStart, keyEnd, lastIndex, srcStart, dst);
65
- // console.log("Value (number): " + ptrToStr(lastIndex, srcStart));
66
68
  // while (isSpace(load<u16>((srcStart += 2)))) {
67
69
  // /* empty */
68
70
  // }
package/assembly/index.ts CHANGED
@@ -36,6 +36,11 @@ export type Raw = string;
36
36
  * JSON Encoder/Decoder for AssemblyScript
37
37
  */
38
38
  export namespace JSON {
39
+ export namespace Memory {
40
+ export function shrink(): void {
41
+ bs.resize(64);
42
+ }
43
+ }
39
44
  /**
40
45
  * Serializes valid JSON data
41
46
  * ```js
@@ -107,9 +112,7 @@ export namespace JSON {
107
112
  serializeString(changetype<string>(data));
108
113
  return bs.out<string>();
109
114
  // @ts-ignore: Supplied by transform
110
- } else if (isDefined(data.__SERIALIZE) && isDefined(data.__ALLOCATE)) {
111
- // @ts-ignore
112
- // data.__ALLOCATE();
115
+ } else if (isDefined(data.__SERIALIZE)) {
113
116
  // @ts-ignore
114
117
  data.__SERIALIZE(changetype<usize>(data));
115
118
  return bs.out<string>();
@@ -119,8 +122,8 @@ export namespace JSON {
119
122
 
120
123
  store<u16>(changetype<usize>(out), QUOTE);
121
124
  memory.copy(changetype<usize>(out) + 2, changetype<usize>(data.toISOString()), 48);
122
- store<u16>(changetype<usize>(out), 50);
123
- return out;
125
+ store<u16>(changetype<usize>(out), QUOTE, 50);
126
+ return changetype<string>(out);
124
127
  } else if (data instanceof Array) {
125
128
  // @ts-ignore
126
129
  serializeArray(changetype<nonnull<T>>(data));
@@ -156,7 +159,7 @@ export namespace JSON {
156
159
  return deserializeInteger<T>(dataPtr, dataPtr + dataSize);
157
160
  } else if (isFloat<T>()) {
158
161
  return deserializeFloat<T>(dataPtr, dataPtr + dataSize);
159
- } else if (isNullable<T>() && data.length == 4 && data == "null") {
162
+ } else if (isNullable<T>() && dataSize == 8 && load<u64>(dataPtr) == 30399761348886638) {
160
163
  // @ts-ignore
161
164
  return null;
162
165
  } else if (isString<T>()) {
@@ -182,7 +185,7 @@ export namespace JSON {
182
185
  return deserializeDate(dataPtr, dataPtr + dataSize);
183
186
  } else if (type instanceof JSON.Box) {
184
187
  // @ts-ignore
185
- return new JSON.Box(JSON.parse<indexof<T>>(data));
188
+ return new JSON.Box(parseBox(data, changetype<nonnull<T>>(0).value));
186
189
  } else {
187
190
  throw new Error(`Could not deserialize data ${data} to type ${nameof<T>()}. Make sure to add the correct decorators to classes.`);
188
191
  }
@@ -339,7 +342,9 @@ export namespace JSON {
339
342
  * Box for primitive types
340
343
  */
341
344
  export class Box<T> {
342
- constructor(public value: T) {}
345
+ constructor(public value: T) {
346
+ if (!isInteger<T>() && !isFloat<T>()) ERROR("JSON.Box should only hold primitive types!");
347
+ }
343
348
  /**
344
349
  * Creates a reference to a primitive type
345
350
  * This means that it can create a nullable primitive
@@ -353,6 +358,12 @@ export namespace JSON {
353
358
  @inline static from<T>(value: T): Box<T> {
354
359
  return new Box(value);
355
360
  }
361
+ toString(): string {
362
+ if (isNullable<this>() && changetype<usize>(this) == null) return "null";
363
+ // @ts-ignore: type
364
+ if (isDefined(this.value.toString)) return this.value.toString();
365
+ return "null";
366
+ }
356
367
  }
357
368
 
358
369
  export function __serialize<T>(src: T): void {
@@ -421,8 +432,20 @@ export namespace JSON {
421
432
  } else if (type instanceof Date) {
422
433
  // @ts-ignore: type
423
434
  return deserializeDate(srcStart, srcEnd);
435
+ } else if (type instanceof JSON.Box) {
436
+ // @ts-ignore: type
437
+ return new JSON.Box(deserializeBox(srcStart, srcEnd, dst, changetype<nonnull<T>>(0).value));
424
438
  }
425
439
  }
426
440
  throw new Error(`Could not deserialize data '${ptrToStr(srcStart, srcEnd).slice(0, 100)}' to type. Make sure to add the correct decorators to classes.`);
427
441
  }
428
442
  }
443
+
444
+ // @ts-ignore: decorator
445
+ @inline function parseBox<T>(data: string, ty: T): T {
446
+ return JSON.parse<T>(data);
447
+ }
448
+
449
+ function deserializeBox<T>(srcStart: usize, srcEnd: usize, dst: usize, ty: T): T {
450
+ return JSON.__deserialize<T>(srcStart, srcEnd, dst);
451
+ }
@@ -18,7 +18,7 @@ export function serializeString_SIMD(src: string): void {
18
18
  const srcSize = changetype<OBJECT>(changetype<usize>(src) - TOTAL_OVERHEAD).rtSize;
19
19
  let srcStart = changetype<usize>(src);
20
20
  const srcEnd = srcStart + srcSize;
21
- bs.ensureSize(srcSize + 4);
21
+ bs.proposeSize(srcSize + 4);
22
22
  const srcEnd16 = srcEnd - 15;
23
23
 
24
24
  store<u8>(changetype<usize>(bs.offset), 34); /* " */
@@ -45,13 +45,13 @@ export function serializeString_SIMD(src: string): void {
45
45
  mask &= mask - 1;
46
46
 
47
47
  if ((escaped & 0xffff) != BACK_SLASH) {
48
- bs.addSize(10);
48
+ bs.growSize(10);
49
49
  store<u64>(dst_offset, 13511005048209500);
50
50
  store<u32>(dst_offset, escaped, 8);
51
51
  v128.store(dst_offset, v128.load(src_offset, 2), 12);
52
52
  bs.offset += 10;
53
53
  } else {
54
- bs.addSize(2);
54
+ bs.growSize(2);
55
55
  store<u32>(dst_offset, escaped);
56
56
  v128.store(dst_offset, v128.load(src_offset, 2), 4);
57
57
  bs.offset += 2;
@@ -84,7 +84,7 @@ export function serializeString_SIMD(src: string): void {
84
84
  mask &= mask - 1;
85
85
 
86
86
  if ((escaped & 0xffff) != BACK_SLASH) {
87
- bs.addSize(10);
87
+ bs.growSize(10);
88
88
  store<u64>(dst_offset, 13511005048209500);
89
89
  store<u32>(dst_offset, escaped, 8);
90
90
  while (lane_index < 6) {
@@ -93,7 +93,7 @@ export function serializeString_SIMD(src: string): void {
93
93
  }
94
94
  bs.offset += 10;
95
95
  } else {
96
- bs.addSize(2);
96
+ bs.growSize(2);
97
97
  store<u32>(dst_offset, escaped);
98
98
 
99
99
  while (lane_index < 6) {
@@ -116,12 +116,12 @@ export function serializeString_SIMD(src: string): void {
116
116
  const escaped = load<u32>(SERIALIZE_ESCAPE_TABLE + (codeA << 2));
117
117
 
118
118
  if ((escaped & 0xffff) != BACK_SLASH) {
119
- bs.addSize(10);
119
+ bs.growSize(10);
120
120
  store<u64>(bs.offset, 13511005048209500);
121
121
  store<u32>(bs.offset, escaped, 8);
122
122
  bs.offset += 12;
123
123
  } else {
124
- bs.addSize(2);
124
+ bs.growSize(2);
125
125
  store<u32>(bs.offset, escaped);
126
126
  bs.offset += 4;
127
127
  }
@@ -134,12 +134,12 @@ export function serializeString_SIMD(src: string): void {
134
134
  const escaped = load<u32>(SERIALIZE_ESCAPE_TABLE + (codeB << 2));
135
135
 
136
136
  if ((escaped & 0xffff) != BACK_SLASH) {
137
- bs.addSize(10);
137
+ bs.growSize(10);
138
138
  store<u64>(bs.offset, 13511005048209500);
139
139
  store<u32>(bs.offset, escaped, 8);
140
140
  bs.offset += 12;
141
141
  } else {
142
- bs.addSize(2);
142
+ bs.growSize(2);
143
143
  store<u32>(bs.offset, escaped);
144
144
  bs.offset += 4;
145
145
  }
@@ -156,12 +156,12 @@ export function serializeString_SIMD(src: string): void {
156
156
  const escaped = load<u32>(SERIALIZE_ESCAPE_TABLE + (code << 2));
157
157
 
158
158
  if ((escaped & 0xffff) != BACK_SLASH) {
159
- bs.addSize(10);
159
+ bs.growSize(10);
160
160
  store<u64>(bs.offset, 13511005048209500);
161
161
  store<u32>(bs.offset, escaped, 8);
162
162
  bs.offset += 12;
163
163
  } else {
164
- bs.addSize(2);
164
+ bs.growSize(2);
165
165
  store<u32>(bs.offset, escaped);
166
166
  bs.offset += 4;
167
167
  }
@@ -3,15 +3,16 @@ import { COMMA, BRACKET_RIGHT, BRACKET_LEFT } from "../../custom/chars";
3
3
  import { JSON } from "../..";
4
4
 
5
5
  export function serializeArray<T extends any[]>(src: T): void {
6
+ bs.proposeSize(4);
6
7
  const end = src.length - 1;
7
8
  let i = 0;
8
9
  if (end == -1) {
9
- bs.proposeSize(4);
10
10
  store<u32>(bs.offset, 6094939);
11
11
  bs.offset += 4;
12
12
  return;
13
13
  }
14
- bs.proposeSize(end << 3);
14
+ // {} = 4
15
+ // xi, = n << 1
15
16
 
16
17
  store<u16>(bs.offset, BRACKET_LEFT);
17
18
  bs.offset += 2;
@@ -26,7 +27,7 @@ export function serializeArray<T extends any[]>(src: T): void {
26
27
 
27
28
  const lastBlock = unchecked(src[end]);
28
29
  JSON.__serialize<valueof<T>>(lastBlock);
29
- bs.proposeSize(2);
30
+ bs.growSize(2);
30
31
  store<u16>(bs.offset, BRACKET_RIGHT);
31
32
  bs.offset += 2;
32
33
  }
@@ -2,6 +2,6 @@ import { dtoa_buffered } from "util/number";
2
2
  import { bs } from "../../../modules/as-bs";
3
3
 
4
4
  export function serializeFloat<T extends number>(data: T): void {
5
- bs.proposeSize(64);
5
+ bs.ensureSize(64);
6
6
  bs.offset += dtoa_buffered(bs.offset, data) << 1;
7
7
  }
@@ -2,6 +2,11 @@ import { itoa_buffered } from "util/number";
2
2
  import { bs } from "../../../modules/as-bs";
3
3
 
4
4
  export function serializeInteger<T extends number>(data: T): void {
5
- bs.proposeSize(sizeof<T>() << 3);
6
- bs.offset += itoa_buffered(bs.offset, data) << 1;
5
+ bs.ensureSize(sizeof<T>() << 3);
6
+ const bytesWritten = itoa_buffered(bs.offset, data) << 1;
7
+ bs.offset += bytesWritten;
8
+ bs.growSize(bytesWritten);
7
9
  }
10
+
11
+ // 32 {"x":,"y":,"z"}
12
+ // 18 3.41.28.3
package/assembly/test.ts CHANGED
@@ -1,5 +1,59 @@
1
- import { JSON } from "./";
2
- import { describe, expect } from "../modules/test/assembly";
1
+ import { JSON } from ".";
2
+ import { bytes } from "./util";
3
3
 
4
- console.log(JSON.stringify(JSON.parse<string>('"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u000f\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f"')));
5
- console.log('"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u000f\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f"');
4
+ @json
5
+ class Obj {
6
+ public a: string = "hello";
7
+ public b: string = "world";
8
+ public c: string = "\"\t\f\u0000\u0001";
9
+ }
10
+
11
+ @json
12
+ class Vec3 {
13
+ x: f32 = 0.0;
14
+ y: f32 = 0.0;
15
+ z: f32 = 0.0;
16
+ }
17
+
18
+ @json
19
+ class Player {
20
+ @alias("first name")
21
+ firstName!: string;
22
+ lastName!: string;
23
+ lastActive!: i32[];
24
+ // Drop in a code block, function, or expression that evaluates to a boolean
25
+ @omitif((age) => age < 18)
26
+ @omitif('this.age <= 0')
27
+ age!: i32;
28
+ @omitnull()
29
+ pos!: Vec3 | null;
30
+ isVerified!: boolean;
31
+ }
32
+
33
+ const player: Player = {
34
+ firstName: "Jairus",
35
+ lastName: "Tanaka",
36
+ lastActive: [2, 7, 2025],
37
+ age: 18,
38
+ pos: {
39
+ x: 3.4,
40
+ y: 1.2,
41
+ z: 8.3
42
+ },
43
+ isVerified: true
44
+ };
45
+
46
+ const a1 = JSON.stringify("\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000a\u000b\u000c\u000d\u000e\u000f\u000f\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f");
47
+ // console.log("Bytes " + bytes(a1).toString());
48
+ console.log("a1: " + a1);
49
+
50
+ const obj = new Obj();
51
+ const a2 = JSON.stringify(obj);
52
+ // console.log("Bytes " + bytes(a2).toString());
53
+ console.log("a2: " + a2);
54
+
55
+ const a3 = JSON.stringify(player);
56
+ // console.log("Bytes " + bytes(a3).toString());
57
+ console.log("a3: " + a3);
58
+
59
+ JSON.Memory.shrink();
@@ -7,7 +7,7 @@ import { POW_TEN_TABLE_32, POW_TEN_TABLE_64 } from "../globals/tables";
7
7
  import { atoi } from "./atoi";
8
8
 
9
9
  // @ts-ignore: Decorator valid here
10
- @inline function snp<T extends number>(srcStart: usize, srcEnd: usize): T {
10
+ @inline export function snp<T extends number>(srcStart: usize, srcEnd: usize): T {
11
11
  // @ts-ignore: type
12
12
  let val: T = 0;
13
13
  let char = load<u16>(srcStart) - 48;
@@ -46,7 +46,7 @@ import { atoi } from "./atoi";
46
46
  char = load<u16>(srcStart);
47
47
  if (char == 45) {
48
48
  // @ts-ignore: type
49
- return val / pow10(atoi(srcStart + 2, srcEnd));
49
+ return val / pow10(atoi<u8>(srcStart + 2, srcEnd));
50
50
  } else {
51
51
  // @ts-ignore: type
52
52
  return val * pow10(atoi(srcStart, srcEnd));