@colyseus/schema 3.0.0-alpha.30 → 3.0.0-alpha.32

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.
Files changed (77) hide show
  1. package/build/cjs/index.js +389 -354
  2. package/build/cjs/index.js.map +1 -1
  3. package/build/esm/index.mjs +389 -354
  4. package/build/esm/index.mjs.map +1 -1
  5. package/build/umd/index.js +389 -354
  6. package/lib/Metadata.d.ts +14 -5
  7. package/lib/Metadata.js +49 -20
  8. package/lib/Metadata.js.map +1 -1
  9. package/lib/Reflection.js +4 -13
  10. package/lib/Reflection.js.map +1 -1
  11. package/lib/Schema.js +26 -39
  12. package/lib/Schema.js.map +1 -1
  13. package/lib/annotations.d.ts +1 -2
  14. package/lib/annotations.js +58 -52
  15. package/lib/annotations.js.map +1 -1
  16. package/lib/bench_encode.js +25 -22
  17. package/lib/bench_encode.js.map +1 -1
  18. package/lib/decoder/DecodeOperation.js +7 -9
  19. package/lib/decoder/DecodeOperation.js.map +1 -1
  20. package/lib/decoder/ReferenceTracker.js +3 -2
  21. package/lib/decoder/ReferenceTracker.js.map +1 -1
  22. package/lib/decoder/strategy/StateCallbacks.js +4 -3
  23. package/lib/decoder/strategy/StateCallbacks.js.map +1 -1
  24. package/lib/encoder/ChangeTree.d.ts +8 -7
  25. package/lib/encoder/ChangeTree.js +135 -117
  26. package/lib/encoder/ChangeTree.js.map +1 -1
  27. package/lib/encoder/EncodeOperation.d.ts +1 -4
  28. package/lib/encoder/EncodeOperation.js +17 -47
  29. package/lib/encoder/EncodeOperation.js.map +1 -1
  30. package/lib/encoder/Encoder.js +18 -6
  31. package/lib/encoder/Encoder.js.map +1 -1
  32. package/lib/encoder/Root.d.ts +2 -2
  33. package/lib/encoder/Root.js +18 -6
  34. package/lib/encoder/Root.js.map +1 -1
  35. package/lib/encoder/StateView.js +3 -3
  36. package/lib/encoder/StateView.js.map +1 -1
  37. package/lib/encoding/assert.d.ts +2 -1
  38. package/lib/encoding/assert.js +2 -2
  39. package/lib/encoding/assert.js.map +1 -1
  40. package/lib/index.d.ts +1 -2
  41. package/lib/index.js +11 -10
  42. package/lib/index.js.map +1 -1
  43. package/lib/types/TypeContext.js +7 -14
  44. package/lib/types/TypeContext.js.map +1 -1
  45. package/lib/types/custom/ArraySchema.js +6 -0
  46. package/lib/types/custom/ArraySchema.js.map +1 -1
  47. package/lib/types/custom/CollectionSchema.js +1 -0
  48. package/lib/types/custom/CollectionSchema.js.map +1 -1
  49. package/lib/types/custom/MapSchema.js +5 -0
  50. package/lib/types/custom/MapSchema.js.map +1 -1
  51. package/lib/types/custom/SetSchema.js +1 -0
  52. package/lib/types/custom/SetSchema.js.map +1 -1
  53. package/lib/types/symbols.d.ts +1 -0
  54. package/lib/types/symbols.js +2 -1
  55. package/lib/types/symbols.js.map +1 -1
  56. package/package.json +1 -1
  57. package/src/Metadata.ts +60 -29
  58. package/src/Reflection.ts +5 -15
  59. package/src/Schema.ts +33 -45
  60. package/src/annotations.ts +75 -67
  61. package/src/bench_encode.ts +29 -27
  62. package/src/decoder/DecodeOperation.ts +12 -11
  63. package/src/decoder/ReferenceTracker.ts +3 -2
  64. package/src/decoder/strategy/StateCallbacks.ts +4 -3
  65. package/src/encoder/ChangeTree.ts +154 -138
  66. package/src/encoder/EncodeOperation.ts +42 -62
  67. package/src/encoder/Encoder.ts +25 -8
  68. package/src/encoder/Root.ts +23 -6
  69. package/src/encoder/StateView.ts +4 -4
  70. package/src/encoding/assert.ts +4 -3
  71. package/src/index.ts +1 -4
  72. package/src/types/TypeContext.ts +10 -15
  73. package/src/types/custom/ArraySchema.ts +8 -0
  74. package/src/types/custom/CollectionSchema.ts +1 -0
  75. package/src/types/custom/MapSchema.ts +6 -0
  76. package/src/types/custom/SetSchema.ts +1 -0
  77. package/src/types/symbols.ts +2 -0
@@ -32,66 +32,80 @@ export class ChangeTree<T extends Ref=any> {
32
32
  refId: number;
33
33
 
34
34
  root?: Root;
35
-
36
- isFiltered?: boolean;
37
- isPartiallyFiltered?: boolean;
38
-
39
35
  parent?: Ref;
40
36
  parentIndex?: number;
41
37
 
42
- indexes: {[index: string]: any} = {}; // TODO: remove this, only used by MapSchema/SetSchema/CollectionSchema (`encodeKeyValueOperation`)
38
+ isFiltered: boolean = false;
39
+ isPartiallyFiltered: boolean = false;
40
+
43
41
  currentOperationIndex: number = 0;
44
42
 
43
+ changes = new Map<number, OPERATION>();
45
44
  allChanges = new Map<number, OPERATION>();
46
- allFilteredChanges = new Map<number, OPERATION>();
47
45
 
48
- changes = new Map<number, OPERATION>();
49
- filteredChanges = new Map<number, OPERATION>();;
46
+ allFilteredChanges: Map<number, OPERATION>;
47
+ filteredChanges: Map<number, OPERATION>;
48
+
49
+ indexes: {[index: string]: any}; // TODO: remove this, only used by MapSchema/SetSchema/CollectionSchema (`encodeKeyValueOperation`)
50
50
 
51
51
  [$isNew] = true;
52
52
 
53
53
  constructor(ref: T) {
54
54
  this.ref = ref;
55
+
56
+ //
57
+ // Does this structure have "filters" declared?
58
+ //
59
+ if (ref.constructor[Symbol.metadata]?.[-2]) {
60
+ this.allFilteredChanges = new Map<number, OPERATION>();
61
+ this.filteredChanges = new Map<number, OPERATION>();
62
+ }
55
63
  }
56
64
 
57
65
  setRoot(root: Root) {
58
66
  this.root = root;
59
67
  this.root.add(this);
60
68
 
61
- //
62
- // At Schema initialization, the "root" structure might not be available
63
- // yet, as it only does once the "Encoder" has been set up.
64
- //
65
- // So the "parent" may be already set without a "root".
66
- //
67
- this.checkIsFiltered(this.parent, this.parentIndex);
69
+ const metadata: Metadata = this.ref.constructor[Symbol.metadata];
68
70
 
69
- // unique refId for the ChangeTree.
70
- this.ensureRefId();
71
-
72
- if (!this.isFiltered) {
73
- this.root.changes.set(this, this.changes);
74
- }
71
+ if (this.root.types.hasFilters) {
72
+ //
73
+ // At Schema initialization, the "root" structure might not be available
74
+ // yet, as it only does once the "Encoder" has been set up.
75
+ //
76
+ // So the "parent" may be already set without a "root".
77
+ //
78
+ this.checkIsFiltered(metadata, this.parent, this.parentIndex);
75
79
 
76
- if (this.isFiltered || this.isPartiallyFiltered) {
77
- this.root.allFilteredChanges.set(this, this.allFilteredChanges);
78
- this.root.filteredChanges.set(this, this.filteredChanges);
80
+ if (this.isFiltered || this.isPartiallyFiltered) {
81
+ this.root.allFilteredChanges.set(this, this.allFilteredChanges);
82
+ this.root.filteredChanges.set(this, this.filteredChanges);
83
+ }
79
84
  }
80
85
 
81
86
  if (!this.isFiltered) {
87
+ this.root.changes.set(this, this.changes);
82
88
  this.root.allChanges.set(this, this.allChanges);
83
89
  }
84
90
 
85
- this.forEachChild((changeTree, _) => {
86
- changeTree.setRoot(root);
87
- });
91
+ this.ensureRefId();
92
+
93
+ if (metadata) {
94
+ metadata[-4]?.forEach((index) => {
95
+ const field = metadata[index as any as number];
96
+ const value = this.ref[field.name];
97
+ if (value) {
98
+ value[$changes].setRoot(root);
99
+ }
100
+ });
101
+
102
+ } else if (this.ref[$childType] && typeof(this.ref[$childType]) !== "string") {
103
+ // MapSchema / ArraySchema, etc.
104
+ (this.ref as MapSchema).forEach((value, key) => {
105
+ value[$changes].setRoot(root);
106
+ });
107
+ }
88
108
 
89
- // this.allChanges.forEach((_, index) => {
90
- // const childRef = this.ref[$getByIndex](index);
91
- // if (childRef && childRef[$changes]) {
92
- // childRef[$changes].setRoot(root);
93
- // }
94
- // });
95
109
  }
96
110
 
97
111
  setParent(
@@ -107,56 +121,71 @@ export class ChangeTree<T extends Ref=any> {
107
121
 
108
122
  root.add(this);
109
123
 
124
+ const metadata: Metadata = this.ref.constructor[Symbol.metadata];
125
+
110
126
  // skip if parent is already set
111
- if (root === this.root) {
112
- this.forEachChild((changeTree, atIndex) => {
113
- changeTree.setParent(this.ref, root, atIndex);
114
- });
115
- return;
116
- }
127
+ if (root !== this.root) {
128
+ this.root = root;
117
129
 
118
- this.root = root;
119
- this.checkIsFiltered(parent, parentIndex);
130
+ if (root.types.hasFilters) {
131
+ this.checkIsFiltered(metadata, parent, parentIndex);
120
132
 
121
- if (!this.isFiltered) {
122
- this.root.changes.set(this, this.changes);
123
- this.root.allChanges.set(this, this.allChanges);
124
- }
133
+ if (this.isFiltered || this.isPartiallyFiltered) {
134
+ this.root.filteredChanges.set(this, this.filteredChanges);
135
+ this.root.allFilteredChanges.set(this, this.filteredChanges);
136
+ }
137
+ }
125
138
 
126
- if (this.isFiltered || this.isPartiallyFiltered) {
127
- this.root.filteredChanges.set(this, this.filteredChanges);
128
- this.root.allFilteredChanges.set(this, this.filteredChanges);
139
+ if (!this.isFiltered) {
140
+ this.root.changes.set(this, this.changes);
141
+ this.root.allChanges.set(this, this.allChanges);
142
+ }
143
+
144
+ this.ensureRefId();
129
145
  }
130
146
 
131
- this.ensureRefId();
147
+ // assign same parent on child structures
148
+ if (metadata) {
149
+ metadata[-4]?.forEach((index) => {
150
+ const field = metadata[index as any as number];
151
+ const value = this.ref[field.name];
152
+ value?.[$changes].setParent(this.ref, root, index);
153
+
154
+ // console.log(this.ref.constructor.name, field.name, value);
155
+
156
+ // try { throw new Error(); } catch (e) {
157
+ // console.log(e.stack);
158
+ // }
159
+
160
+ });
161
+
162
+ } else if (this.ref[$childType] && typeof(this.ref[$childType]) !== "string") {
163
+ // MapSchema / ArraySchema, etc.
164
+ (this.ref as MapSchema).forEach((value, key) => {
165
+ value[$changes].setParent(this.ref, root, this.indexes[key] ?? key);
166
+ });
167
+ }
132
168
 
133
- this.forEachChild((changeTree, atIndex) => {
134
- changeTree.setParent(this.ref, root, atIndex);
135
- });
136
169
  }
137
170
 
138
171
  forEachChild(callback: (change: ChangeTree, atIndex: number) => void) {
139
172
  //
140
173
  // assign same parent on child structures
141
174
  //
142
- if (Metadata.isValidInstance(this.ref)) {
143
- const metadata: Metadata = this.ref['constructor'][Symbol.metadata];
144
-
145
- // FIXME: need to iterate over parent metadata instead.
146
- for (const field in metadata) {
147
- const value = this.ref[field];
148
-
149
- if (value && value[$changes]) {
150
- callback(value[$changes], metadata[field].index);
175
+ const metadata: Metadata = this.ref.constructor[Symbol.metadata];
176
+ if (metadata) {
177
+ metadata[-4]?.forEach((index) => {
178
+ const field = metadata[index as any as number];
179
+ const value = this.ref[field.name];
180
+ if (value) {
181
+ callback(value[$changes], index);
151
182
  }
152
- }
183
+ });
153
184
 
154
- } else if (typeof (this.ref) === "object") {
185
+ } else if (this.ref[$childType] && typeof(this.ref[$childType]) !== "string") {
155
186
  // MapSchema / ArraySchema, etc.
156
187
  (this.ref as MapSchema).forEach((value, key) => {
157
- if (Metadata.isValidInstance(value)) {
158
- callback(value[$changes], this.ref[$changes].indexes[key] ?? key);
159
- }
188
+ callback(value[$changes], this.indexes[key] ?? key);
160
189
  });
161
190
  }
162
191
  }
@@ -167,9 +196,9 @@ export class ChangeTree<T extends Ref=any> {
167
196
  }
168
197
 
169
198
  change(index: number, operation: OPERATION = OPERATION.ADD) {
170
- const metadata = this.ref['constructor'][Symbol.metadata] as Metadata;
199
+ const metadata = this.ref.constructor[Symbol.metadata] as Metadata;
171
200
 
172
- const isFiltered = this.isFiltered || (metadata && metadata[metadata[index]].tag !== undefined);
201
+ const isFiltered = this.isFiltered || (metadata?.[index]?.tag !== undefined);
173
202
  const changeSet = (isFiltered)
174
203
  ? this.filteredChanges
175
204
  : this.changes;
@@ -181,17 +210,15 @@ export class ChangeTree<T extends Ref=any> {
181
210
  : (previousOperation === OPERATION.DELETE)
182
211
  ? OPERATION.DELETE_AND_ADD
183
212
  : operation
213
+ //
214
+ // TODO: are DELETE operations being encoded as ADD here ??
215
+ //
184
216
  changeSet.set(index, op);
185
217
  }
186
218
 
187
- //
188
- // TODO: are DELETE operations being encoded as ADD here ??
189
- //
190
-
191
219
  if (isFiltered) {
192
- this.root?.filteredChanges.set(this, this.filteredChanges);
193
-
194
220
  this.allFilteredChanges.set(index, OPERATION.ADD);
221
+ this.root?.filteredChanges.set(this, this.filteredChanges);
195
222
  this.root?.allFilteredChanges.set(this, this.allFilteredChanges);
196
223
 
197
224
  } else {
@@ -244,10 +271,7 @@ export class ChangeTree<T extends Ref=any> {
244
271
  }
245
272
 
246
273
  indexedOperation(index: number, operation: OPERATION, allChangesIndex = index) {
247
- const metadata = this.ref['constructor'][Symbol.metadata] as Metadata;
248
- const isFiltered = this.isFiltered || (metadata && metadata[metadata[index]].tag !== undefined);
249
-
250
- if (isFiltered) {
274
+ if (this.filteredChanges !== undefined) {
251
275
  this.allFilteredChanges.set(allChangesIndex, OPERATION.ADD);
252
276
  this.filteredChanges.set(index, operation);
253
277
  this.root?.filteredChanges.set(this, this.filteredChanges);
@@ -261,8 +285,8 @@ export class ChangeTree<T extends Ref=any> {
261
285
 
262
286
  getType(index?: number) {
263
287
  if (Metadata.isValidInstance(this.ref)) {
264
- const metadata = this.ref['constructor'][Symbol.metadata] as Metadata;
265
- return metadata[metadata[index]].type;
288
+ const metadata = this.ref.constructor[Symbol.metadata] as Metadata;
289
+ return metadata[index].type;
266
290
 
267
291
  } else {
268
292
  //
@@ -277,7 +301,7 @@ export class ChangeTree<T extends Ref=any> {
277
301
 
278
302
  getChange(index: number) {
279
303
  // TODO: optimize this. avoid checking against multiple instances
280
- return this.changes.get(index) ?? this.filteredChanges.get(index);
304
+ return this.changes.get(index) ?? this.filteredChanges?.get(index);
281
305
  }
282
306
 
283
307
  //
@@ -300,9 +324,7 @@ export class ChangeTree<T extends Ref=any> {
300
324
  return;
301
325
  }
302
326
 
303
- const metadata = this.ref['constructor'][Symbol.metadata] as Metadata;
304
- const isFiltered = this.isFiltered || (metadata && metadata[metadata[index]].tag !== undefined);
305
- const changeSet = (isFiltered)
327
+ const changeSet = (this.filteredChanges)
306
328
  ? this.filteredChanges
307
329
  : this.changes;
308
330
 
@@ -312,8 +334,6 @@ export class ChangeTree<T extends Ref=any> {
312
334
 
313
335
  // remove `root` reference
314
336
  if (previousValue && previousValue[$changes]) {
315
- previousValue[$changes].root = undefined;
316
-
317
337
  //
318
338
  // FIXME: this.root is "undefined"
319
339
  //
@@ -324,13 +344,20 @@ export class ChangeTree<T extends Ref=any> {
324
344
  //
325
345
  // (the property descriptors should NOT be used at decoding time. only at encoding time.)
326
346
  //
327
- this.root?.remove(previousValue[$changes]);
347
+ const refCount = this.root?.remove(previousValue[$changes]);
348
+
349
+ //
350
+ // Only remove "root" reference if it's the last reference
351
+ //
352
+ if (refCount <= 0) {
353
+ previousValue[$changes].root = undefined;
354
+ }
328
355
  }
329
356
 
330
357
  //
331
358
  // FIXME: this is looking a bit ugly (and repeated from `.change()`)
332
359
  //
333
- if (isFiltered) {
360
+ if (this.filteredChanges) {
334
361
  this.root?.filteredChanges.set(this, this.filteredChanges);
335
362
  this.allFilteredChanges.delete(allChangesIndex);
336
363
 
@@ -342,6 +369,8 @@ export class ChangeTree<T extends Ref=any> {
342
369
 
343
370
  endEncode() {
344
371
  this.changes.clear();
372
+
373
+ // ArraySchema and MapSchema have a custom "encode end" method
345
374
  this.ref[$onEncodeEnd]?.();
346
375
 
347
376
  // Not a new instance anymore
@@ -357,14 +386,14 @@ export class ChangeTree<T extends Ref=any> {
357
386
  this.ref[$onEncodeEnd]?.();
358
387
 
359
388
  this.changes.clear();
360
- this.filteredChanges.clear();
389
+ this.filteredChanges?.clear();
361
390
 
362
391
  // reset operation index
363
392
  this.currentOperationIndex = 0;
364
393
 
365
394
  if (discardAll) {
366
395
  this.allChanges.clear();
367
- this.allFilteredChanges.clear();
396
+ this.allFilteredChanges?.clear();
368
397
 
369
398
  // remove children references
370
399
  this.forEachChild((changeTree, _) =>
@@ -400,60 +429,47 @@ export class ChangeTree<T extends Ref=any> {
400
429
  return this.changes.size > 0;
401
430
  }
402
431
 
403
- protected checkIsFiltered(parent: Ref, parentIndex: number) {
432
+ protected checkIsFiltered(metadata: Metadata, parent: Ref, parentIndex: number) {
404
433
  // Detect if current structure has "filters" declared
405
- this.isPartiallyFiltered = (this.ref['constructor']?.[Symbol.metadata]?.[-2] !== undefined);
434
+ this.isPartiallyFiltered = metadata?.[-2] !== undefined;
406
435
 
407
- if (parent && !Metadata.isValidInstance(parent)) {
408
- const parentChangeTree = parent[$changes];
409
- parent = parentChangeTree.parent;
410
- parentIndex = parentChangeTree.parentIndex;
436
+ if (this.isPartiallyFiltered) {
437
+ this.filteredChanges = this.filteredChanges || new Map<number, OPERATION>();
438
+ this.allFilteredChanges = this.allFilteredChanges || new Map<number, OPERATION>();
411
439
  }
412
440
 
413
- const parentMetadata = parent?.['constructor']?.[Symbol.metadata];
414
-
415
- this.isFiltered = (
416
- parent &&
417
- parentMetadata?.[-2]?.includes(parentIndex)
418
- );
419
-
420
- // this.isFiltered = this.ref['constructor']?.[Symbol.metadata]?.[-4];
421
-
422
- // // Detect if parent has "filters" declared
423
- // while (parent && !this.isFiltered) {
424
- // const metadata: Metadata = parent['constructor'][Symbol.metadata];
425
- // // this.isFiltered = metadata?.[-4];
426
-
427
- // const fieldName = metadata?.[parentIndex];
428
- // const isParentOwned = metadata?.[fieldName]?.tag !== undefined;
429
- // this.isFiltered = isParentOwned || parent[$changes].isFiltered; // metadata?.[-2]
430
-
431
- // parent = parent[$changes].parent;
432
- // };
441
+ if (parent) {
442
+ if (!Metadata.isValidInstance(parent)) {
443
+ const parentChangeTree = parent[$changes];
444
+ parent = parentChangeTree.parent;
445
+ parentIndex = parentChangeTree.parentIndex;
446
+ }
433
447
 
434
- // console.log("ChangeTree.checkIsFiltered", {
435
- // parent: parent?.constructor.name,
436
- // ref: this.ref.constructor.name,
437
- // isFiltered: this.isFiltered,
438
- // isPartiallyFiltered: this.isPartiallyFiltered,
439
- // });
448
+ const parentMetadata = parent?.constructor?.[Symbol.metadata];
449
+ this.isFiltered = (parent && parentMetadata?.[-2]?.includes(parentIndex));
440
450
 
441
- //
442
- // TODO: refactor this!
443
- //
444
- // swapping `changes` and `filteredChanges` is required here
445
- // because "isFiltered" may not be imedialely available on `change()`
446
- //
447
- if (this.isFiltered && this.changes.size > 0) {
448
- // swap changes reference
449
- const changes = this.changes;
450
- this.changes = this.filteredChanges;
451
- this.filteredChanges = changes;
452
-
453
- // swap "all changes" reference
454
- const allFilteredChanges = this.allFilteredChanges;
455
- this.allFilteredChanges = this.allChanges;
456
- this.allChanges = allFilteredChanges;
451
+ //
452
+ // TODO: refactor this!
453
+ //
454
+ // swapping `changes` and `filteredChanges` is required here
455
+ // because "isFiltered" may not be imedialely available on `change()`
456
+ //
457
+ if (this.isFiltered) {
458
+ this.filteredChanges = new Map<number, OPERATION>();
459
+ this.allFilteredChanges = new Map<number, OPERATION>();
460
+
461
+ if (this.changes.size > 0) {
462
+ // swap changes reference
463
+ const changes = this.changes;
464
+ this.changes = this.filteredChanges;
465
+ this.filteredChanges = changes;
466
+
467
+ // swap "all changes" reference
468
+ const allFilteredChanges = this.allFilteredChanges;
469
+ this.allFilteredChanges = this.allChanges;
470
+ this.allChanges = allFilteredChanges;
471
+ }
472
+ }
457
473
  }
458
474
  }
459
475
 
@@ -1,9 +1,9 @@
1
1
  import { OPERATION } from "../encoding/spec";
2
- import { $changes } from "../types/symbols";
2
+ import { $changes, $childType, $getByIndex } from "../types/symbols";
3
3
  import { getType } from "../types/registry";
4
4
 
5
5
  import * as encode from "../encoding/encode";
6
- import { EncodeSchemaError, assertInstanceType, assertType } from "../encoding/assert";
6
+ // import { EncodeSchemaError, assertInstanceType, assertType } from "../encoding/assert";
7
7
 
8
8
  import type { ChangeTree, Ref } from "./ChangeTree";
9
9
  import type { Encoder } from "./Encoder";
@@ -12,6 +12,7 @@ import type { PrimitiveType } from "../annotations";
12
12
 
13
13
  import type { Iterator } from "../encoding/decode";
14
14
  import type { ArraySchema } from "../types/custom/ArraySchema";
15
+ import type { Metadata } from "../Metadata";
15
16
 
16
17
  export type EncodeOperation<T extends Ref = any> = (
17
18
  encoder: Encoder,
@@ -24,41 +25,18 @@ export type EncodeOperation<T extends Ref = any> = (
24
25
  hasView: boolean,
25
26
  ) => void;
26
27
 
27
- export function encodePrimitiveType(
28
- type: PrimitiveType,
29
- bytes: Buffer,
30
- value: any,
31
- klass: Schema,
32
- field: string | number,
33
- it: Iterator,
34
- ) {
35
- assertType(value, type as string, klass, field);
36
-
37
- const encodeFunc = encode[type as string];
38
-
39
- if (encodeFunc) {
40
- encodeFunc(bytes, value, it);
41
- // encodeFunc(bytes, value);
42
-
43
- } else {
44
- throw new EncodeSchemaError(`a '${type}' was expected, but ${value} was provided in ${klass.constructor.name}#${field}`);
45
- }
46
- };
47
-
48
28
  export function encodeValue(
49
29
  encoder: Encoder,
50
30
  bytes: Buffer,
51
- ref: Ref,
52
31
  type: any,
53
32
  value: any,
54
- field: string | number,
55
33
  operation: OPERATION,
56
34
  it: Iterator,
57
35
  ) {
58
- if (type[Symbol.metadata] !== undefined) {
59
- // TODO: move this to the `@type()` annotation
60
- assertInstanceType(value, type as typeof Schema, ref as Schema, field);
36
+ if (typeof (type) === "string") {
37
+ encode[type]?.(bytes, value, it);
61
38
 
39
+ } else if (type[Symbol.metadata] !== undefined) {
62
40
  //
63
41
  // Encode refId for this instance.
64
42
  // The actual instance is going to be encoded on next `changeTree` iteration.
@@ -70,23 +48,7 @@ export function encodeValue(
70
48
  encoder.tryEncodeTypeId(bytes, type as typeof Schema, value.constructor as typeof Schema, it);
71
49
  }
72
50
 
73
- } else if (typeof (type) === "string") {
74
- //
75
- // Primitive values
76
- //
77
- encodePrimitiveType(type as PrimitiveType, bytes, value, ref as Schema, field, it);
78
-
79
51
  } else {
80
- //
81
- // Custom type (MapSchema, ArraySchema, etc)
82
- //
83
- const definition = getType(Object.keys(type)[0]);
84
-
85
- //
86
- // ensure a ArraySchema has been provided
87
- //
88
- assertInstanceType(ref[field], definition.constructor, ref as Schema, field);
89
-
90
52
  //
91
53
  // Encode refId for this instance.
92
54
  // The actual instance is going to be encoded on next `changeTree` iteration.
@@ -107,13 +69,6 @@ export const encodeSchemaOperation: EncodeOperation = function (
107
69
  operation: OPERATION,
108
70
  it: Iterator,
109
71
  ) {
110
- const ref = changeTree.ref;
111
- const metadata = ref['constructor'][Symbol.metadata];
112
-
113
- const field = metadata[index];
114
- const type = metadata[field].type;
115
- const value = ref[field];
116
-
117
72
  // "compress" field index + operation
118
73
  bytes[it.offset++] = (index | operation) & 255;
119
74
 
@@ -122,8 +77,19 @@ export const encodeSchemaOperation: EncodeOperation = function (
122
77
  return;
123
78
  }
124
79
 
80
+ const ref = changeTree.ref;
81
+ const metadata: Metadata = ref.constructor[Symbol.metadata];
82
+ const field = metadata[index];
83
+
125
84
  // TODO: inline this function call small performance gain
126
- encodeValue(encoder, bytes, ref, type, value, field, operation, it);
85
+ encodeValue(
86
+ encoder,
87
+ bytes,
88
+ metadata[index].type,
89
+ ref[field.name],
90
+ operation,
91
+ it
92
+ );
127
93
  }
128
94
 
129
95
  /**
@@ -134,12 +100,10 @@ export const encodeKeyValueOperation: EncodeOperation = function (
134
100
  encoder: Encoder,
135
101
  bytes: Buffer,
136
102
  changeTree: ChangeTree,
137
- field: number,
103
+ index: number,
138
104
  operation: OPERATION,
139
105
  it: Iterator,
140
106
  ) {
141
- const ref = changeTree.ref;
142
-
143
107
  // encode operation
144
108
  bytes[it.offset++] = operation & 255;
145
109
 
@@ -149,28 +113,30 @@ export const encodeKeyValueOperation: EncodeOperation = function (
149
113
  }
150
114
 
151
115
  // encode index
152
- encode.number(bytes, field, it);
116
+ encode.number(bytes, index, it);
153
117
 
154
118
  // Do not encode value for DELETE operations
155
119
  if (operation === OPERATION.DELETE) {
156
120
  return;
157
121
  }
158
122
 
123
+ const ref = changeTree.ref;
124
+
159
125
  //
160
126
  // encode "alias" for dynamic fields (maps)
161
127
  //
162
- if ((operation & OPERATION.ADD) == OPERATION.ADD) { // ADD or DELETE_AND_ADD
128
+ if ((operation & OPERATION.ADD) === OPERATION.ADD) { // ADD or DELETE_AND_ADD
163
129
  if (typeof(ref['set']) === "function") {
164
130
  //
165
131
  // MapSchema dynamic key
166
132
  //
167
- const dynamicIndex = changeTree.ref['$indexes'].get(field);
133
+ const dynamicIndex = changeTree.ref['$indexes'].get(index);
168
134
  encode.string(bytes, dynamicIndex, it);
169
135
  }
170
136
  }
171
137
 
172
- const type = changeTree.getType(field);
173
- const value = changeTree.getValue(field);
138
+ const type = ref[$childType];
139
+ const value = ref[$getByIndex](index);
174
140
 
175
141
  // try { throw new Error(); } catch (e) {
176
142
  // // only print if not coming from Reflection.ts
@@ -186,7 +152,14 @@ export const encodeKeyValueOperation: EncodeOperation = function (
186
152
  // }
187
153
 
188
154
  // TODO: inline this function call small performance gain
189
- encodeValue(encoder, bytes, ref, type, value, field, operation, it);
155
+ encodeValue(
156
+ encoder,
157
+ bytes,
158
+ type,
159
+ value,
160
+ operation,
161
+ it
162
+ );
190
163
  }
191
164
 
192
165
  /**
@@ -250,5 +223,12 @@ export const encodeArray: EncodeOperation = function (
250
223
  // });
251
224
 
252
225
  // TODO: inline this function call small performance gain
253
- encodeValue(encoder, bytes, ref, type, value, field, operation, it);
226
+ encodeValue(
227
+ encoder,
228
+ bytes,
229
+ type,
230
+ value,
231
+ operation,
232
+ it
233
+ );
254
234
  }