json-as 1.3.1 → 1.3.3

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 (55) hide show
  1. package/CHANGELOG.md +9 -26
  2. package/README.md +43 -19
  3. package/assembly/deserialize/index/arbitrary.ts +1 -1
  4. package/assembly/deserialize/index/array.ts +6 -1
  5. package/assembly/deserialize/index/float.ts +1 -1
  6. package/assembly/deserialize/index/integer.ts +1 -1
  7. package/assembly/deserialize/index/unsigned.ts +1 -1
  8. package/assembly/deserialize/simd/string.ts +17 -13
  9. package/assembly/deserialize/simple/arbitrary.ts +1 -1
  10. package/assembly/deserialize/simple/array/generic.ts +42 -0
  11. package/assembly/deserialize/simple/array.ts +8 -1
  12. package/assembly/deserialize/{float.ts → simple/float.ts} +22 -2
  13. package/assembly/deserialize/{integer.ts → simple/integer.ts} +3 -2
  14. package/assembly/deserialize/simple/map.ts +62 -12
  15. package/assembly/deserialize/simple/object.ts +1 -1
  16. package/assembly/deserialize/simple/set.ts +119 -134
  17. package/assembly/deserialize/simple/staticarray.ts +13 -1
  18. package/assembly/deserialize/simple/string.ts +15 -10
  19. package/assembly/deserialize/simple/struct.ts +9 -157
  20. package/assembly/deserialize/simple/typedarray.ts +1 -1
  21. package/assembly/deserialize/{unsigned.ts → simple/unsigned.ts} +3 -2
  22. package/assembly/deserialize/swar/array/array.ts +42 -7
  23. package/assembly/deserialize/swar/array/bool.ts +6 -2
  24. package/assembly/deserialize/swar/array/float.ts +7 -3
  25. package/assembly/deserialize/swar/array/generic.ts +41 -0
  26. package/assembly/deserialize/swar/array/integer.ts +8 -4
  27. package/assembly/deserialize/swar/array/object.ts +21 -4
  28. package/assembly/deserialize/swar/array/shared.ts +19 -4
  29. package/assembly/deserialize/swar/array/string.ts +6 -2
  30. package/assembly/deserialize/swar/array/struct.ts +21 -4
  31. package/assembly/deserialize/swar/array.ts +57 -2
  32. package/assembly/deserialize/swar/string.ts +248 -372
  33. package/assembly/index.d.ts +1 -0
  34. package/assembly/index.ts +77 -19
  35. package/assembly/serialize/index/arbitrary.ts +3 -3
  36. package/assembly/serialize/index/float.ts +1 -1
  37. package/assembly/serialize/index/object.ts +1 -5
  38. package/assembly/serialize/simd/string.ts +4 -5
  39. package/assembly/serialize/simple/arbitrary.ts +3 -3
  40. package/assembly/serialize/simple/array.ts +18 -6
  41. package/assembly/serialize/simple/float.ts +20 -4
  42. package/assembly/serialize/simple/map.ts +10 -27
  43. package/assembly/serialize/simple/object.ts +1 -5
  44. package/assembly/serialize/simple/set.ts +3 -4
  45. package/assembly/serialize/simple/staticarray.ts +4 -3
  46. package/assembly/serialize/simple/typedarray.ts +9 -7
  47. package/assembly/serialize/swar/string.ts +0 -1
  48. package/assembly/tsconfig.json +1 -0
  49. package/assembly/util/dragonbox-cache.ts +4 -0
  50. package/assembly/util/dragonbox.ts +624 -0
  51. package/lib/as-bs.ts +35 -24
  52. package/package.json +26 -18
  53. package/transform/lib/index.d.ts.map +1 -1
  54. package/transform/lib/index.js +508 -148
  55. package/transform/lib/index.js.map +1 -1
package/lib/as-bs.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { OBJECT, TOTAL_OVERHEAD } from "rt/common";
2
- import { heap } from "memory";
2
+ import { __heap_base, heap } from "memory";
3
3
 
4
4
  // Buffer management constants
5
5
  const SHRINK_EVERY_N_MASK: usize = 255; // check every 256 outputs
@@ -227,12 +227,14 @@ export namespace bs {
227
227
 
228
228
  const current = load<usize>(dstFieldPtr);
229
229
  let stringPtr: usize;
230
- if (current != 0 && changetype<OBJECT>(current - TOTAL_OVERHEAD).rtSize == byteLength) {
231
- stringPtr = current;
232
- } else if (current != 0 && current != changetype<usize>("")) {
233
- // @ts-expect-error: __renew is a runtime builtin
234
- stringPtr = __renew(current, byteLength);
235
- store<usize>(dstFieldPtr, stringPtr);
230
+ if (current >= __heap_base) {
231
+ if (changetype<OBJECT>(current - TOTAL_OVERHEAD).rtSize == byteLength) {
232
+ stringPtr = current;
233
+ } else {
234
+ // @ts-expect-error: __renew is a runtime builtin
235
+ stringPtr = __renew(current, byteLength);
236
+ store<usize>(dstFieldPtr, stringPtr);
237
+ }
236
238
  } else {
237
239
  // @ts-expect-error: __new is a runtime builtin
238
240
  stringPtr = __new(byteLength, idof<string>());
@@ -284,18 +286,21 @@ export namespace bs {
284
286
  *
285
287
  * Enable caching by setting the `JSON_CACHE` environment variable:
286
288
  * ```bash
287
- * JSON_CACHE=1 npx asc your-file.ts --transform json-as/transform
289
+ * JSON_CACHE=true npx asc your-file.ts --transform json-as/transform
288
290
  * ```
289
291
  *
290
- * ## Memory Configuration
292
+ * You can also configure cache size directly:
293
+ * - `JSON_CACHE=<int>` => bytes
294
+ * - `JSON_CACHE=<int>kb|mb|gb` => kilobits/megabits/gigabits
295
+ * - `JSON_CACHE=<int>KB|MB|GB` => kilobytes/megabytes/gigabytes
291
296
  *
292
- * The cache uses the following fixed memory allocations:
297
+ * ## Memory Configuration
293
298
  *
294
- * - **CACHE_SIZE** (4096 entries): Number of cache slots. Uses direct-mapped
295
- * caching with pointer-based indexing. Collisions will evict previous entries.
296
- * Memory usage: ~49KB (4096 * 12 bytes per entry)
299
+ * The cache uses a size budget from `JSON_CACHE` (or defaults to 1MB when
300
+ * enabled with `true/on/yes`):
297
301
  *
298
- * - **ARENA_SIZE** (1MB): Circular buffer for storing cached serialized strings.
302
+ * - **CACHE_SIZE**: Number of direct-mapped cache slots. Derived from budget.
303
+ * - **ARENA_SIZE**: Circular buffer for storing cached serialized strings.
299
304
  * When full, wraps around and overwrites oldest entries. Larger values retain
300
305
  * more cached data but consume more memory.
301
306
  *
@@ -322,16 +327,20 @@ export namespace sc {
322
327
  // @ts-expect-error: @inline is a valid decorator
323
328
  @inline export const ENTRY_LEN = offsetof<sc.Entry>("len");
324
329
 
325
- /** Number of cache slots (power of 2 for efficient masking). Set to 0 when caching disabled. */
326
- // @ts-expect-error: JSON_CACHE may not be defined. If so, it will default to 0.
327
- export const CACHE_SIZE = isDefined(JSON_CACHE) ? 1024 : 0;
328
- /** Bitmask for fast modulo operation on cache index */
329
- export const CACHE_MASK = CACHE_SIZE - 1;
330
-
331
- /** Size of the circular arena buffer for cached strings (1MB) */
332
- export const ARENA_SIZE = 1 << 20;
330
+ // @ts-expect-error: JSON_CACHE may not be defined. If so, it will default to false.
331
+ export const CACHE_ENABLED: bool = isDefined(JSON_CACHE) ? JSON_CACHE : false;
332
+ // @ts-expect-error: JSON_CACHE_SIZE may not be defined. If so, it will default to 1MB.
333
+ export const CACHE_BYTES: usize = isDefined(JSON_CACHE_SIZE) ? <usize>JSON_CACHE_SIZE : (1 << 20);
333
334
  /** Minimum serialized length to cache - smaller outputs aren't worth caching */
334
335
  export const MIN_CACHE_LEN: usize = 128;
336
+ /** Size of the circular arena buffer for cached strings */
337
+ export const ARENA_SIZE: usize = CACHE_BYTES >= MIN_CACHE_LEN ? CACHE_BYTES : MIN_CACHE_LEN;
338
+
339
+ /** Number of cache slots (power of 2 for efficient masking). Set to 0 when caching disabled. */
340
+ const CACHE_SIZE_BASE: i32 = CACHE_ENABLED ? i32((ARENA_SIZE >> 10) >= 1 ? (ARENA_SIZE >> 10) : 1) : 0;
341
+ export const CACHE_SIZE: usize = CACHE_ENABLED ? <usize>(1 << (32 - clz<i32>(CACHE_SIZE_BASE - 1))) : 0;
342
+ /** Bitmask for fast modulo operation on cache index */
343
+ export const CACHE_MASK: usize = CACHE_SIZE > 0 ? CACHE_SIZE - 1 : 0;
335
344
 
336
345
  /** Cache entry structure - stores pointer to string, cached output location, and length */
337
346
  @unmanaged
@@ -345,9 +354,9 @@ export namespace sc {
345
354
  }
346
355
 
347
356
  /** Static array of cache entries */
348
- export const entries = new StaticArray<sc.Entry>(CACHE_SIZE);
357
+ export const entries = new StaticArray<sc.Entry>(i32(CACHE_SIZE));
349
358
  /** Circular buffer arena for storing cached serialized strings */
350
- export const arena = new ArrayBuffer(ARENA_SIZE);
359
+ export const arena = new ArrayBuffer(i32(ARENA_SIZE));
351
360
  /** Current write position in the arena */
352
361
  export let arenaPtr: usize = changetype<usize>(arena);
353
362
  /** End boundary of the arena */
@@ -391,7 +400,9 @@ export namespace sc {
391
400
  * @param len - Length of serialized output
392
401
  */
393
402
  export function insertCached(str: usize, start: usize, len: usize): void {
403
+ if (!CACHE_ENABLED || ARENA_SIZE == 0) return;
394
404
  if (len < MIN_CACHE_LEN) return;
405
+ if (len > ARENA_SIZE) return;
395
406
  if (arenaPtr + len > arenaEnd) {
396
407
  // Wrap around to beginning of arena (circular buffer)
397
408
  arenaPtr = changetype<usize>(arena);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-as",
3
- "version": "1.3.1",
3
+ "version": "1.3.3",
4
4
  "author": "Jairus Tanaka",
5
5
  "repository": {
6
6
  "type": "git",
@@ -10,18 +10,19 @@
10
10
  "main": "transform/lib/index.js",
11
11
  "devDependencies": {
12
12
  "@assemblyscript/wasi-shim": "^0.1.0",
13
- "@eslint/js": "^9.0.0",
14
- "@types/node": "^25.0.10",
15
- "as-test": "^1.0.1",
16
- "assemblyscript": "^0.28.9",
17
- "assemblyscript-prettier": "^3.0.1",
13
+ "@eslint/js": "^10.0.1",
14
+ "@types/node": "^25.6.0",
15
+ "as-test": "^1.0.7",
16
+ "assemblyscript": "^0.28.14",
17
+ "assemblyscript-prettier": "^3.0.4",
18
18
  "chartjs-node-canvas": "^5.0.0",
19
19
  "chartjs-plugin-datalabels": "^2.2.0",
20
- "eslint": "^10.0.0",
21
- "prettier": "3.8.1",
20
+ "eslint": "^10.2.0",
21
+ "prettier": "3.8.3",
22
+ "serve": "^14.2.6",
22
23
  "tinybench": "^6.0.0",
23
- "typescript": "^5.9.3",
24
- "typescript-eslint": "^8.0.0"
24
+ "typescript": "^6.0.2",
25
+ "typescript-eslint": "^8.58.2"
25
26
  },
26
27
  "bugs": {
27
28
  "url": "https://github.com/JairusSW/json-as/issues"
@@ -40,7 +41,7 @@
40
41
  "Deon Groenewald"
41
42
  ],
42
43
  "description": "The only JSON library you'll need for AssemblyScript with SIMD and SWAR",
43
- "homepage": "https://github.com/JairusSW/json-as#readme",
44
+ "homepage": "https://docs.jairus.dev/json-as",
44
45
  "files": [
45
46
  "assembly/custom/",
46
47
  "assembly/deserialize/",
@@ -80,16 +81,23 @@
80
81
  },
81
82
  "scripts": {
82
83
  "ci": "act",
83
- "test": "ast test --disable coverage --disable try-as",
84
- "test:ci": "ast test --disable coverage --clean",
84
+ "test": "ast test --parallel",
85
+ "test:fast": "npm run build:transform && JSON_USE_FAST_PATH=1 ast test --parallel --mode swar,simd",
86
+ "fuzz": "ast fuzz",
87
+ "test:fuzz": "ast test --fuzz --parallel",
88
+ "test:ci": "ast test --parallel --clean",
89
+ "test:ci:fast": "JSON_USE_FAST_PATH=1 ast test --parallel --clean",
85
90
  "test:coverage": "ast test --enable coverage",
86
- "bench": "npm run bench:as && npm run bench:js && ./build-charts.sh",
87
- "bench:as": "bash ./run-bench.as.sh",
88
- "bench:js": "bash ./run-bench.js.sh",
89
- "bench:publish": "bash ./publish-benchmarks.sh",
91
+ "bench": "npm run bench:as && npm run bench:js && npm run charts:build",
92
+ "bench:as": "bash ./scripts/run-bench.as.sh",
93
+ "bench:js": "bash ./scripts/run-bench.js.sh",
94
+ "charts": "bun run charts:build && bun run charts:serve",
95
+ "charts:build": "bash ./scripts/build-charts.sh",
96
+ "charts:publish": "bash ./scripts/publish-benchmarks.sh",
97
+ "charts:serve": "serve ./build/charts/",
90
98
  "build:test": "JSON_DEBUG=0 JSON_WRITE=assembly/test.ts asc assembly/test.ts --transform ./transform -o ./build/test.wasm --textFile ./build/test.wat --enable simd --debug --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json",
91
99
  "build:tmp:test": "JSON_DEBUG=1 asc assembly/test.tmp.ts -o ./build/test.wasm --textFile ./build/test.wat --enable simd --debug --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json",
92
- "build:test:wine": "JSON_DEBUG=1 JSON_WRITE=assembly/test.ts NODE_SKIP_PLATFORM_CHECK=1 wine ~/.win-bin/node/node.exe ./node_modules/assemblyscript/bin/asc.js assembly/test.ts --transform ./transform -o ./build/test.wasm --textFile ./build/test.wat --debug --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json",
100
+ "build:test:wine": "JSON_DEBUG=1 JSON_WRITE=assembly/test.ts NODE_SKIP_PLATFORM_CHECK=1 wineconsole --backend=curses ~/.win-bin/node/node.exe ./node_modules/assemblyscript/bin/asc.js assembly/test.ts --transform ./transform -o ./build/test.wasm --textFile ./build/test.wat --debug --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json",
93
101
  "test:wasmtime": "wasmtime ./build/test.wasm",
94
102
  "test:wasmer": "wasmer ./build/test.wasm",
95
103
  "build:transform": "tsc -p ./transform",
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAA4G,eAAe,EAA8G,MAAM,EAAE,OAAO,EAAS,MAAM,EAA6C,MAAM,uCAAuC,CAAC;AAC3X,OAAO,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAK7D,OAAO,EAA2B,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAE7E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAkFvC,qBAAa,aAAc,SAAQ,OAAO;IACxC,MAAM,CAAC,EAAE,EAAE,aAAa,CAAuB;IAExC,OAAO,EAAG,OAAO,CAAC;IAClB,OAAO,EAAG,MAAM,CAAC;IACjB,MAAM,EAAG,MAAM,CAAC;IAChB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAA+B;IAC7D,MAAM,EAAG,MAAM,CAAC;IAChB,OAAO,EAAE,SAAS,CAAmB;IACrC,OAAO,EAAE,eAAe,EAAE,CAAM;IAChC,cAAc,EAAE,MAAM,EAAE,CAAM;IAE9B,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAqB;IAEvD,OAAO,CAAC,4BAA4B;IA6CpC,wBAAwB,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI;IAYtD,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,cAAoB,GAAG,MAAM;IAsC3E,qBAAqB,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI;IA0yCnD,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAItC,oBAAoB,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI;IA6ClD,oBAAoB,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI;IAIjD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI/B,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAuG9B,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,OAAe,GAAG,MAAM,EAAE;IA0BxD,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO;CAc3D;AA4BD,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,SAAS;IAChD,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBvD,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;CAwDjC;AAoKD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO9C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAA4G,eAAe,EAA8G,MAAM,EAAE,OAAO,EAAS,MAAM,EAA6C,MAAM,uCAAuC,CAAC;AAC3X,OAAO,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAK7D,OAAO,EAA2B,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAE7E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAmJvC,qBAAa,aAAc,SAAQ,OAAO;IACxC,MAAM,CAAC,EAAE,EAAE,aAAa,CAAuB;IAExC,OAAO,EAAG,OAAO,CAAC;IAClB,OAAO,EAAG,MAAM,CAAC;IACjB,MAAM,EAAG,MAAM,CAAC;IAChB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAA+B;IAC7D,MAAM,EAAG,MAAM,CAAC;IAChB,OAAO,EAAE,SAAS,CAAmB;IACrC,OAAO,EAAE,eAAe,EAAE,CAAM;IAChC,cAAc,EAAE,MAAM,EAAE,CAAM;IAE9B,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAqB;IAEvD,OAAO,CAAC,4BAA4B;IA6CpC,wBAAwB,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI;IAYtD,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,cAAoB,GAAG,MAAM;IAsC3E,qBAAqB,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI;IAghDnD,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAItC,oBAAoB,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI;IA4ClD,oBAAoB,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI;IAIjD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI/B,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IA+J9B,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,OAAe,GAAG,MAAM,EAAE;IA0BxD,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO;CAc3D;AA4BD,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,SAAS;IAChD,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAyBvD,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;CAwDjC;AAoKD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO9C"}