@colyseus/schema 3.0.76 → 4.0.1
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 +47 -22
- 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";
|
|
@@ -9,13 +9,19 @@ import { OPERATION, SWITCH_TO_STRUCTURE, TYPE_ID } from '../encoding/spec';
|
|
|
9
9
|
import { Root } from "./Root";
|
|
10
10
|
|
|
11
11
|
import type { StateView } from "./StateView";
|
|
12
|
-
import type { Metadata } from "../Metadata";
|
|
13
12
|
import type { ChangeSetName, ChangeTree, ChangeTreeList, ChangeTreeNode } from "./ChangeTree";
|
|
14
13
|
import { createChangeTreeList } from "./ChangeTree";
|
|
15
14
|
|
|
15
|
+
function concatBytes(a: Uint8Array, b: Uint8Array): Uint8Array {
|
|
16
|
+
const result = new Uint8Array(a.length + b.length);
|
|
17
|
+
result.set(a, 0);
|
|
18
|
+
result.set(b, a.length);
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
|
|
16
22
|
export class Encoder<T extends Schema = any> {
|
|
17
|
-
static BUFFER_SIZE =
|
|
18
|
-
sharedBuffer =
|
|
23
|
+
static BUFFER_SIZE = 8 * 1024; // 8KB
|
|
24
|
+
sharedBuffer: Uint8Array = new Uint8Array(Encoder.BUFFER_SIZE);
|
|
19
25
|
|
|
20
26
|
context: TypeContext;
|
|
21
27
|
state: T;
|
|
@@ -48,11 +54,11 @@ export class Encoder<T extends Schema = any> {
|
|
|
48
54
|
encode(
|
|
49
55
|
it: Iterator = { offset: 0 },
|
|
50
56
|
view?: StateView,
|
|
51
|
-
buffer = this.sharedBuffer,
|
|
57
|
+
buffer: Uint8Array = this.sharedBuffer,
|
|
52
58
|
changeSetName: ChangeSetName = "changes",
|
|
53
59
|
isEncodeAll = changeSetName === "allChanges",
|
|
54
60
|
initialOffset = it.offset // cache current offset in case we need to resize the buffer
|
|
55
|
-
):
|
|
61
|
+
): Uint8Array {
|
|
56
62
|
const hasView = (view !== undefined);
|
|
57
63
|
const rootChangeTree = this.state[$changes];
|
|
58
64
|
|
|
@@ -63,7 +69,7 @@ export class Encoder<T extends Schema = any> {
|
|
|
63
69
|
|
|
64
70
|
if (hasView) {
|
|
65
71
|
if (!view.isChangeTreeVisible(changeTree)) {
|
|
66
|
-
// console.log("MARK AS INVISIBLE:", { ref: changeTree.ref.constructor.name, refId: changeTree.refId, raw: changeTree.ref.toJSON() });
|
|
72
|
+
// console.log("MARK AS INVISIBLE:", { ref: changeTree.ref.constructor.name, refId: changeTree.ref[$refId], raw: changeTree.ref.toJSON() });
|
|
67
73
|
view.invisible.add(changeTree);
|
|
68
74
|
continue; // skip this change tree
|
|
69
75
|
}
|
|
@@ -86,7 +92,7 @@ export class Encoder<T extends Schema = any> {
|
|
|
86
92
|
// (unless it "hasView", which will need to revisit the root)
|
|
87
93
|
if (hasView || it.offset > initialOffset || changeTree !== rootChangeTree) {
|
|
88
94
|
buffer[it.offset++] = SWITCH_TO_STRUCTURE & 255;
|
|
89
|
-
encode.number(buffer,
|
|
95
|
+
encode.number(buffer, ref[$refId], it);
|
|
90
96
|
}
|
|
91
97
|
|
|
92
98
|
for (let j = 0; j < numChanges; j++) {
|
|
@@ -121,10 +127,9 @@ export class Encoder<T extends Schema = any> {
|
|
|
121
127
|
}
|
|
122
128
|
|
|
123
129
|
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);
|
|
130
|
+
// we can assume that n + 1 BUFFER_SIZE will suffice given that we are likely done with encoding at this point
|
|
131
|
+
// multiples of BUFFER_SIZE are faster to allocate than arbitrary sizes
|
|
132
|
+
const newSize = Math.ceil(it.offset / Encoder.BUFFER_SIZE) * Encoder.BUFFER_SIZE;
|
|
128
133
|
|
|
129
134
|
console.warn(`@colyseus/schema buffer overflow. Encoded state is higher than default BUFFER_SIZE. Use the following to increase default BUFFER_SIZE:
|
|
130
135
|
|
|
@@ -136,7 +141,9 @@ export class Encoder<T extends Schema = any> {
|
|
|
136
141
|
// resize buffer and re-encode (TODO: can we avoid re-encoding here?)
|
|
137
142
|
// -> 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
143
|
//
|
|
139
|
-
|
|
144
|
+
const newBuffer = new Uint8Array(newSize);
|
|
145
|
+
newBuffer.set(buffer); // copy previous encoding steps beyond the initialOffset
|
|
146
|
+
buffer = newBuffer;
|
|
140
147
|
|
|
141
148
|
// assign resized buffer to local sharedBuffer
|
|
142
149
|
if (buffer === this.sharedBuffer) {
|
|
@@ -151,23 +158,36 @@ export class Encoder<T extends Schema = any> {
|
|
|
151
158
|
}
|
|
152
159
|
}
|
|
153
160
|
|
|
154
|
-
encodeAll(
|
|
161
|
+
encodeAll(
|
|
162
|
+
it: Iterator = { offset: 0 },
|
|
163
|
+
buffer: Uint8Array = this.sharedBuffer
|
|
164
|
+
) {
|
|
155
165
|
return this.encode(it, undefined, buffer, "allChanges", true);
|
|
156
166
|
}
|
|
157
167
|
|
|
158
|
-
encodeAllView(
|
|
168
|
+
encodeAllView(
|
|
169
|
+
view: StateView,
|
|
170
|
+
sharedOffset: number,
|
|
171
|
+
it: Iterator,
|
|
172
|
+
bytes: Uint8Array = this.sharedBuffer
|
|
173
|
+
) {
|
|
159
174
|
const viewOffset = it.offset;
|
|
160
175
|
|
|
161
176
|
// try to encode "filtered" changes
|
|
162
177
|
this.encode(it, view, bytes, "allFilteredChanges", true, viewOffset);
|
|
163
178
|
|
|
164
|
-
return
|
|
179
|
+
return concatBytes(
|
|
165
180
|
bytes.subarray(0, sharedOffset),
|
|
166
181
|
bytes.subarray(viewOffset, it.offset)
|
|
167
|
-
|
|
182
|
+
);
|
|
168
183
|
}
|
|
169
184
|
|
|
170
|
-
encodeView(
|
|
185
|
+
encodeView(
|
|
186
|
+
view: StateView,
|
|
187
|
+
sharedOffset: number,
|
|
188
|
+
it: Iterator,
|
|
189
|
+
bytes: Uint8Array = this.sharedBuffer
|
|
190
|
+
) {
|
|
171
191
|
const viewOffset = it.offset;
|
|
172
192
|
|
|
173
193
|
// encode visibility changes (add/remove for this view)
|
|
@@ -195,7 +215,7 @@ export class Encoder<T extends Schema = any> {
|
|
|
195
215
|
const metadata = ctor[Symbol.metadata];
|
|
196
216
|
|
|
197
217
|
bytes[it.offset++] = SWITCH_TO_STRUCTURE & 255;
|
|
198
|
-
encode.number(bytes,
|
|
218
|
+
encode.number(bytes, ref[$refId], it);
|
|
199
219
|
|
|
200
220
|
for (let i = 0, numChanges = keys.length; i < numChanges; i++) {
|
|
201
221
|
const index = Number(keys[i]);
|
|
@@ -219,10 +239,10 @@ export class Encoder<T extends Schema = any> {
|
|
|
219
239
|
// try to encode "filtered" changes
|
|
220
240
|
this.encode(it, view, bytes, "filteredChanges", false, viewOffset);
|
|
221
241
|
|
|
222
|
-
return
|
|
242
|
+
return concatBytes(
|
|
223
243
|
bytes.subarray(0, sharedOffset),
|
|
224
244
|
bytes.subarray(viewOffset, it.offset)
|
|
225
|
-
|
|
245
|
+
);
|
|
226
246
|
}
|
|
227
247
|
|
|
228
248
|
discardChanges() {
|
|
@@ -243,7 +263,12 @@ export class Encoder<T extends Schema = any> {
|
|
|
243
263
|
this.root.filteredChanges = createChangeTreeList();
|
|
244
264
|
}
|
|
245
265
|
|
|
246
|
-
tryEncodeTypeId
|
|
266
|
+
tryEncodeTypeId(
|
|
267
|
+
bytes: Uint8Array,
|
|
268
|
+
baseType: typeof Schema,
|
|
269
|
+
targetType: typeof Schema,
|
|
270
|
+
it: Iterator
|
|
271
|
+
) {
|
|
247
272
|
const baseTypeId = this.context.getTypeId(baseType);
|
|
248
273
|
const targetTypeId = this.context.getTypeId(targetType);
|
|
249
274
|
|
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
|
-
}
|