@colyseus/schema 3.0.76 → 4.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/build/cjs/index.js +781 -434
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +779 -435
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +781 -434
- package/lib/Metadata.js +1 -5
- package/lib/Metadata.js.map +1 -1
- package/lib/Reflection.d.ts +50 -17
- package/lib/Reflection.js +151 -202
- package/lib/Reflection.js.map +1 -1
- package/lib/Schema.d.ts +13 -1
- package/lib/Schema.js +73 -9
- package/lib/Schema.js.map +1 -1
- package/lib/annotations.d.ts +6 -1
- package/lib/annotations.js +8 -34
- package/lib/annotations.js.map +1 -1
- package/lib/bench_encode.js +34 -1
- package/lib/bench_encode.js.map +1 -1
- package/lib/codegen/api.js +35 -2
- package/lib/codegen/api.js.map +1 -1
- package/lib/codegen/cli.js +4 -1
- package/lib/codegen/cli.js.map +1 -1
- package/lib/codegen/parser.js +35 -2
- package/lib/codegen/parser.js.map +1 -1
- package/lib/codegen/types.js +34 -1
- package/lib/codegen/types.js.map +1 -1
- package/lib/decoder/DecodeOperation.d.ts +2 -2
- package/lib/decoder/DecodeOperation.js +3 -3
- package/lib/decoder/DecodeOperation.js.map +1 -1
- package/lib/decoder/Decoder.d.ts +3 -3
- package/lib/decoder/Decoder.js +2 -2
- package/lib/decoder/Decoder.js.map +1 -1
- package/lib/decoder/ReferenceTracker.d.ts +0 -1
- package/lib/decoder/ReferenceTracker.js +9 -7
- package/lib/decoder/ReferenceTracker.js.map +1 -1
- package/lib/decoder/strategy/Callbacks.d.ts +154 -0
- package/lib/decoder/strategy/Callbacks.js +340 -0
- package/lib/decoder/strategy/Callbacks.js.map +1 -0
- package/lib/decoder/strategy/{StateCallbacks.d.ts → getDecoderStateCallbacks.d.ts} +6 -0
- package/lib/decoder/strategy/{StateCallbacks.js → getDecoderStateCallbacks.js} +17 -10
- package/lib/decoder/strategy/getDecoderStateCallbacks.js.map +1 -0
- package/lib/encoder/ChangeTree.d.ts +2 -2
- package/lib/encoder/ChangeTree.js.map +1 -1
- package/lib/encoder/EncodeOperation.d.ts +2 -2
- package/lib/encoder/EncodeOperation.js +3 -3
- package/lib/encoder/EncodeOperation.js.map +1 -1
- package/lib/encoder/Encoder.d.ts +6 -6
- package/lib/encoder/Encoder.js +19 -18
- package/lib/encoder/Encoder.js.map +1 -1
- package/lib/encoder/Root.js +17 -14
- package/lib/encoder/Root.js.map +1 -1
- package/lib/encoder/StateView.js +13 -12
- package/lib/encoder/StateView.js.map +1 -1
- package/lib/encoding/decode.d.ts +2 -2
- package/lib/encoding/encode.d.ts +3 -1
- package/lib/encoding/encode.js.map +1 -1
- package/lib/index.d.ts +3 -2
- package/lib/index.js +7 -3
- package/lib/index.js.map +1 -1
- package/lib/types/HelperTypes.d.ts +7 -14
- package/lib/types/HelperTypes.js.map +1 -1
- package/lib/types/custom/ArraySchema.d.ts +2 -1
- package/lib/types/custom/ArraySchema.js.map +1 -1
- package/lib/types/custom/CollectionSchema.d.ts +2 -1
- package/lib/types/custom/CollectionSchema.js.map +1 -1
- package/lib/types/custom/MapSchema.d.ts +3 -2
- package/lib/types/custom/MapSchema.js.map +1 -1
- package/lib/types/custom/SetSchema.d.ts +2 -1
- package/lib/types/custom/SetSchema.js.map +1 -1
- package/lib/types/symbols.d.ts +1 -0
- package/lib/types/symbols.js +2 -1
- package/lib/types/symbols.js.map +1 -1
- package/lib/utils.js +1 -1
- package/lib/utils.js.map +1 -1
- package/package.json +12 -16
- package/src/Metadata.ts +1 -5
- package/src/Reflection.ts +185 -174
- package/src/Schema.ts +81 -13
- package/src/annotations.ts +14 -40
- package/src/codegen/parser.ts +1 -1
- package/src/decoder/DecodeOperation.ts +9 -9
- package/src/decoder/Decoder.ts +6 -6
- package/src/decoder/ReferenceTracker.ts +10 -8
- package/src/decoder/strategy/Callbacks.ts +547 -0
- package/src/decoder/strategy/{StateCallbacks.ts → getDecoderStateCallbacks.ts} +17 -11
- package/src/encoder/ChangeTree.ts +4 -7
- package/src/encoder/EncodeOperation.ts +9 -9
- package/src/encoder/Encoder.ts +26 -18
- package/src/encoder/Root.ts +20 -15
- package/src/encoder/StateView.ts +15 -13
- package/src/encoding/encode.ts +1 -1
- package/src/index.ts +3 -2
- package/src/types/HelperTypes.ts +13 -11
- package/src/types/custom/ArraySchema.ts +2 -1
- package/src/types/custom/CollectionSchema.ts +4 -2
- package/src/types/custom/MapSchema.ts +4 -2
- package/src/types/custom/SetSchema.ts +3 -1
- package/src/types/symbols.ts +1 -0
- package/src/utils.ts +2 -2
- package/lib/Decoder.d.ts +0 -16
- package/lib/Decoder.js +0 -182
- package/lib/Decoder.js.map +0 -1
- package/lib/Encoder.d.ts +0 -13
- package/lib/Encoder.js +0 -79
- package/lib/Encoder.js.map +0 -1
- package/lib/changes/ChangeSet.d.ts +0 -12
- package/lib/changes/ChangeSet.js +0 -35
- package/lib/changes/ChangeSet.js.map +0 -1
- package/lib/changes/ChangeTree.d.ts +0 -53
- package/lib/changes/ChangeTree.js +0 -202
- package/lib/changes/ChangeTree.js.map +0 -1
- package/lib/changes/DecodeOperation.d.ts +0 -15
- package/lib/changes/DecodeOperation.js +0 -186
- package/lib/changes/DecodeOperation.js.map +0 -1
- package/lib/changes/EncodeOperation.d.ts +0 -18
- package/lib/changes/EncodeOperation.js +0 -130
- package/lib/changes/EncodeOperation.js.map +0 -1
- package/lib/changes/ReferenceTracker.d.ts +0 -14
- package/lib/changes/ReferenceTracker.js +0 -83
- package/lib/changes/ReferenceTracker.js.map +0 -1
- package/lib/changes/consts.d.ts +0 -14
- package/lib/changes/consts.js +0 -18
- package/lib/changes/consts.js.map +0 -1
- package/lib/decoder/strategy/StateCallbacks.js.map +0 -1
- package/lib/decoding/decode.d.ts +0 -48
- package/lib/decoding/decode.js +0 -267
- package/lib/decoding/decode.js.map +0 -1
- package/lib/ecs.d.ts +0 -11
- package/lib/ecs.js +0 -160
- package/lib/ecs.js.map +0 -1
- package/lib/filters/index.d.ts +0 -8
- package/lib/filters/index.js +0 -24
- package/lib/filters/index.js.map +0 -1
- package/lib/spec.d.ts +0 -13
- package/lib/spec.js +0 -42
- package/lib/spec.js.map +0 -1
- package/lib/types/ArraySchema.d.ts +0 -238
- package/lib/types/ArraySchema.js +0 -555
- package/lib/types/ArraySchema.js.map +0 -1
- package/lib/types/CollectionSchema.d.ts +0 -35
- package/lib/types/CollectionSchema.js +0 -150
- package/lib/types/CollectionSchema.js.map +0 -1
- package/lib/types/MapSchema.d.ts +0 -38
- package/lib/types/MapSchema.js +0 -215
- package/lib/types/MapSchema.js.map +0 -1
- package/lib/types/SetSchema.d.ts +0 -32
- package/lib/types/SetSchema.js +0 -162
- package/lib/types/SetSchema.js.map +0 -1
- package/lib/types/typeRegistry.d.ts +0 -5
- package/lib/types/typeRegistry.js +0 -13
- package/lib/types/typeRegistry.js.map +0 -1
- package/lib/usage.d.ts +0 -1
- package/lib/usage.js +0 -22
- package/lib/usage.js.map +0 -1
- package/lib/v3.d.ts +0 -1
- package/lib/v3.js +0 -427
- package/lib/v3.js.map +0 -1
- package/lib/v3_experiment.d.ts +0 -1
- package/lib/v3_experiment.js +0 -407
- package/lib/v3_experiment.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { OPERATION } from "../encoding/spec";
|
|
2
|
-
import { $changes, $childType, $getByIndex } from "../types/symbols";
|
|
2
|
+
import { $changes, $childType, $getByIndex, $refId } from "../types/symbols";
|
|
3
3
|
|
|
4
4
|
import { encode } from "../encoding/encode";
|
|
5
5
|
|
|
@@ -13,7 +13,7 @@ import type { Metadata } from "../Metadata";
|
|
|
13
13
|
|
|
14
14
|
export type EncodeOperation<T extends Ref = any> = (
|
|
15
15
|
encoder: Encoder,
|
|
16
|
-
bytes:
|
|
16
|
+
bytes: Uint8Array,
|
|
17
17
|
changeTree: ChangeTree<T>,
|
|
18
18
|
index: number,
|
|
19
19
|
operation: OPERATION,
|
|
@@ -25,7 +25,7 @@ export type EncodeOperation<T extends Ref = any> = (
|
|
|
25
25
|
|
|
26
26
|
export function encodeValue(
|
|
27
27
|
encoder: Encoder,
|
|
28
|
-
bytes:
|
|
28
|
+
bytes: Uint8Array,
|
|
29
29
|
type: any,
|
|
30
30
|
value: any,
|
|
31
31
|
operation: OPERATION,
|
|
@@ -39,7 +39,7 @@ export function encodeValue(
|
|
|
39
39
|
// Encode refId for this instance.
|
|
40
40
|
// The actual instance is going to be encoded on next `changeTree` iteration.
|
|
41
41
|
//
|
|
42
|
-
encode.number(bytes, value[$
|
|
42
|
+
encode.number(bytes, value[$refId], it);
|
|
43
43
|
|
|
44
44
|
// Try to encode inherited TYPE_ID if it's an ADD operation.
|
|
45
45
|
if ((operation & OPERATION.ADD) === OPERATION.ADD) {
|
|
@@ -51,7 +51,7 @@ export function encodeValue(
|
|
|
51
51
|
// Encode refId for this instance.
|
|
52
52
|
// The actual instance is going to be encoded on next `changeTree` iteration.
|
|
53
53
|
//
|
|
54
|
-
encode.number(bytes, value[$
|
|
54
|
+
encode.number(bytes, value[$refId], it);
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
|
|
@@ -61,7 +61,7 @@ export function encodeValue(
|
|
|
61
61
|
*/
|
|
62
62
|
export const encodeSchemaOperation: EncodeOperation = function <T extends Schema> (
|
|
63
63
|
encoder: Encoder,
|
|
64
|
-
bytes:
|
|
64
|
+
bytes: Uint8Array,
|
|
65
65
|
changeTree: ChangeTree<T>,
|
|
66
66
|
index: number,
|
|
67
67
|
operation: OPERATION,
|
|
@@ -98,7 +98,7 @@ export const encodeSchemaOperation: EncodeOperation = function <T extends Schema
|
|
|
98
98
|
*/
|
|
99
99
|
export const encodeKeyValueOperation: EncodeOperation = function (
|
|
100
100
|
encoder: Encoder,
|
|
101
|
-
bytes:
|
|
101
|
+
bytes: Uint8Array,
|
|
102
102
|
changeTree: ChangeTree,
|
|
103
103
|
index: number,
|
|
104
104
|
operation: OPERATION,
|
|
@@ -163,7 +163,7 @@ export const encodeKeyValueOperation: EncodeOperation = function (
|
|
|
163
163
|
*/
|
|
164
164
|
export const encodeArray: EncodeOperation = function (
|
|
165
165
|
encoder: Encoder,
|
|
166
|
-
bytes:
|
|
166
|
+
bytes: Uint8Array,
|
|
167
167
|
changeTree: ChangeTree<ArraySchema>,
|
|
168
168
|
field: number,
|
|
169
169
|
operation: OPERATION,
|
|
@@ -182,7 +182,7 @@ export const encodeArray: EncodeOperation = function (
|
|
|
182
182
|
// Skip encoding if item is undefined (e.g. when clear() is called)
|
|
183
183
|
if (!item) { return; }
|
|
184
184
|
|
|
185
|
-
refOrIndex = item[$
|
|
185
|
+
refOrIndex = item[$refId];
|
|
186
186
|
|
|
187
187
|
if (operation === OPERATION.DELETE) {
|
|
188
188
|
operation = OPERATION.DELETE_BY_REFID;
|
package/src/encoder/Encoder.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Schema } from "../Schema";
|
|
2
2
|
import { TypeContext } from "../types/TypeContext";
|
|
3
|
-
import { $changes, $encoder, $filter, $getByIndex } from "../types/symbols";
|
|
3
|
+
import { $changes, $encoder, $filter, $getByIndex, $refId } from "../types/symbols";
|
|
4
4
|
|
|
5
5
|
import { encode } from "../encoding/encode";
|
|
6
6
|
import type { Iterator } from "../encoding/decode";
|
|
@@ -13,9 +13,16 @@ import type { Metadata } from "../Metadata";
|
|
|
13
13
|
import type { ChangeSetName, ChangeTree, ChangeTreeList, ChangeTreeNode } from "./ChangeTree";
|
|
14
14
|
import { createChangeTreeList } from "./ChangeTree";
|
|
15
15
|
|
|
16
|
+
function concatBytes(a: Uint8Array, b: Uint8Array): Uint8Array {
|
|
17
|
+
const result = new Uint8Array(a.length + b.length);
|
|
18
|
+
result.set(a, 0);
|
|
19
|
+
result.set(b, a.length);
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
|
|
16
23
|
export class Encoder<T extends Schema = any> {
|
|
17
|
-
static BUFFER_SIZE =
|
|
18
|
-
sharedBuffer =
|
|
24
|
+
static BUFFER_SIZE = 8 * 1024; // 8KB
|
|
25
|
+
sharedBuffer = new Uint8Array(Encoder.BUFFER_SIZE);
|
|
19
26
|
|
|
20
27
|
context: TypeContext;
|
|
21
28
|
state: T;
|
|
@@ -52,7 +59,7 @@ export class Encoder<T extends Schema = any> {
|
|
|
52
59
|
changeSetName: ChangeSetName = "changes",
|
|
53
60
|
isEncodeAll = changeSetName === "allChanges",
|
|
54
61
|
initialOffset = it.offset // cache current offset in case we need to resize the buffer
|
|
55
|
-
):
|
|
62
|
+
): Uint8Array {
|
|
56
63
|
const hasView = (view !== undefined);
|
|
57
64
|
const rootChangeTree = this.state[$changes];
|
|
58
65
|
|
|
@@ -63,7 +70,7 @@ export class Encoder<T extends Schema = any> {
|
|
|
63
70
|
|
|
64
71
|
if (hasView) {
|
|
65
72
|
if (!view.isChangeTreeVisible(changeTree)) {
|
|
66
|
-
// console.log("MARK AS INVISIBLE:", { ref: changeTree.ref.constructor.name, refId: changeTree.refId, raw: changeTree.ref.toJSON() });
|
|
73
|
+
// console.log("MARK AS INVISIBLE:", { ref: changeTree.ref.constructor.name, refId: changeTree.ref[$refId], raw: changeTree.ref.toJSON() });
|
|
67
74
|
view.invisible.add(changeTree);
|
|
68
75
|
continue; // skip this change tree
|
|
69
76
|
}
|
|
@@ -86,7 +93,7 @@ export class Encoder<T extends Schema = any> {
|
|
|
86
93
|
// (unless it "hasView", which will need to revisit the root)
|
|
87
94
|
if (hasView || it.offset > initialOffset || changeTree !== rootChangeTree) {
|
|
88
95
|
buffer[it.offset++] = SWITCH_TO_STRUCTURE & 255;
|
|
89
|
-
encode.number(buffer,
|
|
96
|
+
encode.number(buffer, ref[$refId], it);
|
|
90
97
|
}
|
|
91
98
|
|
|
92
99
|
for (let j = 0; j < numChanges; j++) {
|
|
@@ -121,10 +128,9 @@ export class Encoder<T extends Schema = any> {
|
|
|
121
128
|
}
|
|
122
129
|
|
|
123
130
|
if (it.offset > buffer.byteLength) {
|
|
124
|
-
// we can assume that n + 1
|
|
125
|
-
// multiples of
|
|
126
|
-
|
|
127
|
-
const newSize = Math.ceil(it.offset / (Buffer.poolSize ?? 8 * 1024)) * (Buffer.poolSize ?? 8 * 1024);
|
|
131
|
+
// we can assume that n + 1 BUFFER_SIZE will suffice given that we are likely done with encoding at this point
|
|
132
|
+
// multiples of BUFFER_SIZE are faster to allocate than arbitrary sizes
|
|
133
|
+
const newSize = Math.ceil(it.offset / Encoder.BUFFER_SIZE) * Encoder.BUFFER_SIZE;
|
|
128
134
|
|
|
129
135
|
console.warn(`@colyseus/schema buffer overflow. Encoded state is higher than default BUFFER_SIZE. Use the following to increase default BUFFER_SIZE:
|
|
130
136
|
|
|
@@ -136,7 +142,9 @@ export class Encoder<T extends Schema = any> {
|
|
|
136
142
|
// resize buffer and re-encode (TODO: can we avoid re-encoding here?)
|
|
137
143
|
// -> No we probably can't unless we catch the need for resize before encoding which is likely more computationally expensive than resizing on demand
|
|
138
144
|
//
|
|
139
|
-
|
|
145
|
+
const newBuffer = new Uint8Array(newSize);
|
|
146
|
+
newBuffer.set(buffer); // copy previous encoding steps beyond the initialOffset
|
|
147
|
+
buffer = newBuffer;
|
|
140
148
|
|
|
141
149
|
// assign resized buffer to local sharedBuffer
|
|
142
150
|
if (buffer === this.sharedBuffer) {
|
|
@@ -151,7 +159,7 @@ export class Encoder<T extends Schema = any> {
|
|
|
151
159
|
}
|
|
152
160
|
}
|
|
153
161
|
|
|
154
|
-
encodeAll(it: Iterator = { offset: 0 }, buffer
|
|
162
|
+
encodeAll(it: Iterator = { offset: 0 }, buffer = this.sharedBuffer) {
|
|
155
163
|
return this.encode(it, undefined, buffer, "allChanges", true);
|
|
156
164
|
}
|
|
157
165
|
|
|
@@ -161,10 +169,10 @@ export class Encoder<T extends Schema = any> {
|
|
|
161
169
|
// try to encode "filtered" changes
|
|
162
170
|
this.encode(it, view, bytes, "allFilteredChanges", true, viewOffset);
|
|
163
171
|
|
|
164
|
-
return
|
|
172
|
+
return concatBytes(
|
|
165
173
|
bytes.subarray(0, sharedOffset),
|
|
166
174
|
bytes.subarray(viewOffset, it.offset)
|
|
167
|
-
|
|
175
|
+
);
|
|
168
176
|
}
|
|
169
177
|
|
|
170
178
|
encodeView(view: StateView, sharedOffset: number, it: Iterator, bytes = this.sharedBuffer) {
|
|
@@ -195,7 +203,7 @@ export class Encoder<T extends Schema = any> {
|
|
|
195
203
|
const metadata = ctor[Symbol.metadata];
|
|
196
204
|
|
|
197
205
|
bytes[it.offset++] = SWITCH_TO_STRUCTURE & 255;
|
|
198
|
-
encode.number(bytes,
|
|
206
|
+
encode.number(bytes, ref[$refId], it);
|
|
199
207
|
|
|
200
208
|
for (let i = 0, numChanges = keys.length; i < numChanges; i++) {
|
|
201
209
|
const index = Number(keys[i]);
|
|
@@ -219,10 +227,10 @@ export class Encoder<T extends Schema = any> {
|
|
|
219
227
|
// try to encode "filtered" changes
|
|
220
228
|
this.encode(it, view, bytes, "filteredChanges", false, viewOffset);
|
|
221
229
|
|
|
222
|
-
return
|
|
230
|
+
return concatBytes(
|
|
223
231
|
bytes.subarray(0, sharedOffset),
|
|
224
232
|
bytes.subarray(viewOffset, it.offset)
|
|
225
|
-
|
|
233
|
+
);
|
|
226
234
|
}
|
|
227
235
|
|
|
228
236
|
discardChanges() {
|
|
@@ -243,7 +251,7 @@ export class Encoder<T extends Schema = any> {
|
|
|
243
251
|
this.root.filteredChanges = createChangeTreeList();
|
|
244
252
|
}
|
|
245
253
|
|
|
246
|
-
tryEncodeTypeId (bytes:
|
|
254
|
+
tryEncodeTypeId (bytes: Uint8Array, baseType: typeof Schema, targetType: typeof Schema, it: Iterator) {
|
|
247
255
|
const baseTypeId = this.context.getTypeId(baseType);
|
|
248
256
|
const targetTypeId = this.context.getTypeId(targetType);
|
|
249
257
|
|
package/src/encoder/Root.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { OPERATION } from "../encoding/spec";
|
|
2
2
|
import { TypeContext } from "../types/TypeContext";
|
|
3
3
|
import { ChangeTree, setOperationAtIndex, ChangeTreeList, createChangeTreeList, ChangeSetName, type ChangeTreeNode } from "./ChangeTree";
|
|
4
|
-
import { $changes } from "../types/symbols";
|
|
4
|
+
import { $changes, $refId } from "../types/symbols";
|
|
5
5
|
|
|
6
6
|
export class Root {
|
|
7
7
|
protected nextUniqueId: number = 0;
|
|
@@ -24,15 +24,19 @@ export class Root {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
add(changeTree: ChangeTree) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
const ref = changeTree.ref;
|
|
28
|
+
|
|
29
|
+
// Assign unique `refId` to ref if it doesn't have one yet.
|
|
30
|
+
if (ref[$refId] === undefined) {
|
|
31
|
+
ref[$refId] = this.getNextUniqueId();
|
|
30
32
|
}
|
|
31
33
|
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
+
const refId = ref[$refId];
|
|
35
|
+
|
|
36
|
+
const isNewChangeTree = (this.changeTrees[refId] === undefined);
|
|
37
|
+
if (isNewChangeTree) { this.changeTrees[refId] = changeTree; }
|
|
34
38
|
|
|
35
|
-
const previousRefCount = this.refCount[
|
|
39
|
+
const previousRefCount = this.refCount[refId];
|
|
36
40
|
if (previousRefCount === 0) {
|
|
37
41
|
//
|
|
38
42
|
// When a ChangeTree is re-added, it means that it was previously removed.
|
|
@@ -46,24 +50,25 @@ export class Root {
|
|
|
46
50
|
}
|
|
47
51
|
}
|
|
48
52
|
|
|
49
|
-
this.refCount[
|
|
53
|
+
this.refCount[refId] = (previousRefCount || 0) + 1;
|
|
50
54
|
|
|
51
|
-
// console.log("ADD", { refId
|
|
55
|
+
// console.log("ADD", { refId, ref: ref.constructor.name, refCount: this.refCount[refId], isNewChangeTree });
|
|
52
56
|
|
|
53
57
|
return isNewChangeTree;
|
|
54
58
|
}
|
|
55
59
|
|
|
56
60
|
remove(changeTree: ChangeTree) {
|
|
57
|
-
const
|
|
61
|
+
const refId = changeTree.ref[$refId];
|
|
62
|
+
const refCount = (this.refCount[refId]) - 1;
|
|
58
63
|
|
|
59
|
-
// console.log("REMOVE", { refId
|
|
64
|
+
// console.log("REMOVE", { refId, ref: changeTree.ref.constructor.name, refCount, needRemove: refCount <= 0 });
|
|
60
65
|
|
|
61
66
|
if (refCount <= 0) {
|
|
62
67
|
//
|
|
63
68
|
// Only remove "root" reference if it's the last reference
|
|
64
69
|
//
|
|
65
70
|
changeTree.root = undefined;
|
|
66
|
-
delete this.changeTrees[
|
|
71
|
+
delete this.changeTrees[refId];
|
|
67
72
|
|
|
68
73
|
this.removeChangeFromChangeSet("allChanges", changeTree);
|
|
69
74
|
this.removeChangeFromChangeSet("changes", changeTree);
|
|
@@ -73,13 +78,13 @@ export class Root {
|
|
|
73
78
|
this.removeChangeFromChangeSet("filteredChanges", changeTree);
|
|
74
79
|
}
|
|
75
80
|
|
|
76
|
-
this.refCount[
|
|
81
|
+
this.refCount[refId] = 0;
|
|
77
82
|
|
|
78
83
|
changeTree.forEachChild((child, _) => {
|
|
79
84
|
if (child.removeParent(changeTree.ref)) {
|
|
80
85
|
if ((
|
|
81
86
|
child.parentChain === undefined || // no parent, remove it
|
|
82
|
-
(child.parentChain && this.refCount[child.refId] > 0) // parent is still in use, but has more than one reference, remove it
|
|
87
|
+
(child.parentChain && this.refCount[child.ref[$refId]] > 0) // parent is still in use, but has more than one reference, remove it
|
|
83
88
|
)) {
|
|
84
89
|
this.remove(child);
|
|
85
90
|
|
|
@@ -91,7 +96,7 @@ export class Root {
|
|
|
91
96
|
});
|
|
92
97
|
|
|
93
98
|
} else {
|
|
94
|
-
this.refCount[
|
|
99
|
+
this.refCount[refId] = refCount;
|
|
95
100
|
|
|
96
101
|
//
|
|
97
102
|
// When losing a reference to an instance, it is best to move the
|
package/src/encoder/StateView.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ChangeTree, IndexedOperations, Ref } from "./ChangeTree";
|
|
2
|
-
import { $changes, $fieldIndexesByViewTag, $viewFieldIndexes } from "../types/symbols";
|
|
2
|
+
import { $changes, $fieldIndexesByViewTag, $refId, $viewFieldIndexes } from "../types/symbols";
|
|
3
3
|
import { DEFAULT_VIEW_TAG } from "../annotations";
|
|
4
4
|
import { OPERATION } from "../encoding/spec";
|
|
5
5
|
import { Metadata } from "../Metadata";
|
|
@@ -52,7 +52,7 @@ export class StateView {
|
|
|
52
52
|
|
|
53
53
|
} else if (
|
|
54
54
|
!parentChangeTree &&
|
|
55
|
-
|
|
55
|
+
obj[$refId] !== 0 // allow root object
|
|
56
56
|
) {
|
|
57
57
|
/**
|
|
58
58
|
* TODO: can we avoid this?
|
|
@@ -82,11 +82,11 @@ export class StateView {
|
|
|
82
82
|
this.addParentOf(changeTree, tag);
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
let changes = this.changes.get(
|
|
85
|
+
let changes = this.changes.get(obj[$refId]);
|
|
86
86
|
if (changes === undefined) {
|
|
87
87
|
changes = {};
|
|
88
88
|
// FIXME / OPTIMIZE: do not add if no changes are needed
|
|
89
|
-
this.changes.set(
|
|
89
|
+
this.changes.set(obj[$refId], changes);
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
let isChildAdded = false;
|
|
@@ -182,10 +182,10 @@ export class StateView {
|
|
|
182
182
|
|
|
183
183
|
// add parent's tag properties
|
|
184
184
|
if (changeTree.getChange(parentIndex) !== OPERATION.DELETE) {
|
|
185
|
-
let changes = this.changes.get(changeTree.refId);
|
|
185
|
+
let changes = this.changes.get(changeTree.ref[$refId]);
|
|
186
186
|
if (changes === undefined) {
|
|
187
187
|
changes = {};
|
|
188
|
-
this.changes.set(changeTree.refId, changes);
|
|
188
|
+
this.changes.set(changeTree.ref[$refId], changes);
|
|
189
189
|
}
|
|
190
190
|
|
|
191
191
|
if (!this.tags) {
|
|
@@ -227,28 +227,30 @@ export class StateView {
|
|
|
227
227
|
const ref = changeTree.ref;
|
|
228
228
|
const metadata: Metadata = ref.constructor[Symbol.metadata]; // ArraySchema/MapSchema do not have metadata
|
|
229
229
|
|
|
230
|
-
|
|
230
|
+
const refId = ref[$refId];
|
|
231
|
+
|
|
232
|
+
let changes = this.changes.get(refId);
|
|
231
233
|
if (changes === undefined) {
|
|
232
234
|
changes = {};
|
|
233
|
-
this.changes.set(
|
|
235
|
+
this.changes.set(refId, changes);
|
|
234
236
|
}
|
|
235
237
|
|
|
236
238
|
if (tag === DEFAULT_VIEW_TAG) {
|
|
237
239
|
// parent is collection (Map/Array)
|
|
238
240
|
const parent = changeTree.parent;
|
|
239
241
|
if (parent && !Metadata.isValidInstance(parent) && changeTree.isFiltered) {
|
|
240
|
-
const
|
|
241
|
-
let changes = this.changes.get(
|
|
242
|
+
const parentRefId = parent[$refId];
|
|
243
|
+
let changes = this.changes.get(parentRefId);
|
|
242
244
|
if (changes === undefined) {
|
|
243
245
|
changes = {};
|
|
244
|
-
this.changes.set(
|
|
246
|
+
this.changes.set(parentRefId, changes);
|
|
245
247
|
|
|
246
248
|
} else if (changes[changeTree.parentIndex] === OPERATION.ADD) {
|
|
247
249
|
//
|
|
248
250
|
// SAME PATCH ADD + REMOVE:
|
|
249
251
|
// The 'changes' of deleted structure should be ignored.
|
|
250
252
|
//
|
|
251
|
-
this.changes.delete(
|
|
253
|
+
this.changes.delete(refId);
|
|
252
254
|
}
|
|
253
255
|
|
|
254
256
|
// DELETE / DELETE BY REF ID
|
|
@@ -322,7 +324,7 @@ export class StateView {
|
|
|
322
324
|
|
|
323
325
|
// console.log("CHECK AGAINST PARENT...", {
|
|
324
326
|
// ref: changeTree.ref.constructor.name,
|
|
325
|
-
// refId: changeTree.refId,
|
|
327
|
+
// refId: changeTree.ref[$refId],
|
|
326
328
|
// parent: changeTree.parent.constructor.name,
|
|
327
329
|
// });
|
|
328
330
|
|
package/src/encoding/encode.ts
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
import type { TextEncoder } from "util";
|
|
27
27
|
import type { Iterator } from "./decode";
|
|
28
28
|
|
|
29
|
-
export type BufferLike = number[]
|
|
29
|
+
export type BufferLike = ArrayLike<number> & { [index: number]: number };
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
32
|
* msgpack implementation highly based on notepack.io
|
package/src/index.ts
CHANGED
|
@@ -26,7 +26,7 @@ registerType("collection", { constructor: CollectionSchema, });
|
|
|
26
26
|
export { dumpChanges } from "./utils";
|
|
27
27
|
|
|
28
28
|
// Encoder / Decoder
|
|
29
|
-
export { $track, $encoder, $decoder, $filter, $getByIndex, $deleteByIndex, $changes, $childType } from "./types/symbols";
|
|
29
|
+
export { $track, $encoder, $decoder, $filter, $getByIndex, $deleteByIndex, $changes, $childType, $refId } from "./types/symbols";
|
|
30
30
|
export { encode } from "./encoding/encode";
|
|
31
31
|
export { decode, type Iterator } from "./encoding/decode";
|
|
32
32
|
|
|
@@ -62,7 +62,8 @@ export { TypeContext } from "./types/TypeContext";
|
|
|
62
62
|
// Helper types for type inference
|
|
63
63
|
export type { InferValueType, InferSchemaInstanceType, AssignableProps } from "./types/HelperTypes";
|
|
64
64
|
|
|
65
|
-
export { getDecoderStateCallbacks, CallbackProxy, SchemaCallback, CollectionCallback, SchemaCallbackProxy } from "./decoder/strategy/
|
|
65
|
+
export { getDecoderStateCallbacks, CallbackProxy, SchemaCallback, CollectionCallback, SchemaCallbackProxy } from "./decoder/strategy/getDecoderStateCallbacks";
|
|
66
|
+
export { Callbacks, StateCallbackStrategy } from "./decoder/strategy/Callbacks";
|
|
66
67
|
export { getRawChangesCallback } from "./decoder/strategy/RawChanges";
|
|
67
68
|
|
|
68
69
|
export { Encoder } from "./encoder/Encoder";
|
package/src/types/HelperTypes.ts
CHANGED
|
@@ -7,6 +7,13 @@ import type { SetSchema } from "./custom/SetSchema";
|
|
|
7
7
|
|
|
8
8
|
export type Constructor<T = {}> = new (...args: any[]) => T;
|
|
9
9
|
|
|
10
|
+
// Helper to convert primitive type literals to actual runtime types
|
|
11
|
+
type PrimitiveStringToType<T> =
|
|
12
|
+
T extends "string" ? string
|
|
13
|
+
: T extends "number" | "int8" | "uint8" | "int16" | "uint16" | "int32" | "uint32" | "int64" | "uint64" | "float32" | "float64" ? number
|
|
14
|
+
: T extends "boolean" ? boolean
|
|
15
|
+
: T;
|
|
16
|
+
|
|
10
17
|
export interface Collection<K = any, V = any, IT = V> {
|
|
11
18
|
[Symbol.iterator](): IterableIterator<IT>;
|
|
12
19
|
forEach(callback: Function): void;
|
|
@@ -38,25 +45,20 @@ export type InferValueType<T extends DefinitionType> =
|
|
|
38
45
|
: T extends { type: infer ChildType } ? (ChildType extends Record<string | number, string | number> ? ChildType[keyof ChildType] : ChildType) // TS ENUM
|
|
39
46
|
|
|
40
47
|
// Handle direct array patterns
|
|
41
|
-
: T extends Array<infer ChildType extends Constructor> ? InstanceType<ChildType
|
|
42
|
-
: T extends Array<infer ChildType extends
|
|
43
|
-
: T extends Array<infer ChildType> ? (ChildType extends Record<string | number, string | number> ? ChildType[keyof ChildType][] : ChildType[]) // TS ENUM
|
|
48
|
+
: T extends Array<infer ChildType extends Constructor> ? ArraySchema<InstanceType<ChildType>>
|
|
49
|
+
: T extends Array<infer ChildType> ? (ChildType extends Record<string | number, string | number> ? ArraySchema<ChildType[keyof ChildType]> : ArraySchema<PrimitiveStringToType<ChildType>>) // TS ENUM
|
|
44
50
|
|
|
45
51
|
// Handle collection object patterns
|
|
46
|
-
: T extends { array: infer ChildType extends Constructor } ? InstanceType<ChildType
|
|
47
|
-
: T extends { array: infer ChildType extends
|
|
48
|
-
: T extends { array: infer ChildType } ? (ChildType extends Record<string | number, string | number> ? ChildType[keyof ChildType][] : ChildType[]) // TS ENUM
|
|
52
|
+
: T extends { array: infer ChildType extends Constructor } ? ArraySchema<InstanceType<ChildType>>
|
|
53
|
+
: T extends { array: infer ChildType } ? (ChildType extends Record<string | number, string | number> ? ArraySchema<ChildType[keyof ChildType]> : ArraySchema<PrimitiveStringToType<ChildType>>) // TS ENUM
|
|
49
54
|
|
|
50
55
|
: T extends { map: infer ChildType extends Constructor } ? MapSchema<InstanceType<ChildType>>
|
|
51
|
-
: T extends { map: infer ChildType extends
|
|
52
|
-
: T extends { map: infer ChildType } ? (ChildType extends Record<string | number, string | number> ? MapSchema<ChildType[keyof ChildType]> : MapSchema<ChildType>) // TS ENUM
|
|
56
|
+
: T extends { map: infer ChildType } ? (ChildType extends Record<string | number, string | number> ? MapSchema<ChildType[keyof ChildType]> : MapSchema<PrimitiveStringToType<ChildType>>) // TS ENUM
|
|
53
57
|
|
|
54
58
|
: T extends { set: infer ChildType extends Constructor } ? SetSchema<InstanceType<ChildType>>
|
|
55
|
-
: T extends { set: infer ChildType extends RawPrimitiveType } ? SetSchema<InferValueType<ChildType>> // primitive types
|
|
56
59
|
: T extends { set: infer ChildType } ? (ChildType extends Record<string | number, string | number> ? SetSchema<ChildType[keyof ChildType]> : SetSchema<ChildType>) // TS ENUM
|
|
57
60
|
|
|
58
61
|
: T extends { collection: infer ChildType extends Constructor } ? CollectionSchema<InstanceType<ChildType>>
|
|
59
|
-
: T extends { collection: infer ChildType extends RawPrimitiveType } ? CollectionSchema<InferValueType<ChildType>> // primitive types
|
|
60
62
|
: T extends { collection: infer ChildType } ? (ChildType extends Record<string | number, string | number> ? CollectionSchema<ChildType[keyof ChildType]> : CollectionSchema<ChildType>) // TS ENUM
|
|
61
63
|
|
|
62
64
|
// Handle direct types
|
|
@@ -89,7 +91,7 @@ export type NonFunctionNonPrimitivePropNames<T> = {
|
|
|
89
91
|
}[keyof T];
|
|
90
92
|
|
|
91
93
|
// Helper to recursively convert Schema instances to their JSON representation
|
|
92
|
-
type ToJSONValue<U> = U extends Schema ? ToJSON<U> : U
|
|
94
|
+
type ToJSONValue<U> = U extends Schema ? ToJSON<U> : PrimitiveStringToType<U>;
|
|
93
95
|
|
|
94
96
|
export type ToJSON<T> = NonFunctionProps<{
|
|
95
97
|
[K in keyof T]:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $changes, $childType, $decoder, $deleteByIndex, $onEncodeEnd, $encoder, $filter, $getByIndex, $onDecodeEnd } from "../symbols";
|
|
1
|
+
import { $changes, $childType, $decoder, $deleteByIndex, $onEncodeEnd, $encoder, $filter, $getByIndex, $onDecodeEnd, $refId } from "../symbols";
|
|
2
2
|
import type { Schema } from "../../Schema";
|
|
3
3
|
import { type IRef, ChangeTree, setOperationAtIndex } from "../../encoder/ChangeTree";
|
|
4
4
|
import { OPERATION } from "../../encoding/spec";
|
|
@@ -21,6 +21,7 @@ const DEFAULT_SORT = (a: any, b: any) => {
|
|
|
21
21
|
export class ArraySchema<V = any> implements Array<V>, Collection<number, V>, IRef {
|
|
22
22
|
[n: number]: V;
|
|
23
23
|
[$changes]: ChangeTree;
|
|
24
|
+
[$refId]?: number;
|
|
24
25
|
|
|
25
26
|
protected [$childType]: string | typeof Schema;
|
|
26
27
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $changes, $childType, $decoder, $deleteByIndex, $encoder, $filter, $getByIndex, $onEncodeEnd } from "../symbols";
|
|
1
|
+
import { $changes, $childType, $decoder, $deleteByIndex, $encoder, $filter, $getByIndex, $onEncodeEnd, $refId } from "../symbols";
|
|
2
2
|
import { ChangeTree, type IRef } from "../../encoder/ChangeTree";
|
|
3
3
|
import { OPERATION } from "../../encoding/spec";
|
|
4
4
|
import { registerType } from "../registry";
|
|
@@ -11,7 +11,9 @@ import type { Schema } from "../../Schema";
|
|
|
11
11
|
type K = number; // TODO: allow to specify K generic on MapSchema.
|
|
12
12
|
|
|
13
13
|
export class CollectionSchema<V=any> implements Collection<K, V>, IRef {
|
|
14
|
-
|
|
14
|
+
[$changes]: ChangeTree;
|
|
15
|
+
[$refId]?: number;
|
|
16
|
+
|
|
15
17
|
protected [$childType]: string | typeof Schema;
|
|
16
18
|
|
|
17
19
|
protected $items: Map<number, V> = new Map<number, V>();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $changes, $childType, $decoder, $deleteByIndex, $onEncodeEnd, $encoder, $filter, $getByIndex, $numFields } from "../symbols";
|
|
1
|
+
import { $changes, $childType, $decoder, $deleteByIndex, $onEncodeEnd, $encoder, $filter, $getByIndex, $numFields, $refId } from "../symbols";
|
|
2
2
|
import { ChangeTree, IRef } from "../../encoder/ChangeTree";
|
|
3
3
|
import { OPERATION } from "../../encoding/spec";
|
|
4
4
|
import { registerType } from "../registry";
|
|
@@ -10,8 +10,10 @@ import type { Schema } from "../../Schema";
|
|
|
10
10
|
import { assertInstanceType } from "../../encoding/assert";
|
|
11
11
|
|
|
12
12
|
export class MapSchema<V=any, K extends string = string> implements Map<K, V>, Collection<K, V, [K, V]>, IRef {
|
|
13
|
-
protected childType: new () => V;
|
|
14
13
|
[$changes]: ChangeTree;
|
|
14
|
+
[$refId]?: number;
|
|
15
|
+
|
|
16
|
+
protected childType: new () => V;
|
|
15
17
|
protected [$childType]: string | typeof Schema;
|
|
16
18
|
|
|
17
19
|
protected $items: Map<K, V> = new Map<K, V>();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { OPERATION } from "../../encoding/spec";
|
|
2
2
|
import { registerType } from "../registry";
|
|
3
|
-
import { $changes, $childType, $decoder, $deleteByIndex, $encoder, $filter, $getByIndex, $onEncodeEnd } from "../symbols";
|
|
3
|
+
import { $changes, $childType, $decoder, $deleteByIndex, $encoder, $filter, $getByIndex, $onEncodeEnd, $refId } from "../symbols";
|
|
4
4
|
import { Collection } from "../HelperTypes";
|
|
5
5
|
import { ChangeTree, type IRef } from "../../encoder/ChangeTree";
|
|
6
6
|
import { encodeKeyValueOperation } from "../../encoder/EncodeOperation";
|
|
@@ -10,6 +10,8 @@ import type { Schema } from "../../Schema";
|
|
|
10
10
|
|
|
11
11
|
export class SetSchema<V=any> implements Collection<number, V>, IRef {
|
|
12
12
|
[$changes]: ChangeTree;
|
|
13
|
+
[$refId]?: number;
|
|
14
|
+
|
|
13
15
|
protected [$childType]: string | typeof Schema;
|
|
14
16
|
|
|
15
17
|
protected $items: Map<number, V> = new Map<number, V>();
|
package/src/types/symbols.ts
CHANGED
package/src/utils.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Schema } from "./Schema";
|
|
2
2
|
import { OPERATION } from "./encoding/spec";
|
|
3
|
-
import { $changes } from "./types/symbols";
|
|
3
|
+
import { $changes, $refId } from "./types/symbols";
|
|
4
4
|
|
|
5
5
|
interface ChangeDump {
|
|
6
6
|
ops: {
|
|
@@ -37,7 +37,7 @@ export function dumpChanges(schema: Schema) {
|
|
|
37
37
|
|
|
38
38
|
const changes = changeTree.indexedOperations;
|
|
39
39
|
|
|
40
|
-
dump.refs.push(`refId#${changeTree.refId}`);
|
|
40
|
+
dump.refs.push(`refId#${changeTree.ref[$refId]}`);
|
|
41
41
|
for (const index in changes) {
|
|
42
42
|
const op = changes[index];
|
|
43
43
|
const opName = OPERATION[op];
|
package/lib/Decoder.d.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { TypeContext } from "./annotations";
|
|
2
|
-
import { DataChange, Schema } from "./Schema";
|
|
3
|
-
import { Ref } from "./changes/ChangeTree";
|
|
4
|
-
import { Iterator } from "./encoding/decode";
|
|
5
|
-
import { ReferenceTracker } from "./changes/ReferenceTracker";
|
|
6
|
-
export declare class Decoder<T extends Schema = any> {
|
|
7
|
-
context: TypeContext;
|
|
8
|
-
root: T;
|
|
9
|
-
refs: ReferenceTracker;
|
|
10
|
-
currentRefId: number;
|
|
11
|
-
constructor(root: T, context?: TypeContext);
|
|
12
|
-
protected setRoot(root: T): void;
|
|
13
|
-
decode(bytes: number[], it?: Iterator, ref?: Ref): DataChange<any, string>[];
|
|
14
|
-
getInstanceType(bytes: number[], it: Iterator, defaultType: typeof Schema): typeof Schema;
|
|
15
|
-
createInstanceOfType(type: typeof Schema): Schema;
|
|
16
|
-
}
|