json-as 1.0.0-beta.1 → 1.0.0-beta.10
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/.trunk/configs/.markdownlint.yaml +2 -0
- package/.trunk/configs/.shellcheckrc +7 -0
- package/.trunk/configs/.yamllint.yaml +7 -0
- package/.trunk/trunk.yaml +37 -0
- package/CHANGELOG +60 -0
- package/README.md +275 -25
- package/assembly/__benches__/misc.bench.ts +0 -1
- package/assembly/__benches__/string.bench.ts +23 -0
- package/assembly/__benches__/struct.bench.ts +21 -0
- package/assembly/__tests__/arbitrary.spec.ts +1 -1
- package/assembly/__tests__/array.spec.ts +42 -1
- package/assembly/__tests__/bool.spec.ts +1 -1
- package/assembly/__tests__/box.spec.ts +1 -1
- package/assembly/__tests__/custom.spec.ts +42 -0
- package/assembly/__tests__/date.spec.ts +1 -1
- package/assembly/__tests__/float.spec.ts +4 -4
- package/assembly/__tests__/integer.spec.ts +1 -1
- package/assembly/__tests__/null.spec.ts +1 -1
- package/assembly/__tests__/raw.spec.ts +23 -0
- package/assembly/__tests__/string.spec.ts +1 -1
- package/assembly/__tests__/{obj.spec.ts → struct.spec.ts} +18 -4
- package/assembly/__tests__/test.spec.ts +1 -1
- package/assembly/as-bs.d.ts +53 -0
- package/assembly/custom/bench.ts +26 -0
- package/assembly/deserialize/simple/array/arbitrary.ts +1 -2
- 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 +1 -1
- 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 +92 -67
- package/assembly/deserialize/simple/object.ts +3 -2
- package/assembly/deserialize/simple/raw.ts +6 -0
- package/assembly/deserialize/simple/struct.ts +29 -16
- package/assembly/index.d.ts +15 -1
- package/assembly/index.ts +94 -13
- package/assembly/serialize/simd/string.ts +0 -1
- package/assembly/serialize/simple/array.ts +0 -1
- package/assembly/serialize/simple/bool.ts +0 -2
- package/assembly/serialize/simple/date.ts +0 -1
- package/assembly/serialize/simple/float.ts +0 -1
- package/assembly/serialize/simple/integer.ts +0 -1
- package/assembly/serialize/simple/map.ts +0 -1
- package/assembly/serialize/simple/object.ts +0 -1
- package/assembly/serialize/simple/raw.ts +14 -0
- package/assembly/serialize/simple/string.ts +0 -1
- package/assembly/test.ts +69 -28
- package/bench/bench.ts +15 -0
- package/bench/schemas.ts +5 -0
- package/bench/string.bench.ts +16 -0
- package/index.ts +1 -1
- package/lib/tsconfig.json +8 -0
- package/package.json +9 -6
- package/run-tests.sh +1 -1
- package/transform/lib/index.js +120 -46
- package/transform/lib/index.js.map +1 -1
- package/transform/src/index.ts +137 -54
- package/.gitmodules +0 -0
- package/as-test.config.json +0 -18
- package/modules/as-bs/LICENSE +0 -21
- package/modules/as-bs/README.md +0 -95
- package/modules/as-bs/assembly/state.ts +0 -8
- package/modules/as-bs/assembly/tsconfig.json +0 -97
- package/modules/as-bs/index.ts +0 -1
- package/modules/as-bs/package.json +0 -32
- /package/{modules/test/assembly → assembly/__tests__/lib}/index.ts +0 -0
- /package/{modules/as-bs/assembly/index.ts → lib/as-bs.ts} +0 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# This file controls the behavior of Trunk: https://docs.trunk.io/cli
|
|
2
|
+
# To learn more about the format of this file, see https://docs.trunk.io/reference/trunk-yaml
|
|
3
|
+
version: 0.1
|
|
4
|
+
cli:
|
|
5
|
+
version: 1.22.10
|
|
6
|
+
# Trunk provides extensibility via plugins. (https://docs.trunk.io/plugins)
|
|
7
|
+
plugins:
|
|
8
|
+
sources:
|
|
9
|
+
- id: trunk
|
|
10
|
+
ref: v1.6.7
|
|
11
|
+
uri: https://github.com/trunk-io/plugins
|
|
12
|
+
# Many linters and tools depend on runtimes - configure them here. (https://docs.trunk.io/runtimes)
|
|
13
|
+
runtimes:
|
|
14
|
+
enabled:
|
|
15
|
+
- go@1.21.0
|
|
16
|
+
- node@18.20.5
|
|
17
|
+
- python@3.10.8
|
|
18
|
+
# This is the section where you manage your linters. (https://docs.trunk.io/check/configuration)
|
|
19
|
+
lint:
|
|
20
|
+
disabled:
|
|
21
|
+
- markdownlint
|
|
22
|
+
enabled:
|
|
23
|
+
- actionlint@1.7.7
|
|
24
|
+
- checkov@3.2.377
|
|
25
|
+
- git-diff-check
|
|
26
|
+
- prettier@3.5.2
|
|
27
|
+
- shellcheck@0.10.0
|
|
28
|
+
- shfmt@3.6.0
|
|
29
|
+
- trufflehog@3.88.13
|
|
30
|
+
- yamllint@1.35.1
|
|
31
|
+
actions:
|
|
32
|
+
disabled:
|
|
33
|
+
- trunk-announce
|
|
34
|
+
- trunk-check-pre-push
|
|
35
|
+
- trunk-fmt-pre-commit
|
|
36
|
+
enabled:
|
|
37
|
+
- trunk-upgrade-available
|
package/CHANGELOG
CHANGED
|
@@ -1,5 +1,65 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 2025-03-04 - 1.0.0-beta.10
|
|
4
|
+
|
|
5
|
+
- fix: transform not generating the right load operations for keys
|
|
6
|
+
- fix: whitespace not working in objects or struct deserialization
|
|
7
|
+
- fix: JSON.Raw not working when deserializing as Map<string, JSON.Raw>
|
|
8
|
+
|
|
9
|
+
## 2025-03-03 - 1.0.0-beta.9
|
|
10
|
+
|
|
11
|
+
- rename: change libs folder to lib
|
|
12
|
+
|
|
13
|
+
## 2025-03-03 - 1.0.0-beta.8
|
|
14
|
+
|
|
15
|
+
- docs: add instructions for using `--lib` in README
|
|
16
|
+
|
|
17
|
+
## 2025-03-03 - 1.0.0-beta.7
|
|
18
|
+
|
|
19
|
+
- fix: add as-bs to `--lib` section
|
|
20
|
+
- chore: clean up transform
|
|
21
|
+
- refactor: transform should import `~lib/as-bs.ts` instead of relative path
|
|
22
|
+
|
|
23
|
+
## 2025-03-01 - 1.0.0-beta.6
|
|
24
|
+
|
|
25
|
+
- fix: import from base directory index.ts
|
|
26
|
+
|
|
27
|
+
## 2025-03-01 - 1.0.0-beta.5
|
|
28
|
+
|
|
29
|
+
- fix: revert pull request [#112](https://github.com/JairusSW/json-as/pull/112)
|
|
30
|
+
|
|
31
|
+
## 2025-02-25 - 1.0.0-beta.4
|
|
32
|
+
|
|
33
|
+
- fix: warn on presence of invalid types contained in a schema [#112](https://github.com/JairusSW/json-as/pull/112)
|
|
34
|
+
|
|
35
|
+
## 2025-02-25 - 1.0.0-beta.3
|
|
36
|
+
|
|
37
|
+
- feat: change `JSON.Raw` to actual class to facilitate proper support without transformations
|
|
38
|
+
- fix: remove old `JSON.Raw` logic from transform code
|
|
39
|
+
|
|
40
|
+
## 2025-02-25 - 1.0.0-beta.2
|
|
41
|
+
|
|
42
|
+
- feat: add support for custom serializers and deserializers [#110](https://github.com/JairusSW/json-as/pull/110)
|
|
43
|
+
|
|
44
|
+
## 2025-02-22 - 1.0.0-beta.1
|
|
45
|
+
|
|
46
|
+
- perf: add benchmarks for both AssemblyScript and JavaScript
|
|
47
|
+
- docs: publish preliminary benchmark results
|
|
48
|
+
- tests: ensure nested serialization works and add to tests
|
|
49
|
+
- feat: finish arbitrary type implementation
|
|
50
|
+
- feat: introduce `JSON.Obj` to handle objects effectively
|
|
51
|
+
- feat: reimplement arbitrary array deserialization
|
|
52
|
+
- fix: remove brace check on array deserialization
|
|
53
|
+
- feat: introduce native support for `JSON.Obj` transformations
|
|
54
|
+
- feat: implement arbitrary object serialization
|
|
55
|
+
- fix: deserialization of booleans panics on `false`
|
|
56
|
+
- fix: `bs.resize` should be type-safe
|
|
57
|
+
- impl: add `JSON.Obj` type as prototype to handle arbitrary object structures
|
|
58
|
+
- chore: rename static objects (schemas) to structs and name arbitrary objects as `obj`
|
|
59
|
+
- tests: add proper tests for arbitrary types
|
|
60
|
+
- fix: empty method generation using outdated function signature
|
|
61
|
+
- docs: update readme to be more concise
|
|
62
|
+
|
|
3
63
|
## 2025-02-13 - 1.0.0-alpha.4
|
|
4
64
|
|
|
5
65
|
- feat: reintroduce support for `Box<T>`-wrapped primitive types
|
package/README.md
CHANGED
|
@@ -1,48 +1,52 @@
|
|
|
1
1
|
<h5 align="center">
|
|
2
2
|
<pre>
|
|
3
3
|
<span style="font-size: 0.8em;"> ██ ███████ ██████ ███ ██ █████ ███████
|
|
4
|
-
██ ██ ██ ██ ████ ██ ██ ██ ██
|
|
4
|
+
██ ██ ██ ██ ████ ██ ██ ██ ██
|
|
5
5
|
██ ███████ ██ ██ ██ ██ ██ █████ ███████ ███████
|
|
6
6
|
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
7
7
|
█████ ███████ ██████ ██ ████ ██ ██ ███████
|
|
8
8
|
</span>
|
|
9
|
-
AssemblyScript - v1.0.0-beta.
|
|
9
|
+
AssemblyScript - v1.0.0-beta.10
|
|
10
10
|
</pre>
|
|
11
11
|
</h5>
|
|
12
12
|
|
|
13
|
+
## 📝 About
|
|
14
|
+
|
|
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
|
+
|
|
13
17
|
## 📚 Contents
|
|
14
18
|
|
|
15
|
-
- [About](#-about)
|
|
16
19
|
- [Installation](#-installation)
|
|
17
20
|
- [Usage](#-usage)
|
|
18
|
-
- [Examples](
|
|
21
|
+
- [Examples](#-examples)
|
|
22
|
+
- [Omitting Fields](#️-omitting-fields)
|
|
23
|
+
- [Nullable Primitives](#️-using-nullable-primitives)
|
|
24
|
+
- [Unknown or Dynamic Data](#-working-with-unknown-or-dynamic-data)
|
|
25
|
+
- [Using Raw JSON Strings](#️-using-raw-json-strings)
|
|
26
|
+
- [Custom Serializers](#️-using-custom-serializers-or-deserializers)
|
|
19
27
|
- [Performance](#-performance)
|
|
20
28
|
- [License](#-license)
|
|
21
29
|
- [Contact](#-contact)
|
|
22
30
|
|
|
23
|
-
## 📝 About
|
|
24
|
-
|
|
25
|
-
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.
|
|
26
|
-
|
|
27
31
|
## 💾 Installation
|
|
28
32
|
|
|
29
33
|
```bash
|
|
30
|
-
npm install json-as@1.0.0-beta.
|
|
34
|
+
npm install json-as@1.0.0-beta.10
|
|
31
35
|
```
|
|
32
36
|
|
|
33
37
|
Add the `--transform` to your `asc` command (e.g. in package.json)
|
|
34
38
|
|
|
35
39
|
```bash
|
|
36
|
-
--transform json-as/transform
|
|
40
|
+
--transform json-as/transform --lib json-as/lib
|
|
37
41
|
```
|
|
38
42
|
|
|
39
43
|
Alternatively, add it to your `asconfig.json`
|
|
40
44
|
|
|
41
45
|
```json
|
|
42
46
|
{
|
|
43
|
-
// ...
|
|
44
47
|
"options": {
|
|
45
|
-
"transform": ["json-as/transform"]
|
|
48
|
+
"transform": ["json-as/transform"],
|
|
49
|
+
"lib": ["json-as/lib"]
|
|
46
50
|
}
|
|
47
51
|
}
|
|
48
52
|
```
|
|
@@ -95,7 +99,254 @@ console.log("Serialized " + serialized);
|
|
|
95
99
|
console.log("Deserialized " + JSON.stringify(deserialized));
|
|
96
100
|
```
|
|
97
101
|
|
|
98
|
-
## Examples
|
|
102
|
+
## 🔍 Examples
|
|
103
|
+
|
|
104
|
+
### 🏷️ Omitting Fields
|
|
105
|
+
|
|
106
|
+
This library allows selective omission of fields during serialization using the following decorators:
|
|
107
|
+
|
|
108
|
+
**@omit**
|
|
109
|
+
|
|
110
|
+
This decorator excludes a field from serialization entirely.
|
|
111
|
+
|
|
112
|
+
```js
|
|
113
|
+
@json
|
|
114
|
+
class Example {
|
|
115
|
+
name!: string;
|
|
116
|
+
@omit
|
|
117
|
+
secret!: string;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const obj = new Example();
|
|
121
|
+
obj.name = "Visible";
|
|
122
|
+
obj.secret = "Hidden";
|
|
123
|
+
|
|
124
|
+
console.log(JSON.stringify(obj)); // { "name": "Visible" }
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**@omitnull**
|
|
128
|
+
|
|
129
|
+
This decorator omits a field only if its value is null.
|
|
130
|
+
|
|
131
|
+
```js
|
|
132
|
+
@json
|
|
133
|
+
class Example {
|
|
134
|
+
name!: string;
|
|
135
|
+
@omitnull()
|
|
136
|
+
optionalField!: string | null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const obj = new Example();
|
|
140
|
+
obj.name = "Present";
|
|
141
|
+
obj.optionalField = null;
|
|
142
|
+
|
|
143
|
+
console.log(JSON.stringify(obj)); // { "name": "Present" }
|
|
144
|
+
|
|
145
|
+
@omitif((self: this) => condition)
|
|
146
|
+
|
|
147
|
+
This decorator omits a field based on a custom predicate function.
|
|
148
|
+
|
|
149
|
+
@json
|
|
150
|
+
class Example {
|
|
151
|
+
name!: string;
|
|
152
|
+
@omitif((self: Example) => self.age < 18)
|
|
153
|
+
age!: number;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const obj = new Example();
|
|
157
|
+
obj.name = "John";
|
|
158
|
+
obj.age = 16;
|
|
159
|
+
|
|
160
|
+
console.log(JSON.stringify(obj)); // { "name": "John" }
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
If age were 18 or higher, it would be included in the serialization.
|
|
164
|
+
|
|
165
|
+
### 🗳️ Using nullable primitives
|
|
166
|
+
|
|
167
|
+
AssemblyScript doesn't support using nullable primitive types, so instead, json-as offers the `JSON.Box` class to remedy it.
|
|
168
|
+
|
|
169
|
+
For example, this schema won't compile in AssemblyScript:
|
|
170
|
+
|
|
171
|
+
```js
|
|
172
|
+
@json
|
|
173
|
+
class Person {
|
|
174
|
+
name!: string;
|
|
175
|
+
age: i32 | null = null;
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Instead, use `JSON.Box` to allow nullable primitives:
|
|
180
|
+
|
|
181
|
+
```js
|
|
182
|
+
@json
|
|
183
|
+
class Person {
|
|
184
|
+
name: string;
|
|
185
|
+
age: JSON.Box<i32> | null = null;
|
|
186
|
+
constructor(name: string) {
|
|
187
|
+
this.name = name;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const person = new Person("Bob");
|
|
192
|
+
console.log(JSON.stringify(person)); // {"name":"Bob","age":null}
|
|
193
|
+
|
|
194
|
+
person.age = new JSON.Box<i32>(18); // Set age to 18
|
|
195
|
+
console.log(JSON.stringify(person)); // {"name":"Bob","age":18}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### 📤 Working with unknown or dynamic data
|
|
199
|
+
|
|
200
|
+
Sometimes it's necessary to work with unknown data or data with dynamic types.
|
|
201
|
+
|
|
202
|
+
Because AssemblyScript is a statically-typed language, that typically isn't allowed, so json-as provides the `JSON.Value` and `JSON.Obj` types.
|
|
203
|
+
|
|
204
|
+
Here's a few examples:
|
|
205
|
+
|
|
206
|
+
**Working with multi-type arrays**
|
|
207
|
+
|
|
208
|
+
When dealing with arrays that have multiple types within them, eg. `["string",true,null,["array"]]`, use `JSON.Value[]`
|
|
209
|
+
|
|
210
|
+
```js
|
|
211
|
+
const a1 = JSON.parse<JSON.Value[]>('["string",true,null,["array"]]');
|
|
212
|
+
console.log(JSON.stringify(a[0])); // "string"
|
|
213
|
+
console.log(JSON.stringify(a[1])); // true
|
|
214
|
+
console.log(JSON.stringify(a[2])); // null
|
|
215
|
+
console.log(JSON.stringify(a[3])); // ["array"]
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
**Working with unknown objects**
|
|
219
|
+
|
|
220
|
+
When dealing with an object with an unknown structure, use the `JSON.Obj` type
|
|
221
|
+
|
|
222
|
+
```js
|
|
223
|
+
const o1 = JSON.parse<JSON.Obj>('{"a":3.14,"b":true,"c":[1,2,3],"d":{"x":1,"y":2,"z":3}}');
|
|
224
|
+
|
|
225
|
+
console.log(o1.keys().join(" ")); // a b c d
|
|
226
|
+
console.log(
|
|
227
|
+
o1.values()
|
|
228
|
+
.map<string>((v) => JSON.stringify(v))
|
|
229
|
+
.join(" ")
|
|
230
|
+
); // 3.14 true [1,2,3] {"x":1,"y":2,"z":3}
|
|
231
|
+
|
|
232
|
+
const y = o1.get("d").get<JSON.Obj>().get<i32>();
|
|
233
|
+
console.log('o1["d"]["y"] = ' + y.toString()); // o1["d"]["y"] = 2
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
**Working with dynamic types within a schema**
|
|
237
|
+
|
|
238
|
+
More often, objects will be completely statically typed except for one or two values.
|
|
239
|
+
|
|
240
|
+
In such cases, `JSON.Value` can be used to handle fields that may hold different types at runtime.
|
|
241
|
+
|
|
242
|
+
```js
|
|
243
|
+
@json
|
|
244
|
+
class DynamicObj {
|
|
245
|
+
id: i32 = 0;
|
|
246
|
+
name: string = "";
|
|
247
|
+
data!: JSON.Value; // Can hold any type of value
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const obj = new DynamicObj();
|
|
251
|
+
obj.id = 1;
|
|
252
|
+
obj.name = "Example";
|
|
253
|
+
obj.data = JSON.parse<JSON.Value>('{"key":"value"}'); // Assigning an object
|
|
254
|
+
|
|
255
|
+
console.log(JSON.stringify(obj)); // {"id":1,"name":"Example","data":{"key":"value"}}
|
|
256
|
+
|
|
257
|
+
obj.data = JSON.Value.from<i32>(42); // Changing to an integer
|
|
258
|
+
console.log(JSON.stringify(obj)); // {"id":1,"name":"Example","data":42}
|
|
259
|
+
|
|
260
|
+
obj.data = JSON.Value.from("a string"); // Changing to a string
|
|
261
|
+
console.log(JSON.stringify(obj)); // {"id":1,"name":"Example","data":"a string"}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### 🏗️ Using Raw JSON strings
|
|
265
|
+
|
|
266
|
+
Sometimes its necessary to simply copy a string instead of serializing it.
|
|
267
|
+
|
|
268
|
+
For example, the following data would typically be serialized as:
|
|
269
|
+
|
|
270
|
+
```js
|
|
271
|
+
const m1 = new Map<string, string>();
|
|
272
|
+
m1.set('pos', '{"x":1.0,"y":2.0,"z":3.0}');
|
|
273
|
+
|
|
274
|
+
const a1 = JSON.stringify(m1);
|
|
275
|
+
console.log("a1: " + a1);
|
|
276
|
+
// {"pos":"{\"x\":1.0,\"y\":2.0,\"z\":3.0}"}
|
|
277
|
+
// pos's value (Vec3) is contained within a string... ideally, it should be left alone
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
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
|
+
|
|
282
|
+
```js
|
|
283
|
+
const m1 = new Map<string, JSON.Raw>();
|
|
284
|
+
m1.set('pos', new JSON.Raw('{"x":1.0,"y":2.0,"z":3.0}'));
|
|
285
|
+
|
|
286
|
+
const a1 = JSON.stringify(m1);
|
|
287
|
+
console.log("a1: " + a1);
|
|
288
|
+
// {"pos":{"x":1.0,"y":2.0,"z":3.0}}
|
|
289
|
+
// Now its properly formatted JSON where pos's value is of type Vec3 not string!
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### ⚒️ Using custom serializers or deserializers
|
|
293
|
+
|
|
294
|
+
This library supports custom serialization and deserialization methods, which can be defined using the `@serializer` and `@deserializer` decorators.
|
|
295
|
+
|
|
296
|
+
Here's an example of creating a custom data type called `Point` which serializes to `(x,y)`
|
|
297
|
+
|
|
298
|
+
```js
|
|
299
|
+
@json
|
|
300
|
+
class Point {
|
|
301
|
+
x: f64 = 0.0;
|
|
302
|
+
y: f64 = 0.0;
|
|
303
|
+
constructor(x: f64, y: f64) {
|
|
304
|
+
this.x = x;
|
|
305
|
+
this.y = y;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
@serializer
|
|
309
|
+
serializer(self: Point): string {
|
|
310
|
+
return `(${self.x},${self.y})`;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
@deserializer
|
|
314
|
+
deserializer(data: string): Point {
|
|
315
|
+
const dataSize = bytes(data);
|
|
316
|
+
if (dataSize <= 2) throw new Error("Could not deserialize provided data as type Point");
|
|
317
|
+
|
|
318
|
+
const c = data.indexOf(",");
|
|
319
|
+
const x = data.slice(1, c);
|
|
320
|
+
const y = data.slice(c + 1, data.length - 1);
|
|
321
|
+
|
|
322
|
+
return new Point(
|
|
323
|
+
f64.parse(x),
|
|
324
|
+
f64.parse(y)
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
The serializer function converts a `Point` instance into a string format `(x,y)`.
|
|
331
|
+
|
|
332
|
+
The deserializer function parses the string `(x,y)` back into a `Point` instance.
|
|
333
|
+
|
|
334
|
+
These functions are then wrapped before being consumed by the json-as library:
|
|
335
|
+
|
|
336
|
+
```js
|
|
337
|
+
@inline __SERIALIZE_CUSTOM(ptr: usize): void {
|
|
338
|
+
const data = this.serializer(changetype<Point>(ptr));
|
|
339
|
+
const dataSize = data.length << 1;
|
|
340
|
+
memory.copy(bs.offset, changetype<usize>(data), dataSize);
|
|
341
|
+
bs.offset += dataSize;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
@inline __DESERIALIZE_CUSTOM(data: string): Point {
|
|
345
|
+
return this.deserializer(data);
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
This allows custom serialization while maintaining a generic interface for the library to access.
|
|
99
350
|
|
|
100
351
|
## ⚡ Performance
|
|
101
352
|
|
|
@@ -106,7 +357,7 @@ The `json-as` library has been optimized to achieve near-gigabyte-per-second JSO
|
|
|
106
357
|
Simple
|
|
107
358
|
|
|
108
359
|
| Test Case | Serialization (ops/s) | Deserialization (ops/s) | Serialization (MB/s) | Deserialization (MB/s) |
|
|
109
|
-
|
|
360
|
+
| ------------------ | --------------------- | ----------------------- | -------------------- | ---------------------- |
|
|
110
361
|
| Vector3 Object | 32,642,320 ops/s | 9,736,272 ops/s | 1,240 MB/s | 369 MB/s |
|
|
111
362
|
| Alphabet String | 4,928,856 ops/s | 7,567,360 ops/s | 975 MB/s | 1,498 MB/s |
|
|
112
363
|
| Small JSON Object | [Fill Value] | [Fill Value] | [Fill Value] | [Fill Value] |
|
|
@@ -116,7 +367,7 @@ Simple
|
|
|
116
367
|
SIMD
|
|
117
368
|
|
|
118
369
|
| Test Case | Serialization (ops/s) | Deserialization (ops/s) | Serialization (MB/s) | Deserialization (MB/s) |
|
|
119
|
-
|
|
370
|
+
| ------------------ | --------------------- | ----------------------- | -------------------- | ---------------------- |
|
|
120
371
|
| Vector3 Object | 32,642,320 ops/s | 9,736,272 ops/s | 1,240 MB/s | 369 MB/s |
|
|
121
372
|
| Alphabet String | 20,368,584 ops/s | 28,467,424 ops/s | 3,910 MB/s | 5,636 MB/s |
|
|
122
373
|
| Small JSON Object | [Fill Value] | [Fill Value] | [Fill Value] | [Fill Value] |
|
|
@@ -126,7 +377,7 @@ SIMD
|
|
|
126
377
|
JavaScript
|
|
127
378
|
|
|
128
379
|
| Test Case | Serialization (ops/s) | Deserialization (ops/s) | Serialization (MB/s) | Deserialization (MB/s) |
|
|
129
|
-
|
|
380
|
+
| ------------------ | --------------------- | ----------------------- | -------------------- | ---------------------- |
|
|
130
381
|
| Vector3 Object | 2,548,013 ops/s | 1,942,440 ops/s | 97 MB/s | 73 MB/s |
|
|
131
382
|
| Alphabet String | 3,221,556 ops/s | 2,716,617 ops/s | 624 MB/s | 537 MB/s |
|
|
132
383
|
| Small JSON Object | [Fill Value] | [Fill Value] | [Fill Value] | [Fill Value] |
|
|
@@ -135,12 +386,11 @@ JavaScript
|
|
|
135
386
|
|
|
136
387
|
### Real-World Usage
|
|
137
388
|
|
|
138
|
-
| Scenario
|
|
139
|
-
|
|
140
|
-
| Web API Response
|
|
141
|
-
| Database Entry
|
|
142
|
-
| File Parsing
|
|
143
|
-
|
|
389
|
+
| Scenario | JSON Size (kb) | Serialization Time (ops/s) | Deserialization Time (ops/s) | Throughput (GB/s) |
|
|
390
|
+
| ---------------- | -------------- | -------------------------- | ---------------------------- | ----------------- |
|
|
391
|
+
| Web API Response | [Fill Value] | [Fill Value] | [Fill Value] | [Fill Value] |
|
|
392
|
+
| Database Entry | [Fill Value] | [Fill Value] | [Fill Value] | [Fill Value] |
|
|
393
|
+
| File Parsing | [Fill Value] | [Fill Value] | [Fill Value] | [Fill Value] |
|
|
144
394
|
|
|
145
395
|
## 📃 License
|
|
146
396
|
|
|
@@ -148,9 +398,9 @@ This project is distributed under an open source license. You can view the full
|
|
|
148
398
|
|
|
149
399
|
## 📫 Contact
|
|
150
400
|
|
|
151
|
-
Please send all issues to [GitHub Issues](https://github.com/JairusSW/as
|
|
401
|
+
Please send all issues to [GitHub Issues](https://github.com/JairusSW/json-as/issues) and to converse, please send me an email at [me@jairus.dev](mailto:me@jairus.dev)
|
|
152
402
|
|
|
153
403
|
- **Email:** Send me inquiries, questions, or requests at [me@jairus.dev](mailto:me@jairus.dev)
|
|
154
|
-
- **GitHub:** Visit the official GitHub repository [Here](https://github.com/JairusSW/as
|
|
404
|
+
- **GitHub:** Visit the official GitHub repository [Here](https://github.com/JairusSW/json-as)
|
|
155
405
|
- **Website:** Visit my official website at [jairus.dev](https://jairus.dev/)
|
|
156
|
-
- **Discord:**
|
|
406
|
+
- **Discord:** Contact me at [My Discord](https://discord.com/users/600700584038760448) or on the [AssemblyScript Discord Server](https://discord.gg/assemblyscript/)
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { bench } from "as-bench/assembly";
|
|
2
2
|
import { JSON } from "..";
|
|
3
3
|
import { Vec3 } from "./schemas";
|
|
4
|
-
import { bs } from "../../modules/as-bs/assembly";
|
|
5
4
|
import { serializeString_SIMD } from "../serialize/simd/string";
|
|
6
5
|
import { serializeString } from "../serialize/simple/string";
|
|
7
6
|
import { deserializeString } from "../deserialize/simple/string";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {JSON} from "..";
|
|
2
|
+
import {Vec3} from "./schemas";
|
|
3
|
+
import {bench} from "../custom/bench";
|
|
4
|
+
import {serializeString_SIMD} from "../serialize/simd/string";
|
|
5
|
+
import {deserializeString_SIMD} from "../deserialize/simd/string";
|
|
6
|
+
import {serializeString} from "../serialize/simple/string";
|
|
7
|
+
import {deserializeString} from "../deserialize/simple/string";
|
|
8
|
+
|
|
9
|
+
const vec: Vec3 = {x: 1, y: 2, z: 3};
|
|
10
|
+
|
|
11
|
+
bs.ensureSize(4096);
|
|
12
|
+
|
|
13
|
+
bench(
|
|
14
|
+
"Serialize String (Simple)",
|
|
15
|
+
() => {
|
|
16
|
+
serializeString("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~`!@#$%^&*()-_=+{[}]|\\:;\"'?/>.<,'\"}");
|
|
17
|
+
},
|
|
18
|
+
25_000_000
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
// bench("Deserialize String Simple", () => {
|
|
22
|
+
// deserializeString_SIMD("\"hello world\"")
|
|
23
|
+
// });
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {JSON} from "..";
|
|
2
|
+
import {Vec3} from "./schemas";
|
|
3
|
+
import {bench} from "./bench";
|
|
4
|
+
|
|
5
|
+
const vec: Vec3 = {x: 1, y: 2, z: 3};
|
|
6
|
+
|
|
7
|
+
bs.ensureSize(4096);
|
|
8
|
+
bench(
|
|
9
|
+
"Serialize Vector3",
|
|
10
|
+
() => {
|
|
11
|
+
// JSON.__serialize(vec);
|
|
12
|
+
// bs.offset = changetype<usize>(bs.buffer);
|
|
13
|
+
// bs.stackSize = 0;
|
|
14
|
+
JSON.stringify(vec);
|
|
15
|
+
},
|
|
16
|
+
25_000_000
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
// bench("Deserialize Vector3", () => {
|
|
20
|
+
// JSON.parse<Vec3>('{"x":1,"y":2,"z":3}');
|
|
21
|
+
// });
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { JSON } from "..";
|
|
2
|
-
import { describe, expect } from "
|
|
2
|
+
import { describe, expect } from "./lib";
|
|
3
3
|
|
|
4
4
|
describe("Should serialize integer arrays", () => {
|
|
5
5
|
expect(JSON.stringify<u32[]>([0, 100, 101])).toBe("[0,100,101]");
|
|
@@ -58,6 +58,47 @@ 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
|
+
});
|
|
61
102
|
|
|
62
103
|
@json
|
|
63
104
|
class Vec3 {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { JSON } from "..";
|
|
2
|
+
import { describe, expect } from "./lib";
|
|
3
|
+
import { bytes } from "../util";
|
|
4
|
+
|
|
5
|
+
@json
|
|
6
|
+
class Point {
|
|
7
|
+
x: f64 = 0.0;
|
|
8
|
+
y: f64 = 0.0;
|
|
9
|
+
constructor(x: f64, y: f64) {
|
|
10
|
+
this.x = x;
|
|
11
|
+
this.y = y;
|
|
12
|
+
}
|
|
13
|
+
@serializer
|
|
14
|
+
serializer(self: Point): string {
|
|
15
|
+
return `(${self.x},${self.y})`;
|
|
16
|
+
}
|
|
17
|
+
@deserializer
|
|
18
|
+
deserializer(data: string): Point {
|
|
19
|
+
const dataSize = bytes(data);
|
|
20
|
+
if (dataSize <= 2) throw new Error("Could not deserialize provided data as type Point");
|
|
21
|
+
|
|
22
|
+
const c = data.indexOf(",");
|
|
23
|
+
const x = data.slice(1, c);
|
|
24
|
+
const y = data.slice(c + 1, data.length - 1);
|
|
25
|
+
|
|
26
|
+
return new Point(
|
|
27
|
+
f64.parse(x),
|
|
28
|
+
f64.parse(y)
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
describe("Should serialize using custom serializers", () => {
|
|
35
|
+
expect(JSON.stringify<Point>(new Point(1,2))).toBe("(1.0,2.0)");
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe("Should deserialize using custom deserializers", () => {
|
|
39
|
+
const p1 = JSON.parse<Point>("(1.0,2.0)");
|
|
40
|
+
expect(p1.x.toString()).toBe("1.0");
|
|
41
|
+
expect(p1.y.toString()).toBe("2.0");
|
|
42
|
+
});
|