json-as 0.5.35 → 0.5.37

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/LICENSE CHANGED
File without changes
package/README.md CHANGED
@@ -8,15 +8,6 @@ JSON for AssemblyScript focused on performance, low-overhead, and ease-of-use.
8
8
  ```bash
9
9
  npm install json-as
10
10
  ```
11
- ```bash
12
- npm install visitor-as --save-dev
13
- ```
14
-
15
- For arbitrary-length numbers, use
16
-
17
- ```bash
18
- npm install as-bignum
19
- ```
20
11
 
21
12
  Add the transform to your `asc` command (e.g. in package.json)
22
13
 
@@ -75,26 +66,29 @@ const stringified = JSON.stringify<Player>(player);
75
66
  const parsed = JSON.parse<Player>(stringified);
76
67
  ```
77
68
 
78
- ## Planned Features
79
-
80
- - [x] Serialize
81
- - [x] Objects
82
- - [x] Other Types
83
- - [ ] Dynamic Types
84
- - [x] Deserialize
85
- - [x] Objects
86
- - [x] Other Types
87
- - [ ] Dynamic Types
88
- - [ ] Streaming API
89
- - [ ] Whitespace support
90
- - [ ] Integrate features from SIMDJson
91
- - [x] Optimize
92
- - [x] Strings
93
- - [x] Int/Float
94
- - [x] Bool
95
- - [x] Object Serialization
96
- - [ ] Object Parsing
97
- - [ ] Arrays
69
+ ## Deviations from the spec
70
+
71
+ This implementation does not hold strongly to the JSON specification. Rather, design and behavior are inspired by the JSON implementation found in Google's v8 engine.
72
+
73
+ - No support for dynamic types
74
+ - Unsafe by design--parser assumes valid JSON
75
+ - Partial whitespace support--parser prefers speed over handling whitespace effectively. Users may use the `removeWhitespace` function provided by `json-as/src/util.ts`
76
+ - Is not based off of the official spec, but rather the behavior of the JSON C implementation found in google's v8 engine
77
+ - Support for scientific notation on integers. Float support coming soon.
78
+
79
+ ## Implemented features
80
+
81
+ Fully supports:
82
+
83
+ - Strings
84
+ - Integers
85
+ - Floats (Scientific notation not implemented)
86
+ - Booleans
87
+ - Arrays
88
+ - Objects
89
+ - Date
90
+ - Null
91
+
98
92
  ## Performance
99
93
 
100
94
  Number parsing speed has doubled over the last 5 versions due to the use of a `atoi_fast` function found in `assembly/util.ts`. This can be further optimized with SIMD.
@@ -107,7 +101,7 @@ Schema (object) parsing is being optimized on GitHub and should be at least doub
107
101
 
108
102
  **Serialize Object (Vec3):** 6.7m ops/5s
109
103
 
110
- **Deserialize Object (Vec3):** 3.8m ops/5s
104
+ **Deserialize Object (Vec3):** 5.1m ops/5s
111
105
 
112
106
  **Serialize Array (int[]):** 6.6m ops/5s
113
107
 
File without changes
package/as-pect.config.js CHANGED
File without changes
package/asconfig.json CHANGED
File without changes
@@ -1,6 +1,6 @@
1
1
  import { JSON } from "..";
2
2
  import { backSlashCode, quoteCode } from "../src/chars";
3
- import { atoi_fast, unsafeCharCodeAt } from "../src/util";
3
+ import { atoi_fast, parseSciInteger, unsafeCharCodeAt } from "../src/util";
4
4
  import { HASH } from "util/hash";
5
5
 
6
6
  @json
@@ -24,11 +24,11 @@ class Vec3 {
24
24
  if (inStr === false && char === quoteCode) {
25
25
  if (key != null) {
26
26
  if (unsafeCharCodeAt(key, 0) == 120) {
27
- to.x = atoi_fast<i32>(data.substring(last, pos - 1))
27
+ to.x = parseSciInteger<i32>(data.substring(last, pos - 1))
28
28
  } else if (unsafeCharCodeAt(key, 0) == 121) {
29
- to.y = atoi_fast<i32>(data.substring(last, pos - 1))
29
+ to.y = parseSciInteger<i32>(data.substring(last, pos - 1))
30
30
  } else if (unsafeCharCodeAt(key, 0) == 122) {
31
- to.z = atoi_fast<i32>(data.substring(last, pos - 1))
31
+ to.z = parseSciInteger<i32>(data.substring(last, pos - 1))
32
32
  }
33
33
  }
34
34
  last = ++pos;
@@ -41,11 +41,11 @@ class Vec3 {
41
41
  }
42
42
  if (key != null) {
43
43
  if (unsafeCharCodeAt(key, 0) == 120) {
44
- to.x = atoi_fast<i32>(data.substring(last, pos - 1))
44
+ to.x = parseSciInteger<i32>(data.substring(last, pos - 1))
45
45
  } else if (unsafeCharCodeAt(key, 0) == 121) {
46
- to.y = atoi_fast<i32>(data.substring(last, pos - 1))
46
+ to.y = parseSciInteger<i32>(data.substring(last, pos - 1))
47
47
  } else if (unsafeCharCodeAt(key, 0) == 122) {
48
- to.z = atoi_fast<i32>(data.substring(last, pos - 1))
48
+ to.z = parseSciInteger<i32>(data.substring(last, pos - 1))
49
49
  }
50
50
  }
51
51
  return to;
@@ -63,8 +63,8 @@ const vecOut = new Vec3();
63
63
  const i32Max = blackbox("429496729");
64
64
  /*
65
65
  bench("Stringify Object (Vec3)", () => {
66
- blackbox<string>(vec.__JSON_Serialize(vec));
67
- });*/
66
+ blackbox<string>(vec.__JSON_Serialize());
67
+ });
68
68
 
69
69
  bench("HASH String", () => {
70
70
  blackbox<number>(HASH("Hello"));
@@ -89,7 +89,7 @@ bench("Stringify Boolean Array", () => {
89
89
  bench("Stringify String Array", () => {
90
90
  blackbox(JSON.stringify<string[]>(["a", "b", "c"]));
91
91
  });
92
-
92
+ */
93
93
  bench("Stringify String", () => {
94
94
  blackbox(JSON.stringify(blackbox("Hello \"World!")));
95
95
  });
@@ -97,7 +97,7 @@ bench("Stringify String", () => {
97
97
  bench("Parse String", () => {
98
98
  blackbox(JSON.parse<string>(blackbox('"Hello \"World!"')));
99
99
  });
100
-
100
+ /*
101
101
  bench("Stringify Boolean", () => {
102
102
  blackbox(JSON.stringify(blackbox(true)));
103
103
  });
@@ -120,4 +120,4 @@ bench("Stringify Float", () => {
120
120
 
121
121
  bench("Parse Float", () => {
122
122
  blackbox(JSON.parse<f32>(blackbox("3.14")));
123
- });
123
+ });*/
File without changes
File without changes
File without changes
package/assembly/index.ts CHANGED
File without changes
File without changes
@@ -1,6 +1,4 @@
1
- import { u128, u128Safe, u256, u256Safe, i128, i128Safe } from "as-bignum/assembly";
2
1
  import { StringSink } from "as-string-sink/assembly";
3
- import { itoa32, itoa64, dtoa, dtoa_buffered } from "util/number";
4
2
  import { isSpace } from "util/string";
5
3
  import {
6
4
  backSlashCode,
@@ -23,7 +21,7 @@ import {
23
21
  uCode,
24
22
  emptyArrayWord
25
23
  } from "./chars";
26
- import { atoi_fast, escapeChar, isBigNum, unsafeCharCodeAt } from "./util";
24
+ import { parseSciInteger, unsafeCharCodeAt } from "./util";
27
25
 
28
26
  /**
29
27
  * JSON Encoder/Decoder for AssemblyScript
@@ -94,9 +92,6 @@ export namespace JSON {
94
92
  result.write(rightBracketWord);
95
93
  return result.toString();
96
94
  }
97
- } else if ((isManaged<T>() || isReference<T>()) && isBigNum<T>()) {
98
- // @ts-ignore
99
- return data.toString();
100
95
  } else {
101
96
  throw new Error(`Could not serialize data of type ${nameof<T>()}. Make sure to add the correct decorators to classes.`);
102
97
  }
@@ -133,9 +128,6 @@ export namespace JSON {
133
128
  } else if (idof<nonnull<T>>() == idof<Date>()) {
134
129
  // @ts-ignore
135
130
  return Date.fromString(data);
136
- } else if ((isManaged<T>() || isReference<T>()) && isBigNum<T>()) {
137
- // @ts-ignore
138
- return parseBigNum<T>(data);
139
131
  } else {
140
132
  // @ts-ignore
141
133
  throw new Error(`Could not deserialize data ${data} to type ${nameof<T>()}. Make sure to add the correct decorators to classes.`);
@@ -206,9 +198,6 @@ export namespace JSON {
206
198
  } else if (idof<nonnull<T>>() == idof<Date>()) {
207
199
  // @ts-ignore
208
200
  return Date.fromString(data);
209
- } else if ((isManaged<T>() || isReference<T>()) && isBigNum<T>()) {
210
- // @ts-ignore
211
- return parseBigNum<T>(data);
212
201
  } else {
213
202
  // @ts-ignore
214
203
  throw new Error(`Could not deserialize data ${data} to type ${nameof<T>()}. Make sure to add the correct decorators to classes.`)
@@ -221,8 +210,8 @@ export namespace JSON {
221
210
  @inline
222
211
  function serializeString(data: string): string {
223
212
  // @ts-ignore
224
- if (data.length === 0) return "\"\"";
225
- // Fast path for Vectors (3)
213
+ //if (data.length === 0) return "\"\"";
214
+ /*
226
215
  let char: i32 = 0;
227
216
  if (data.length === 1) {
228
217
  char = unsafeCharCodeAt(data, 0);
@@ -254,29 +243,26 @@ function serializeString(data: string): string {
254
243
  } else {
255
244
  return data;
256
245
  }
257
- }
246
+ }*/
258
247
 
259
248
  let result = "\"";
260
249
 
261
250
  let last: i32 = 0;
262
- let found: boolean = false;
263
251
  // @ts-ignore
264
252
  for (let i = 0; i < data.length; i++) {
265
- char = unsafeCharCodeAt(<string>data, i);
253
+ const char = unsafeCharCodeAt(<string>data, i);
266
254
  if (char === 34 || char === 92) {
267
255
  result += (<string>data).slice(last, i) + "\\";
268
256
  last = i;
269
- found = true;
270
257
  i++;
271
258
  } else if (char <= 13 && char >= 8) {
272
259
  result += (<string>data).slice(last, i);
273
260
  last = ++i;
274
- found = true;
275
261
  switch (char) {
276
- case 0x5C: {
262
+ /*case 0x5C: {
277
263
  result += "\\\\";
278
264
  break;
279
- }
265
+ }*/
280
266
  case 0x08: {
281
267
  result += "\\b";
282
268
  break;
@@ -300,40 +286,20 @@ function serializeString(data: string): string {
300
286
  }
301
287
  }
302
288
  }// 8 10 13 9 12
303
- if (!found) return "\"" + data + "\"";
289
+ if (result.length === 1) return "\"" + data + "\"";
304
290
  else result += (<string>data).slice(last);
305
291
  return result + "\"";
306
292
  }
307
- // @ts-ignore
308
- @inline
309
- // @ts-ignore
310
- function parseBigNum<T>(data: string): T {
311
- // @ts-ignore
312
- if (idof<T>() == idof<u128>()) return u128.fromString(data);
313
- // @ts-ignore
314
- if (idof<T>() == idof<u128Safe>()) return u128Safe.fromString(data);
315
- // @ts-ignore
316
- if (idof<T>() == idof<u256>()) return u128Safe.fromString(data);
317
- // @ts-ignore
318
- if (idof<T>() == idof<u256Safe>()) return u256Safe.fromString(data);
319
- // @ts-ignore
320
- if (idof<T>() == idof<i128>()) return i128.fromString(data);
321
- // @ts-ignore
322
- if (idof<T>() == idof<i128Safe>()) return i128Safe.fromString(data);
323
- // @ts-ignore
324
- //if (idof<T>() == idof<i256Safe>()) return data.
325
- }
326
293
 
327
294
  // @ts-ignore
328
295
  @inline
329
296
  function parseString(data: string): string {
330
297
  let result = "";
331
298
  let last = 1;
332
- let char = 0;
333
299
  for (let i = 1; i < data.length - 1; i++) {
334
300
  // \\"
335
301
  if (unsafeCharCodeAt(data, i) === backSlashCode) {
336
- char = unsafeCharCodeAt(data, ++i);
302
+ const char = unsafeCharCodeAt(data, ++i);
337
303
  result += data.slice(last, i - 1)
338
304
  if (char === 34) {
339
305
  result += "\"";
@@ -343,25 +309,40 @@ function parseString(data: string): string {
343
309
  last = ++i;
344
310
  // 92 98 114 116 102 117
345
311
  } else if (char >= 92 && char <= 117) {
346
- if (char === 92) {
347
- result += "\\";
348
- last = ++i;
349
- } else if (char === 98) {
350
- result += "\b";
351
- last = ++i;
352
- } else if (char === 102) {
353
- result += "\f";
354
- last = ++i;
355
- } else if (char === 114) {
356
- result += "\r";
357
- last = ++i;
358
- } else if (char === 116) {
359
- result += "\t";
360
- last = ++i;
361
- } else if (char === 117 && load<u64>(changetype<usize>(data) + <usize>((i + 1) << 1)) === 27584753879220272) {
362
- result += "\u000b";
363
- i += 4;
364
- last = ++i;
312
+ switch (char) {
313
+ case 92: {
314
+ result += "\\";
315
+ last = ++i;
316
+ break;
317
+ }
318
+ case 98: {
319
+ result += "\b";
320
+ last = ++i;
321
+ break;
322
+ }
323
+ case 102: {
324
+ result += "\f";
325
+ last = ++i;
326
+ break;
327
+ }
328
+ case 114: {
329
+ result += "\r";
330
+ last = ++i;
331
+ break;
332
+ }
333
+ case 116: {
334
+ result += "\t";
335
+ last = ++i;
336
+ break;
337
+ }
338
+ default: {
339
+ if (char === 117 && load<u64>(changetype<usize>(data) + <usize>((i + 1) << 1)) === 27584753879220272) {
340
+ result += "\u000b";
341
+ i += 4;
342
+ last = ++i;
343
+ }
344
+ break;
345
+ }
365
346
  }
366
347
  }
367
348
  }
@@ -384,7 +365,7 @@ function parseBoolean<T extends boolean>(data: string): T {
384
365
  export function parseNumber<T>(data: string): T {
385
366
  if (isInteger<T>()) {
386
367
  // @ts-ignore
387
- return atoi_fast<T>(data);
368
+ return parseSciInteger<T>(data);
388
369
  }
389
370
  // @ts-ignore
390
371
  const type: T = 0;
@@ -1,20 +1,6 @@
1
1
  import { StringSink } from "as-string-sink/assembly";
2
2
  import { CharCode, isSpace } from "util/string";
3
3
  import { backSlashCode, quoteCode } from "./chars";
4
- import { u128, u128Safe, u256, u256Safe, i128, i128Safe, i256Safe } from "as-bignum/assembly";
5
-
6
- // @ts-ignore
7
- @inline
8
- export function isBigNum<T>(): boolean {
9
- if (idof<T>() == idof<u128>()) return true;
10
- if (idof<T>() == idof<u128Safe>()) return true;
11
- if (idof<T>() == idof<u256>()) return true;
12
- if (idof<T>() == idof<u256Safe>()) return true;
13
- if (idof<T>() == idof<i128>()) return true;
14
- if (idof<T>() == idof<i128Safe>()) return true;
15
- if (idof<T>() == idof<i256Safe>()) return true;
16
- return false;
17
- }
18
4
 
19
5
  // @ts-ignore
20
6
  @inline
@@ -56,7 +42,7 @@ export function escapeChar(char: string): string {
56
42
  case 0x09: return "\\t";
57
43
  case 0x0C: return "\\f";
58
44
  case 0x0B: return "\\u000b";
59
- default: return char;
45
+ default: return char;
60
46
  }
61
47
  }
62
48
 
@@ -81,21 +67,67 @@ export function getArrayDepth<T>(depth: i32 = 1): i32 {
81
67
 
82
68
  /**
83
69
  * Implementation of ATOI. Can be much much faster with SIMD.
84
- * Its pretty fast. (173m ops (atoi_fast) vs 89 ops (parseInt))
70
+ * Benchmark: 40-46m ops/s
85
71
  */
86
72
  @unsafe
87
73
  @inline
88
- export function atoi_fast<T extends number>(str: string): T {
74
+ export function atoi_fast<T extends number>(str: string, offset: i32 = 0): T {
89
75
  // @ts-ignore
90
76
  let val: T = 0;
91
- for (let pos = 0; pos < (str.length << 1); pos += 2) {
77
+ for (; offset < (str.length << 1); offset += 2) {
92
78
  // @ts-ignore
93
- val = (val << 1) + (val << 3) + (load<u16>(changetype<usize>(str) + <usize>pos) - 48);
79
+ val = (val << 1) + (val << 3) + (load<u16>(changetype<usize>(str) + <usize>offset) - 48);
94
80
  // We use load because in this case, there is no need to have bounds-checking
95
81
  }
96
82
  return val;
97
83
  }
98
84
 
99
85
  /**
100
- *
101
- */
86
+ * Parses an integer using atoi_fast and applies the appended exponential number to it as scientific notation.
87
+ * Benchmark: Hovers around 30m ops/s
88
+ * Only safe if the string is valid.
89
+ * @param str integer to parse. example: 123e1, 123e-1, 123E100
90
+ * @returns
91
+ */
92
+ @inline
93
+ export function parseSciInteger<T extends number>(str: string): T {
94
+ // @ts-ignore
95
+ let val: T = 0;
96
+ let offset = 0;
97
+ for (; offset < (str.length << 1); offset += 2) {
98
+ const char = load<u16>(changetype<usize>(str) + <usize>offset);
99
+ if (char === 101 || char === 69) {
100
+ const char = load<u16>(changetype<usize>(str) + <usize>(offset += 2));
101
+ if (char === 45) {
102
+ // @ts-ignore
103
+ val /= sciNote<T>(atoi_fast<T>(str, offset += 2));
104
+ // @ts-ignore
105
+ return val;
106
+ } else {
107
+ // @ts-ignore
108
+ val *= sciNote<T>(atoi_fast<T>(str, offset));
109
+ // @ts-ignore
110
+ return val;
111
+ }
112
+ }
113
+ // @ts-ignore
114
+ val = (val << 1) + (val << 3) + (char - 48);
115
+ // We use load because in this case, there is no need to have bounds-checking
116
+ }
117
+ return val;
118
+ }
119
+
120
+ function sciNote<T extends number>(num: T): T {
121
+ let res = 1;
122
+ if (num > 0) {
123
+ for (let i = 0; i < num; i++) {
124
+ res *= 10;
125
+ }
126
+ } else {
127
+ for (let i = 0; i < num; i++) {
128
+ res /= 10;
129
+ }
130
+ }
131
+ // @ts-ignore
132
+ return res;
133
+ }
package/assembly/test.ts CHANGED
@@ -1,6 +1,5 @@
1
- import { backSlashCode, quoteCode } from "./src/chars";
2
1
  import { JSON } from "./src/json";
3
- import { atoi_fast, unsafeCharCodeAt } from "./src/util";
2
+ import { atoi_fast, parseSciInteger } from "./src/util";
4
3
 
5
4
  @json
6
5
  class Vec3 {
@@ -51,4 +50,12 @@ console.log(JSON.stringify(parsedVec3));
51
50
 
52
51
  console.log(`atoi_fast("429496729"): ${atoi_fast<i32>("429496729")}`);
53
52
 
54
- console.log(`strtol("429496729"): ${i32.parse("429496729")}`);
53
+ console.log(`strtol("429496729"): ${i32.parse("429496729")}`);
54
+
55
+ console.log(parseSciInteger<i32>("321").toString());
56
+ console.log(parseSciInteger<i32>("321e1").toString());
57
+ console.log(parseSciInteger<i32>("321e2").toString());
58
+ console.log(parseSciInteger<i32>("321e3").toString());
59
+ console.log(parseSciInteger<i32>("321e-1").toString());
60
+
61
+ console.log(atoi_fast<i32>("321e1").toString());
File without changes
package/index.ts CHANGED
File without changes
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "json-as",
3
- "version": "0.5.35",
3
+ "version": "0.5.37",
4
4
  "description": "JSON encoder/decoder for AssemblyScript",
5
5
  "types": "assembly/index.ts",
6
6
  "author": "Jairus Tanaka",
7
7
  "contributors": [
8
8
  "DogWhich",
9
- "Joshua Tenner",
10
- "Rom"
9
+ "Romdotdog",
10
+ "Derek Barrera",
11
+ "Frankk Taylor",
12
+ "lekiano"
11
13
  ],
12
14
  "license": "MIT",
13
15
  "scripts": {
@@ -23,7 +25,6 @@
23
25
  "devDependencies": {
24
26
  "@as-pect/cli": "^8.0.1",
25
27
  "@as-tral/cli": "^2.0.0",
26
- "@assemblyscript/loader": "^0.27.1",
27
28
  "@assemblyscript/wasi-shim": "^0.1.0",
28
29
  "assemblyscript": "^0.27.1",
29
30
  "assemblyscript-prettier": "^1.0.7",
File without changes
File without changes
File without changes
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "@json-as/transform",
3
- "version": "0.5.35",
3
+ "version": "0.5.37",
4
4
  "description": "JSON encoder/decoder for AssemblyScript",
5
5
  "main": "./lib/index.js",
6
6
  "author": "Jairus Tanaka",
7
7
  "contributors": [
8
8
  "DogWhich",
9
- "Joshua Tenner",
10
- "Rom"
9
+ "Romdotdog",
10
+ "Derek Barrera",
11
+ "Frankk Taylor",
12
+ "lekiano"
11
13
  ],
12
14
  "license": "MIT",
13
15
  "devDependencies": {
@@ -31,4 +33,4 @@
31
33
  "homepage": "https://github.com/JairusSW/as-json#readme",
32
34
  "type": "module",
33
35
  "exports": "./lib/index.js"
34
- }
36
+ }
File without changes
@@ -61,7 +61,7 @@ class AsJSONTransform extends BaseVisitor {
61
61
  }
62
62
 
63
63
  const parentSchema = this.schemasList.find((v) => v.name == this.currentClass.parent);
64
- const members = [...node.members, ...(parentSchema ? parentSchema.node.members : [])]
64
+ const members = [...node.members, ...(parentSchema ? parentSchema.node.members : [])];
65
65
 
66
66
  for (const mem of members) {
67
67
  if (mem.type && mem.type.name && mem.type.name.identifier.text) {
@@ -129,7 +129,7 @@ class AsJSONTransform extends BaseVisitor {
129
129
  this.currentClass.setDataStmts.join("")
130
130
  }
131
131
  }
132
- `
132
+ `;
133
133
 
134
134
  const serializeMethod = SimpleParser.parseClassMember(serializeFunc, node);
135
135
  node.members.push(serializeMethod);
@@ -164,7 +164,7 @@ export default class Transformer extends Transform {
164
164
  } else {
165
165
  return 0;
166
166
  }
167
- })
167
+ });
168
168
 
169
169
  // Loop over every source
170
170
  for (const source of sources) {
File without changes
package/tsconfig.json CHANGED
File without changes
package/build/.gitignore DELETED
@@ -1,2 +0,0 @@
1
- *
2
- !.gitignore