json-as 1.0.0-beta.9 → 1.0.0
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 → CHANGELOG.md} +41 -0
- package/README.md +102 -96
- package/assembly/__tests__/array.spec.ts +42 -0
- package/assembly/__tests__/float.spec.ts +3 -3
- package/assembly/__tests__/map.spec.ts +7 -0
- package/assembly/__tests__/raw.spec.ts +4 -5
- package/assembly/__tests__/struct.spec.ts +2 -2
- package/assembly/deserialize/simple/arbitrary.ts +8 -4
- package/assembly/deserialize/simple/array/arbitrary.ts +6 -6
- package/assembly/deserialize/simple/array/array.ts +4 -3
- package/assembly/deserialize/simple/array/bool.ts +7 -7
- package/assembly/deserialize/simple/array/float.ts +2 -2
- package/assembly/deserialize/simple/array/integer.ts +1 -1
- package/assembly/deserialize/simple/array/map.ts +1 -1
- package/assembly/deserialize/simple/array/string.ts +3 -3
- package/assembly/deserialize/simple/array/struct.ts +14 -3
- package/assembly/deserialize/simple/array.ts +3 -0
- package/assembly/deserialize/simple/map.ts +93 -75
- package/assembly/deserialize/simple/object.ts +26 -16
- package/assembly/deserialize/simple/struct.ts +31 -19
- package/assembly/index.ts +14 -11
- package/assembly/serialize/simple/array.ts +1 -0
- package/assembly/serialize/simple/bool.ts +1 -0
- package/assembly/serialize/simple/date.ts +1 -0
- package/assembly/serialize/simple/float.ts +1 -0
- package/assembly/serialize/simple/integer.ts +1 -0
- package/assembly/serialize/simple/map.ts +1 -0
- package/assembly/serialize/simple/object.ts +1 -0
- package/assembly/serialize/simple/raw.ts +1 -0
- package/assembly/serialize/simple/string.ts +1 -0
- package/assembly/test.ts +18 -0
- package/index.ts +1 -1
- package/package.json +4 -3
- package/run-tests.sh +1 -1
- package/transform/lib/index.js +29 -69
- package/transform/lib/index.js.map +1 -1
- package/transform/src/index.ts +55 -71
- package/.gitmodules +0 -0
- package/assembly/as-bs.d.ts +0 -53
|
@@ -1,5 +1,46 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 2025-03-09 - 1.0.0
|
|
4
|
+
|
|
5
|
+
- fix: relative paths pointing through node_modules would create a second Source
|
|
6
|
+
- feat: move behavior of `--lib` into transform itself
|
|
7
|
+
- fix: object with an object as a value containing a rhs bracket or brace would exit early [3b33e94](https://github.com/JairusSW/json-as/commit/3b33e9414dc04779d22d65272863372fcd7af4a6)
|
|
8
|
+
|
|
9
|
+
## 2025-03-04 - 1.0.0-beta.17
|
|
10
|
+
|
|
11
|
+
- fix: forgot to build transform
|
|
12
|
+
|
|
13
|
+
## 2025-03-04 - 1.0.0-beta.16
|
|
14
|
+
|
|
15
|
+
- fix: isPrimitive should only trigger on actual primitives
|
|
16
|
+
|
|
17
|
+
## 2025-03-04 - 1.0.0-beta.15
|
|
18
|
+
|
|
19
|
+
- fix: deserialize custom should take in string
|
|
20
|
+
|
|
21
|
+
## 2025-03-04 - 1.0.0-beta.14
|
|
22
|
+
|
|
23
|
+
- fix: reference to nonexistent variable during custom deserialization layer 2
|
|
24
|
+
|
|
25
|
+
## 2025-03-04 - 1.0.0-beta.13
|
|
26
|
+
|
|
27
|
+
- fix: forgot to actually build the transform
|
|
28
|
+
|
|
29
|
+
## 2025-03-04 - 1.0.0-beta.12
|
|
30
|
+
|
|
31
|
+
- fix: build transform
|
|
32
|
+
|
|
33
|
+
## 2025-03-04 - 1.0.0-beta.11
|
|
34
|
+
|
|
35
|
+
- fix: wrongly assumed pointer types within arbitrary deserialization
|
|
36
|
+
- fix: wrong pointer type being passed during map deserialization
|
|
37
|
+
|
|
38
|
+
## 2025-03-04 - 1.0.0-beta.10
|
|
39
|
+
|
|
40
|
+
- fix: transform not generating the right load operations for keys
|
|
41
|
+
- fix: whitespace not working in objects or struct deserialization
|
|
42
|
+
- fix: JSON.Raw not working when deserializing as Map<string, JSON.Raw>
|
|
43
|
+
|
|
3
44
|
## 2025-03-03 - 1.0.0-beta.9
|
|
4
45
|
|
|
5
46
|
- rename: change libs folder to lib
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
7
7
|
█████ ███████ ██████ ██ ████ ██ ██ ███████
|
|
8
8
|
</span>
|
|
9
|
-
AssemblyScript - v1.0.0
|
|
9
|
+
AssemblyScript - v1.0.0
|
|
10
10
|
</pre>
|
|
11
11
|
</h5>
|
|
12
12
|
|
|
@@ -14,6 +14,20 @@
|
|
|
14
14
|
|
|
15
15
|
JSON is the de-facto serialization format of modern web applications, but its serialization and deserialization remain a significant performance bottleneck, especially at scale. Traditional parsing approaches are computationally expensive, adding unnecessary overhead to both clients and servers. This library is designed to mitigate this by leveraging SIMD acceleration and highly optimized transformations.
|
|
16
16
|
|
|
17
|
+
## 🚨 What's new in v1.0.0
|
|
18
|
+
|
|
19
|
+
🔹Breaking changes to the way custom serializers/deserializers function (See Custom Serializers below)
|
|
20
|
+
|
|
21
|
+
🔹Major performance improvements and addition of SIMD
|
|
22
|
+
|
|
23
|
+
🔹Extremely low memory overhead compared to pre-1.x.x versions (great for serverless workloads)
|
|
24
|
+
|
|
25
|
+
🔹Fixes to many major issues and newly discovered bugs
|
|
26
|
+
|
|
27
|
+
🔹Full support for dynamic objects, arrays, and values
|
|
28
|
+
|
|
29
|
+
🔹Full support for `JSON.Raw` type everywhere
|
|
30
|
+
|
|
17
31
|
## 📚 Contents
|
|
18
32
|
|
|
19
33
|
- [Installation](#-installation)
|
|
@@ -31,22 +45,21 @@ JSON is the de-facto serialization format of modern web applications, but its se
|
|
|
31
45
|
## 💾 Installation
|
|
32
46
|
|
|
33
47
|
```bash
|
|
34
|
-
npm install json-as
|
|
48
|
+
npm install json-as
|
|
35
49
|
```
|
|
36
50
|
|
|
37
51
|
Add the `--transform` to your `asc` command (e.g. in package.json)
|
|
38
52
|
|
|
39
53
|
```bash
|
|
40
|
-
--transform json-as/transform
|
|
54
|
+
--transform json-as/transform
|
|
41
55
|
```
|
|
42
56
|
|
|
43
57
|
Alternatively, add it to your `asconfig.json`
|
|
44
58
|
|
|
45
|
-
```
|
|
59
|
+
```typescript
|
|
46
60
|
{
|
|
47
61
|
"options": {
|
|
48
|
-
"transform": ["json-as/transform"]
|
|
49
|
-
"lib": ["json-as/lib"]
|
|
62
|
+
"transform": ["json-as/transform"]
|
|
50
63
|
}
|
|
51
64
|
}
|
|
52
65
|
```
|
|
@@ -55,7 +68,7 @@ If you'd like to see the code that the transform generates, run with `JSON_DEBUG
|
|
|
55
68
|
|
|
56
69
|
## 🪄 Usage
|
|
57
70
|
|
|
58
|
-
```
|
|
71
|
+
```typescript
|
|
59
72
|
import { JSON } from "json-as";
|
|
60
73
|
|
|
61
74
|
@json
|
|
@@ -82,15 +95,15 @@ class Player {
|
|
|
82
95
|
const player: Player = {
|
|
83
96
|
firstName: "Jairus",
|
|
84
97
|
lastName: "Tanaka",
|
|
85
|
-
lastActive: [
|
|
98
|
+
lastActive: [3, 9, 2025],
|
|
86
99
|
age: 18,
|
|
87
100
|
pos: {
|
|
88
101
|
x: 3.4,
|
|
89
102
|
y: 1.2,
|
|
90
|
-
z: 8.3
|
|
103
|
+
z: 8.3,
|
|
91
104
|
},
|
|
92
|
-
isVerified: true
|
|
93
|
-
}
|
|
105
|
+
isVerified: true,
|
|
106
|
+
}
|
|
94
107
|
|
|
95
108
|
const serialized = JSON.stringify<Player>(player);
|
|
96
109
|
const deserialized = JSON.parse<Player>(serialized);
|
|
@@ -109,26 +122,26 @@ This library allows selective omission of fields during serialization using the
|
|
|
109
122
|
|
|
110
123
|
This decorator excludes a field from serialization entirely.
|
|
111
124
|
|
|
112
|
-
```
|
|
125
|
+
```typescript
|
|
113
126
|
@json
|
|
114
127
|
class Example {
|
|
115
128
|
name!: string;
|
|
116
129
|
@omit
|
|
117
|
-
|
|
130
|
+
SSN!: string;
|
|
118
131
|
}
|
|
119
132
|
|
|
120
133
|
const obj = new Example();
|
|
121
|
-
obj.name = "
|
|
122
|
-
obj.
|
|
134
|
+
obj.name = "Jairus";
|
|
135
|
+
obj.SSN = "123-45-6789";
|
|
123
136
|
|
|
124
|
-
console.log(JSON.stringify(obj)); // { "name": "
|
|
137
|
+
console.log(JSON.stringify(obj)); // { "name": "Jairus" }
|
|
125
138
|
```
|
|
126
139
|
|
|
127
140
|
**@omitnull**
|
|
128
141
|
|
|
129
142
|
This decorator omits a field only if its value is null.
|
|
130
143
|
|
|
131
|
-
```
|
|
144
|
+
```typescript
|
|
132
145
|
@json
|
|
133
146
|
class Example {
|
|
134
147
|
name!: string;
|
|
@@ -137,30 +150,36 @@ class Example {
|
|
|
137
150
|
}
|
|
138
151
|
|
|
139
152
|
const obj = new Example();
|
|
140
|
-
obj.name = "
|
|
153
|
+
obj.name = "Jairus";
|
|
141
154
|
obj.optionalField = null;
|
|
142
155
|
|
|
143
|
-
console.log(JSON.stringify(obj)); // { "name": "
|
|
156
|
+
console.log(JSON.stringify(obj)); // { "name": "Jairus" }
|
|
157
|
+
```
|
|
144
158
|
|
|
145
|
-
|
|
159
|
+
**@omitif((self: this) => condition)**
|
|
146
160
|
|
|
147
161
|
This decorator omits a field based on a custom predicate function.
|
|
148
162
|
|
|
163
|
+
```typescript
|
|
149
164
|
@json
|
|
150
165
|
class Example {
|
|
151
166
|
name!: string;
|
|
152
|
-
@omitif((self: Example) => self.age
|
|
167
|
+
@omitif((self: Example) => self.age <= 18)
|
|
153
168
|
age!: number;
|
|
154
169
|
}
|
|
155
170
|
|
|
156
171
|
const obj = new Example();
|
|
157
|
-
obj.name = "
|
|
158
|
-
obj.age =
|
|
172
|
+
obj.name = "Jairus";
|
|
173
|
+
obj.age = 18;
|
|
174
|
+
|
|
175
|
+
console.log(JSON.stringify(obj)); // { "name": "Jairus" }
|
|
176
|
+
|
|
177
|
+
obj.age = 99;
|
|
159
178
|
|
|
160
|
-
console.log(JSON.stringify(obj)); // { "name": "
|
|
179
|
+
console.log(JSON.stringify(obj)); // { "name": "Jairus", "age": 99 }
|
|
161
180
|
```
|
|
162
181
|
|
|
163
|
-
If age were
|
|
182
|
+
If age were higher than 18, it would be included in the serialization.
|
|
164
183
|
|
|
165
184
|
### 🗳️ Using nullable primitives
|
|
166
185
|
|
|
@@ -168,7 +187,7 @@ AssemblyScript doesn't support using nullable primitive types, so instead, json-
|
|
|
168
187
|
|
|
169
188
|
For example, this schema won't compile in AssemblyScript:
|
|
170
189
|
|
|
171
|
-
```
|
|
190
|
+
```typescript
|
|
172
191
|
@json
|
|
173
192
|
class Person {
|
|
174
193
|
name!: string;
|
|
@@ -178,7 +197,7 @@ class Person {
|
|
|
178
197
|
|
|
179
198
|
Instead, use `JSON.Box` to allow nullable primitives:
|
|
180
199
|
|
|
181
|
-
```
|
|
200
|
+
```typescript
|
|
182
201
|
@json
|
|
183
202
|
class Person {
|
|
184
203
|
name: string;
|
|
@@ -188,11 +207,11 @@ class Person {
|
|
|
188
207
|
}
|
|
189
208
|
}
|
|
190
209
|
|
|
191
|
-
const person = new Person("
|
|
192
|
-
console.log(JSON.stringify(person)); // {"name":"
|
|
210
|
+
const person = new Person("Jairus");
|
|
211
|
+
console.log(JSON.stringify(person)); // {"name":"Jairus","age":null}
|
|
193
212
|
|
|
194
213
|
person.age = new JSON.Box<i32>(18); // Set age to 18
|
|
195
|
-
console.log(JSON.stringify(person)); // {"name":"
|
|
214
|
+
console.log(JSON.stringify(person)); // {"name":"Jairus","age":18}
|
|
196
215
|
```
|
|
197
216
|
|
|
198
217
|
### 📤 Working with unknown or dynamic data
|
|
@@ -205,31 +224,31 @@ Here's a few examples:
|
|
|
205
224
|
|
|
206
225
|
**Working with multi-type arrays**
|
|
207
226
|
|
|
208
|
-
When dealing with arrays that have multiple types within them, eg. `["string",true,
|
|
227
|
+
When dealing with arrays that have multiple types within them, eg. `["string",true,["array"]]`, use `JSON.Value[]`
|
|
209
228
|
|
|
210
|
-
```
|
|
211
|
-
const
|
|
229
|
+
```typescript
|
|
230
|
+
const a = JSON.parse<JSON.Value[]>('["string",true,["array"]]');
|
|
212
231
|
console.log(JSON.stringify(a[0])); // "string"
|
|
213
232
|
console.log(JSON.stringify(a[1])); // true
|
|
214
|
-
console.log(JSON.stringify(a[2])); //
|
|
215
|
-
console.log(JSON.stringify(a[3])); // ["array"]
|
|
233
|
+
console.log(JSON.stringify(a[2])); // ["array"]
|
|
216
234
|
```
|
|
217
235
|
|
|
218
236
|
**Working with unknown objects**
|
|
219
237
|
|
|
220
238
|
When dealing with an object with an unknown structure, use the `JSON.Obj` type
|
|
221
239
|
|
|
222
|
-
```
|
|
223
|
-
const
|
|
240
|
+
```typescript
|
|
241
|
+
const obj = JSON.parse<JSON.Obj>('{"a":3.14,"b":true,"c":[1,2,3],"d":{"x":1,"y":2,"z":3}}');
|
|
224
242
|
|
|
225
|
-
console.log(
|
|
226
|
-
console.log(
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
243
|
+
console.log("Keys: " + obj.keys().join(" ")); // a b c d
|
|
244
|
+
console.log("Values: " +
|
|
245
|
+
obj
|
|
246
|
+
.values()
|
|
247
|
+
.map<string>((v) => JSON.stringify(v))
|
|
248
|
+
.join(" "),
|
|
230
249
|
); // 3.14 true [1,2,3] {"x":1,"y":2,"z":3}
|
|
231
250
|
|
|
232
|
-
const y =
|
|
251
|
+
const y = obj.get("d")!.get<JSON.Obj>().get("y")!;
|
|
233
252
|
console.log('o1["d"]["y"] = ' + y.toString()); // o1["d"]["y"] = 2
|
|
234
253
|
```
|
|
235
254
|
|
|
@@ -239,7 +258,7 @@ More often, objects will be completely statically typed except for one or two va
|
|
|
239
258
|
|
|
240
259
|
In such cases, `JSON.Value` can be used to handle fields that may hold different types at runtime.
|
|
241
260
|
|
|
242
|
-
```
|
|
261
|
+
```typescript
|
|
243
262
|
@json
|
|
244
263
|
class DynamicObj {
|
|
245
264
|
id: i32 = 0;
|
|
@@ -267,24 +286,22 @@ Sometimes its necessary to simply copy a string instead of serializing it.
|
|
|
267
286
|
|
|
268
287
|
For example, the following data would typically be serialized as:
|
|
269
288
|
|
|
270
|
-
```
|
|
271
|
-
const
|
|
272
|
-
|
|
289
|
+
```typescript
|
|
290
|
+
const map = new Map<string, string>();
|
|
291
|
+
map.set("pos", '{"x":1.0,"y":2.0,"z":3.0}');
|
|
273
292
|
|
|
274
|
-
|
|
275
|
-
console.log("a1: " + a1);
|
|
293
|
+
console.log(JSON.stringify(map));
|
|
276
294
|
// {"pos":"{\"x\":1.0,\"y\":2.0,\"z\":3.0}"}
|
|
277
295
|
// pos's value (Vec3) is contained within a string... ideally, it should be left alone
|
|
278
296
|
```
|
|
279
297
|
|
|
280
298
|
If, instead, one wanted to insert Raw JSON into an existing schema/data structure, they could make use of the JSON.Raw type to do so:
|
|
281
299
|
|
|
282
|
-
```
|
|
283
|
-
const
|
|
284
|
-
|
|
300
|
+
```typescript
|
|
301
|
+
const map = new Map<string, JSON.Raw>();
|
|
302
|
+
map.set("pos", new JSON.Raw('{"x":1.0,"y":2.0,"z":3.0}'));
|
|
285
303
|
|
|
286
|
-
|
|
287
|
-
console.log("a1: " + a1);
|
|
304
|
+
console.log(JSON.stringify(map));
|
|
288
305
|
// {"pos":{"x":1.0,"y":2.0,"z":3.0}}
|
|
289
306
|
// Now its properly formatted JSON where pos's value is of type Vec3 not string!
|
|
290
307
|
```
|
|
@@ -295,7 +312,9 @@ This library supports custom serialization and deserialization methods, which ca
|
|
|
295
312
|
|
|
296
313
|
Here's an example of creating a custom data type called `Point` which serializes to `(x,y)`
|
|
297
314
|
|
|
298
|
-
```
|
|
315
|
+
```typescript
|
|
316
|
+
import { bytes } from "json-as/assembly/util";
|
|
317
|
+
|
|
299
318
|
@json
|
|
300
319
|
class Point {
|
|
301
320
|
x: f64 = 0.0;
|
|
@@ -319,12 +338,17 @@ class Point {
|
|
|
319
338
|
const x = data.slice(1, c);
|
|
320
339
|
const y = data.slice(c + 1, data.length - 1);
|
|
321
340
|
|
|
322
|
-
return new Point(
|
|
323
|
-
f64.parse(x),
|
|
324
|
-
f64.parse(y)
|
|
325
|
-
);
|
|
341
|
+
return new Point(f64.parse(x), f64.parse(y));
|
|
326
342
|
}
|
|
327
343
|
}
|
|
344
|
+
|
|
345
|
+
const obj = new Point(3.5, -9.2);
|
|
346
|
+
|
|
347
|
+
const serialized = JSON.stringify<Point>(obj);
|
|
348
|
+
const deserialized = JSON.parse<Point>(serialized);
|
|
349
|
+
|
|
350
|
+
console.log("Serialized " + serialized);
|
|
351
|
+
console.log("Deserialized " + JSON.stringify(deserialized));
|
|
328
352
|
```
|
|
329
353
|
|
|
330
354
|
The serializer function converts a `Point` instance into a string format `(x,y)`.
|
|
@@ -333,7 +357,7 @@ The deserializer function parses the string `(x,y)` back into a `Point` instance
|
|
|
333
357
|
|
|
334
358
|
These functions are then wrapped before being consumed by the json-as library:
|
|
335
359
|
|
|
336
|
-
```
|
|
360
|
+
```typescript
|
|
337
361
|
@inline __SERIALIZE_CUSTOM(ptr: usize): void {
|
|
338
362
|
const data = this.serializer(changetype<Point>(ptr));
|
|
339
363
|
const dataSize = data.length << 1;
|
|
@@ -352,45 +376,27 @@ This allows custom serialization while maintaining a generic interface for the l
|
|
|
352
376
|
|
|
353
377
|
The `json-as` library has been optimized to achieve near-gigabyte-per-second JSON processing speeds through SIMD acceleration and highly efficient transformations. Below are some key performance benchmarks to give you an idea of how it performs.
|
|
354
378
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
Simple
|
|
358
|
-
|
|
359
|
-
| Test Case | Serialization (ops/s) | Deserialization (ops/s) | Serialization (MB/s) | Deserialization (MB/s) |
|
|
360
|
-
| ------------------ | --------------------- | ----------------------- | -------------------- | ---------------------- |
|
|
361
|
-
| Vector3 Object | 32,642,320 ops/s | 9,736,272 ops/s | 1,240 MB/s | 369 MB/s |
|
|
362
|
-
| Alphabet String | 4,928,856 ops/s | 7,567,360 ops/s | 975 MB/s | 1,498 MB/s |
|
|
363
|
-
| Small JSON Object | [Fill Value] | [Fill Value] | [Fill Value] | [Fill Value] |
|
|
364
|
-
| Medium JSON Object | [Fill Value] | [Fill Value] | [Fill Value] | [Fill Value] |
|
|
365
|
-
| Large JSON Object | [Fill Value] | [Fill Value] | [Fill Value] | [Fill Value] |
|
|
366
|
-
|
|
367
|
-
SIMD
|
|
368
|
-
|
|
369
|
-
| Test Case | Serialization (ops/s) | Deserialization (ops/s) | Serialization (MB/s) | Deserialization (MB/s) |
|
|
370
|
-
| ------------------ | --------------------- | ----------------------- | -------------------- | ---------------------- |
|
|
371
|
-
| Vector3 Object | 32,642,320 ops/s | 9,736,272 ops/s | 1,240 MB/s | 369 MB/s |
|
|
372
|
-
| Alphabet String | 20,368,584 ops/s | 28,467,424 ops/s | 3,910 MB/s | 5,636 MB/s |
|
|
373
|
-
| Small JSON Object | [Fill Value] | [Fill Value] | [Fill Value] | [Fill Value] |
|
|
374
|
-
| Medium JSON Object | [Fill Value] | [Fill Value] | [Fill Value] | [Fill Value] |
|
|
375
|
-
| Large JSON Object | [Fill Value] | [Fill Value] | [Fill Value] | [Fill Value] |
|
|
379
|
+
Note: the AssemblyScript benches are run using a _bump allocator_ so that Garbage Collection does not interfere with results. Also note that ideally, I would use [d8](https://v8.dev/docs/d8), but until that is done, these results serve as a temporary performance comparison.
|
|
376
380
|
|
|
377
|
-
|
|
381
|
+
**Table 1** - _AssemblyScript_
|
|
378
382
|
|
|
379
|
-
| Test Case
|
|
380
|
-
|
|
|
381
|
-
| Vector3 Object
|
|
382
|
-
| Alphabet String
|
|
383
|
-
| Small
|
|
384
|
-
| Medium
|
|
385
|
-
| Large
|
|
383
|
+
| Test Case | Size | Serialization (ops/s) | Deserialization (ops/s) | Serialization (MB/s) | Deserialization (MB/s) |
|
|
384
|
+
| --------------- | ---------- | --------------------- | ----------------------- | -------------------- | ---------------------- |
|
|
385
|
+
| Vector3 Object | 38 bytes | 35,714,285 ops/s | 35,435,552 ops/s | 1,357 MB/s | 1,348 MB/s |
|
|
386
|
+
| Alphabet String | 104 bytes | 13,617,021 ops/s | 18,390,804 ops/s | 1,416 MB/s | 1,986 MB/s |
|
|
387
|
+
| Small Object | 88 bytes | 24,242,424 ops/s | 12,307,692 ops/s | 2,133 MB/s | 1,083 MB/s |
|
|
388
|
+
| Medium Object | 494 bytes | 4,060,913 ops/s | 1,396,160 ops/s | 2,006 MB/s | 689.7 MB/s |
|
|
389
|
+
| Large Object | 3374 bytes | 614,754 ops/s | 132,802 ops/s | 2,074 MB/s | 448.0 MB/s |
|
|
386
390
|
|
|
387
|
-
|
|
391
|
+
**Table 2** - _JavaScript_
|
|
388
392
|
|
|
389
|
-
|
|
|
390
|
-
|
|
|
391
|
-
|
|
|
392
|
-
|
|
|
393
|
-
|
|
|
393
|
+
| Test Case | Size | Serialization (ops/s) | Deserialization (ops/s) | Serialization (MB/s) | Deserialization (MB/s) |
|
|
394
|
+
| --------------- | ---------- | --------------------- | ----------------------- | -------------------- | ---------------------- |
|
|
395
|
+
| Vector3 Object | 38 bytes | 8,791,209 ops/s | 5,369,12 ops/s | 357.4 MB/s | 204.3 MB/s |
|
|
396
|
+
| Alphabet String | 104 bytes | 13,793,103 ops/s | 14,746,544 ops/s | 1,416 MB/s | 1,592 MB/s |
|
|
397
|
+
| Small Object | 88 bytes | 8,376,963 ops/s | 4,968,944 ops/s | 737.1 MB/s | 437.2 MB/s |
|
|
398
|
+
| Medium Object | 494 bytes | 2,395,210 ops/s | 1,381,693 ops/s | 1,183 MB/s | 682.5 MB/s |
|
|
399
|
+
| Large Object | 3374 bytes | 222,222 ops/s | 117,233 ops/s | 749.7 MB/s | 395.5 MB/s |
|
|
394
400
|
|
|
395
401
|
## 📃 License
|
|
396
402
|
|
|
@@ -403,4 +409,4 @@ Please send all issues to [GitHub Issues](https://github.com/JairusSW/json-as/is
|
|
|
403
409
|
- **Email:** Send me inquiries, questions, or requests at [me@jairus.dev](mailto:me@jairus.dev)
|
|
404
410
|
- **GitHub:** Visit the official GitHub repository [Here](https://github.com/JairusSW/json-as)
|
|
405
411
|
- **Website:** Visit my official website at [jairus.dev](https://jairus.dev/)
|
|
406
|
-
- **Discord:** Contact me at [My Discord](https://discord.com/users/600700584038760448) or on the [AssemblyScript Discord Server](https://discord.gg/assemblyscript/)
|
|
412
|
+
- **Discord:** Contact me at [My Discord](https://discord.com/users/600700584038760448) or on the [AssemblyScript Discord Server](https://discord.gg/assemblyscript/)
|
|
@@ -58,6 +58,48 @@ describe("Should serialize object arrays", () => {
|
|
|
58
58
|
).toBe('[{"x":3.4,"y":1.2,"z":8.3},{"x":3.4,"y":-2.1,"z":9.3}]');
|
|
59
59
|
});
|
|
60
60
|
|
|
61
|
+
describe("Should deserialize integer arrays", () => {
|
|
62
|
+
expect(JSON.stringify(JSON.parse<u32[]>("[0,100,101]"))).toBe('[0,100,101]');
|
|
63
|
+
expect(JSON.stringify(JSON.parse<u64[]>("[0,100,101]"))).toBe('[0,100,101]');
|
|
64
|
+
expect(JSON.stringify(JSON.parse<i32[]>("[0,100,101,-100,-101]"))).toBe("[0,100,101,-100,-101]");
|
|
65
|
+
expect(JSON.stringify(JSON.parse<i64[]>("[0,100,101,-100,-101]"))).toBe("[0,100,101,-100,-101]");
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe("Should deserialize float arrays", () => {
|
|
69
|
+
expect(JSON.stringify(JSON.parse<f64[]>("[7.23,1000.0,1000.0,1.23456,1.23456,0.0,7.23]"))).toBe("[7.23,1000.0,1000.0,1.23456,1.23456,0.0,7.23]");
|
|
70
|
+
expect(JSON.stringify(JSON.parse<f64[]>("[1e+21,1e+22,1e-7,1e-8,1e-9]"))).toBe("[1e+21,1e+22,1e-7,1e-8,1e-9]");
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe("Should deserialize boolean arrays", () => {
|
|
74
|
+
expect(JSON.stringify(JSON.parse<bool[]>("[true,false]"))).toBe("[true,false]");
|
|
75
|
+
expect(JSON.stringify(JSON.parse<boolean[]>("[true,false]"))).toBe("[true,false]");
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
describe("Should deserialize string arrays", () => {
|
|
79
|
+
expect(JSON.stringify(JSON.parse<string[]>("[\"string \\\"with random spa\\nces and \\nnewlines\\n\\n\\n\"]"))).toBe("[\"string \\\"with random spa\\nces and \\nnewlines\\n\\n\\n\"]");
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe("Should deserialize nested integer arrays", () => {
|
|
83
|
+
expect(JSON.stringify(JSON.parse<i64[][]>("[[100,101],[-100,-101],[0]]"))).toBe("[[100,101],[-100,-101],[0]]");
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
describe("Should deserialize nested float arrays", () => {
|
|
87
|
+
expect(JSON.stringify(JSON.parse<f64[][]>("[[7.23],[1000.0],[1000.0],[1.23456],[1.23456],[0.0],[7.23]]"))).toBe("[[7.23],[1000.0],[1000.0],[1.23456],[1.23456],[0.0],[7.23]]");
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe("Should deserialize nested boolean arrays", () => {
|
|
91
|
+
expect(JSON.stringify(JSON.parse<bool[][]>("[[true],[false]]"))).toBe("[[true],[false]]");
|
|
92
|
+
expect(JSON.stringify(JSON.parse<boolean[][]>("[[true],[false]]"))).toBe("[[true],[false]]");
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe("Should deserialize object arrays", () => {
|
|
96
|
+
expect(
|
|
97
|
+
JSON.stringify(JSON.parse<Vec3[]>(
|
|
98
|
+
'[{"x":3.4,"y":1.2,"z":8.3},{"x":3.4,"y":-2.1,"z":9.3}]'
|
|
99
|
+
)
|
|
100
|
+
)).toBe('[{"x":3.4,"y":1.2,"z":8.3},{"x":3.4,"y":-2.1,"z":9.3}]');
|
|
101
|
+
});
|
|
102
|
+
|
|
61
103
|
@json
|
|
62
104
|
class Vec3 {
|
|
63
105
|
x: f64 = 0.0;
|
|
@@ -34,9 +34,9 @@ describe("Should deserialize floats", () => {
|
|
|
34
34
|
|
|
35
35
|
expect(JSON.parse<f64>("0.000001").toString()).toBe("0.000001");
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
expect(JSON.parse<f64>("1e-7").toString()).toBe(1e-7.toString());
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
expect(JSON.parse<f64>("100000000000000000000.0").toString()).toBe(1e20.toString());
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
expect(JSON.parse<f64>("1e+21").toString()).toBe(1e21.toString());
|
|
42
42
|
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { JSON } from "..";
|
|
2
|
+
import { describe, expect } from "./lib";
|
|
3
|
+
|
|
4
|
+
describe("Should deserialize complex objects", () => {
|
|
5
|
+
const input = '{"a":{"b":{"c":[{"d":"random value 1"},{"e":["value 2","value 3"]}],"f":{"g":{"h":[1,2,3],"i":{"j":"nested value"}}}},"k":"simple value"},"l":[{"m":"another value","n":{"o":"deep nested","p":[{"q":"even deeper"},"final value"]}}],"r":null}';
|
|
6
|
+
expect(JSON.stringify(JSON.parse<Map<string, JSON.Raw>>(input))).toBe(input);
|
|
7
|
+
})
|
|
@@ -17,8 +17,7 @@ describe("Should serialize Map<string, JSON.Raw>", () => {
|
|
|
17
17
|
expect(JSON.stringify(m1)).toBe('{"hello":"world","pos":{"x":1.0,"y":2.0,"z":3.0}}');
|
|
18
18
|
});
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
// });
|
|
20
|
+
describe("Should deserialize Map<string, JSON.Raw>", () => {
|
|
21
|
+
const m1 = JSON.parse<Map<string, JSON.Raw>>('{"hello":"world","pos":{"x":1.0,"y":2.0,"z":3.0}}');
|
|
22
|
+
expect(JSON.stringify(m1)).toBe('{"hello":"world","pos":{"x":1.0,"y":2.0,"z":3.0}}');
|
|
23
|
+
});
|
|
@@ -64,9 +64,9 @@ describe("Should deserialize structs with whitespace", () => {
|
|
|
64
64
|
).toBe('{"x":3.4,"y":1.2,"z":8.3}');
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
-
describe("Should serialize Suite struct", () => {
|
|
67
|
+
// describe("Should serialize Suite struct", () => {
|
|
68
68
|
|
|
69
|
-
});
|
|
69
|
+
// });
|
|
70
70
|
|
|
71
71
|
@json
|
|
72
72
|
class BaseObject {
|
|
@@ -4,14 +4,18 @@ import { deserializeBoolean } from "./bool";
|
|
|
4
4
|
import { deserializeFloat } from "./float";
|
|
5
5
|
import { deserializeString } from "./string";
|
|
6
6
|
import { deserializeObject } from "./object";
|
|
7
|
+
import { BRACE_LEFT, BRACKET_LEFT, CHAR_N, QUOTE } from "../../custom/chars";
|
|
7
8
|
|
|
8
9
|
export function deserializeArbitrary(srcStart: usize, srcEnd: usize, dst: usize): JSON.Value {
|
|
9
10
|
const firstChar = load<u16>(srcStart);
|
|
10
|
-
if (firstChar ==
|
|
11
|
-
else if (firstChar ==
|
|
11
|
+
if (firstChar == QUOTE) return JSON.Value.from(deserializeString(srcStart, srcEnd, 0));
|
|
12
|
+
else if (firstChar == BRACE_LEFT) return JSON.Value.from(deserializeObject(srcStart, srcEnd, 0));
|
|
12
13
|
else if (firstChar - 48 <= 9 || firstChar == 45) return JSON.Value.from(deserializeFloat<f64>(srcStart, srcEnd));
|
|
13
|
-
else if (firstChar ==
|
|
14
|
-
return JSON.Value.from(deserializeArray<JSON.Value[]>(srcStart, srcEnd,
|
|
14
|
+
else if (firstChar == BRACKET_LEFT) {
|
|
15
|
+
return JSON.Value.from(deserializeArray<JSON.Value[]>(srcStart, srcEnd, 0));
|
|
15
16
|
} else if (firstChar == 116 || firstChar == 102) return JSON.Value.from(deserializeBoolean(srcStart, srcEnd));
|
|
17
|
+
else if (firstChar == CHAR_N) {
|
|
18
|
+
return JSON.Value.from(null);
|
|
19
|
+
}
|
|
16
20
|
return unreachable();
|
|
17
21
|
}
|
|
@@ -4,7 +4,7 @@ import { isSpace } from "util/string";
|
|
|
4
4
|
import { ptrToStr } from "../../../util/ptrToStr";
|
|
5
5
|
|
|
6
6
|
export function deserializeArbitraryArray(srcStart: usize, srcEnd: usize, dst: usize): JSON.Value[] {
|
|
7
|
-
const out =
|
|
7
|
+
const out = changetype<JSON.Value[]>(dst || changetype<usize>(instantiate<JSON.Value[]>()));
|
|
8
8
|
let lastIndex: usize = 0;
|
|
9
9
|
let depth: u32 = 0;
|
|
10
10
|
// if (load<u16>(srcStart) != BRACKET_LEFT)
|
|
@@ -121,12 +121,12 @@ export function deserializeArbitraryArray(srcStart: usize, srcEnd: usize, dst: u
|
|
|
121
121
|
}
|
|
122
122
|
} else if (code == CHAR_N) {
|
|
123
123
|
if (load<u64>(srcStart) == 30399761348886638) {
|
|
124
|
+
console.log("Value (null): " + ptrToStr(srcStart, srcStart + 8));
|
|
124
125
|
// @ts-ignore: type
|
|
125
|
-
out.push(JSON.__deserialize<JSON.Value>(
|
|
126
|
-
//
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
126
|
+
out.push(JSON.__deserialize<JSON.Value>(srcStart, (srcStart += 8)));
|
|
127
|
+
// while (isSpace(load<u16>((srcStart += 2)))) {
|
|
128
|
+
// /* empty */
|
|
129
|
+
// }
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
srcStart += 2;
|
|
@@ -2,15 +2,16 @@ import { BRACKET_LEFT, BRACKET_RIGHT } from "../../../custom/chars";
|
|
|
2
2
|
import { JSON } from "../../../";
|
|
3
3
|
|
|
4
4
|
export function deserializeArrayArray<T extends unknown[][]>(srcStart: usize, srcEnd: usize, dst: usize): T {
|
|
5
|
-
const out = dst
|
|
5
|
+
const out = changetype<nonnull<T>>(dst || changetype<usize>(instantiate<T>()));
|
|
6
6
|
let lastIndex: usize = 0;
|
|
7
7
|
let depth: u32 = 0;
|
|
8
|
-
|
|
8
|
+
srcStart += 2;
|
|
9
|
+
while (srcStart < srcEnd - 2) {
|
|
9
10
|
const code = load<u16>(srcStart);
|
|
10
11
|
if (code == BRACKET_LEFT && depth++ == 0) {
|
|
11
12
|
lastIndex = srcStart;
|
|
12
13
|
} else if (code == BRACKET_RIGHT && --depth == 0) {
|
|
13
|
-
out.push(JSON.__deserialize<valueof<T>>(lastIndex, srcStart));
|
|
14
|
+
out.push(JSON.__deserialize<valueof<T>>(lastIndex, srcStart + 2));
|
|
14
15
|
}
|
|
15
16
|
srcStart += 2;
|
|
16
17
|
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { CHAR_E, CHAR_F, CHAR_T } from "../../../custom/chars";
|
|
2
|
-
|
|
3
1
|
export function deserializeBooleanArray<T extends boolean[]>(srcStart: usize, srcEnd: usize, dst: usize): T {
|
|
4
|
-
const out = dst
|
|
2
|
+
const out = changetype<nonnull<T>>(dst || changetype<usize>(instantiate<T>()));
|
|
3
|
+
srcStart += 2; // skip [
|
|
5
4
|
while (srcStart < srcEnd) {
|
|
6
|
-
const
|
|
7
|
-
if (
|
|
5
|
+
const block = load<u64>(srcStart);
|
|
6
|
+
if (block == 28429475166421108) {
|
|
8
7
|
out.push(true);
|
|
9
8
|
srcStart += 10;
|
|
10
|
-
} else if (
|
|
9
|
+
} else if (block == 32370086184550502 && load<u16>(srcStart, 8) == 101) {
|
|
11
10
|
out.push(false);
|
|
12
11
|
srcStart += 12;
|
|
12
|
+
} else {
|
|
13
|
+
srcStart += 2;
|
|
13
14
|
}
|
|
14
|
-
srcStart += 2;
|
|
15
15
|
}
|
|
16
16
|
return out;
|
|
17
17
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { isSpace } from "../../../util";
|
|
2
|
-
import { COMMA,
|
|
2
|
+
import { COMMA, BRACKET_RIGHT } from "../../../custom/chars";
|
|
3
3
|
import { JSON } from "../../..";
|
|
4
4
|
|
|
5
5
|
export function deserializeFloatArray<T extends number[]>(srcStart: usize, srcEnd: usize, dst: usize): T {
|
|
6
|
-
const out = dst
|
|
6
|
+
const out = changetype<nonnull<T>>(dst || changetype<usize>(instantiate<T>()));
|
|
7
7
|
let lastIndex: usize = 0;
|
|
8
8
|
while (srcStart < srcEnd) {
|
|
9
9
|
const code = load<u16>(srcStart);
|