typia 7.0.0-dev.20241019 → 7.0.0-dev.20241020

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.
@@ -9,11 +9,11 @@ import { StatementFactory } from "../../factories/StatementFactory";
9
9
  import { TypeFactory } from "../../factories/TypeFactory";
10
10
 
11
11
  import { Metadata } from "../../schemas/metadata/Metadata";
12
- import { MetadataArray } from "../../schemas/metadata/MetadataArray";
13
- import { MetadataAtomic } from "../../schemas/metadata/MetadataAtomic";
14
12
  import { MetadataMap } from "../../schemas/metadata/MetadataMap";
15
13
  import { MetadataObjectType } from "../../schemas/metadata/MetadataObjectType";
16
- import { MetadataProperty } from "../../schemas/metadata/MetadataProperty";
14
+ import { IProtobufProperty } from "../../schemas/protobuf/IProtobufProperty";
15
+ import { IProtobufPropertyType } from "../../schemas/protobuf/IProtobufPropertyType";
16
+ import { IProtobufSchema } from "../../schemas/protobuf/IProtobufSchema";
17
17
 
18
18
  import { IProgrammerProps } from "../../transformers/IProgrammerProps";
19
19
  import { ITypiaContext } from "../../transformers/ITypiaContext";
@@ -102,13 +102,7 @@ export namespace ProtobufEncodeProgrammer {
102
102
  [ts.factory.createIdentifier("sizer")],
103
103
  ),
104
104
  ),
105
- ts.factory.createReturnStatement(
106
- ts.factory.createCallExpression(
107
- IdentifierFactory.access(WRITER(), "buffer"),
108
- undefined,
109
- undefined,
110
- ),
111
- ),
105
+ ts.factory.createReturnStatement(callWriter("buffer")),
112
106
  ],
113
107
  true,
114
108
  ),
@@ -157,19 +151,6 @@ export namespace ProtobufEncodeProgrammer {
157
151
  }),
158
152
  }),
159
153
  );
160
- const main: ts.Block = decode({
161
- context: props.context,
162
- functor: props.functor,
163
- index: null,
164
- input: ts.factory.createIdentifier("input"),
165
- metadata: props.metadata,
166
- explore: {
167
- source: "top",
168
- from: "top",
169
- tracable: false,
170
- postfix: "",
171
- },
172
- });
173
154
  return ts.factory.createArrowFunction(
174
155
  undefined,
175
156
  [
@@ -196,7 +177,17 @@ export namespace ProtobufEncodeProgrammer {
196
177
  ...props.functor.declareUnions(),
197
178
  ...functors,
198
179
  ...IsProgrammer.write_function_statements(props),
199
- ...main.statements,
180
+ ts.factory.createExpressionStatement(
181
+ ts.factory.createCallExpression(
182
+ ts.factory.createIdentifier(
183
+ props.functor.useLocal(
184
+ `${PREFIX}o${props.metadata.objects[0]?.type.index ?? 0}`,
185
+ ),
186
+ ),
187
+ [],
188
+ [ts.factory.createIdentifier("input")],
189
+ ),
190
+ ),
200
191
  ts.factory.createReturnStatement(
201
192
  ts.factory.createIdentifier("writer"),
202
193
  ),
@@ -213,20 +204,20 @@ export namespace ProtobufEncodeProgrammer {
213
204
  object: MetadataObjectType;
214
205
  explore: FeatureProgrammer.IExplore;
215
206
  }): ts.ArrowFunction => {
216
- let index: number = 1;
217
207
  const body: ts.Statement[] = props.object.properties
218
208
  .map((p) => {
219
- const block = decode({
220
- ...props,
221
- index,
222
- input: IdentifierFactory.access(props.input, p.key.getSoleLiteral()!),
209
+ const block = decode_property({
210
+ context: props.context,
211
+ functor: props.functor,
212
+ explore: props.explore,
223
213
  metadata: p.value,
214
+ protobuf: p.of_protobuf_!,
215
+ input: IdentifierFactory.access(props.input, p.key.getSoleLiteral()!),
224
216
  });
225
- index += ProtobufUtil.size(p.value);
226
217
  return [
227
218
  ts.factory.createExpressionStatement(
228
219
  ts.factory.createIdentifier(
229
- `// property "${p.key.getSoleLiteral()!}"`,
220
+ `// property ${JSON.stringify(p.key.getSoleLiteral())}: ${p.value.getName()}`,
230
221
  ),
231
222
  ),
232
223
  ...block.statements,
@@ -244,16 +235,139 @@ export namespace ProtobufEncodeProgrammer {
244
235
  };
245
236
 
246
237
  /* -----------------------------------------------------------
247
- DECODERS
248
- ----------------------------------------------------------- */
249
- const decode = (props: {
238
+ DECODER STATION
239
+ ----------------------------------------------------------- */
240
+ const decode_property = (props: {
250
241
  context: ITypiaContext;
251
242
  functor: FunctionProgrammer;
252
- index: number | null;
253
- input: ts.Expression;
254
243
  metadata: Metadata;
244
+ protobuf: IProtobufProperty;
245
+ input: ts.Expression;
255
246
  explore: FeatureProgrammer.IExplore;
256
247
  }): ts.Block => {
248
+ const union: IUnion[] = [];
249
+ for (const schema of props.protobuf.union) {
250
+ //----
251
+ // ATOMICS
252
+ //----
253
+ if (schema.type === "bool")
254
+ union.push({
255
+ is: () =>
256
+ ts.factory.createStrictEquality(
257
+ ts.factory.createStringLiteral("boolean"),
258
+ ts.factory.createTypeOfExpression(props.input),
259
+ ),
260
+ value: () =>
261
+ decode_bool({
262
+ input: props.input,
263
+ index: schema.index,
264
+ }),
265
+ });
266
+ else if (schema.type === "bigint")
267
+ union.push(
268
+ decode_bigint({
269
+ input: props.input,
270
+ type: schema.name,
271
+ candidates: props.protobuf.union
272
+ .filter((s) => s.type === "bigint")
273
+ .map((s) => s.name),
274
+ index: schema.index,
275
+ }),
276
+ );
277
+ else if (schema.type === "number")
278
+ union.push(
279
+ decode_number({
280
+ input: props.input,
281
+ type: schema.name,
282
+ candidates: props.protobuf.union
283
+ .filter((s) => s.type === "number")
284
+ .map((s) => s.name),
285
+ index: schema.index,
286
+ }),
287
+ );
288
+ else if (schema.type === "string")
289
+ union.push({
290
+ is: () =>
291
+ ts.factory.createStrictEquality(
292
+ ts.factory.createStringLiteral("string"),
293
+ ts.factory.createTypeOfExpression(props.input),
294
+ ),
295
+ value: () =>
296
+ decode_bytes({
297
+ method: "string",
298
+ index: schema.index,
299
+ input: props.input,
300
+ }),
301
+ });
302
+ //----
303
+ // INSTANCES
304
+ //----
305
+ else if (schema.type === "bytes")
306
+ union.push({
307
+ is: () => ExpressionFactory.isInstanceOf("Uint8Array", props.input),
308
+ value: () =>
309
+ decode_bytes({
310
+ method: "bytes",
311
+ index: schema.index,
312
+ input: props.input,
313
+ }),
314
+ });
315
+ else if (schema.type === "array")
316
+ union.push({
317
+ is: () => ExpressionFactory.isArray(props.input),
318
+ value: () =>
319
+ decode_array({
320
+ context: props.context,
321
+ functor: props.functor,
322
+ input: props.input,
323
+ schema,
324
+ }),
325
+ });
326
+ else if (schema.type === "map" && schema.map instanceof MetadataMap) {
327
+ union.push({
328
+ is: () => ExpressionFactory.isInstanceOf("Map", props.input),
329
+ value: () =>
330
+ decode_map({
331
+ context: props.context,
332
+ functor: props.functor,
333
+ schema,
334
+ input: props.input,
335
+ }),
336
+ });
337
+ }
338
+ const objectSchemas: Array<
339
+ IProtobufPropertyType.IObject | IProtobufPropertyType.IMap
340
+ > = props.protobuf.union
341
+ .filter((schema) => schema.type === "object" || schema.type === "map")
342
+ .filter(
343
+ (schema) =>
344
+ schema.type === "object" ||
345
+ (schema.type === "map" && schema.map instanceof MetadataObjectType),
346
+ );
347
+ if (objectSchemas.length !== 0)
348
+ union.push({
349
+ is: () =>
350
+ ExpressionFactory.isObject({
351
+ checkNull: true,
352
+ checkArray: false,
353
+ input: props.input,
354
+ }),
355
+ value: () =>
356
+ explore_objects({
357
+ context: props.context,
358
+ functor: props.functor,
359
+ level: 0,
360
+ schemas: objectSchemas,
361
+ explore: {
362
+ ...props.explore,
363
+ from: "object",
364
+ },
365
+ input: props.input,
366
+ }),
367
+ });
368
+ }
369
+
370
+ // RETURNS
257
371
  const wrapper: (block: ts.Block) => ts.Block =
258
372
  props.metadata.isRequired() && props.metadata.nullable === false
259
373
  ? (block) => block
@@ -305,387 +419,42 @@ export namespace ProtobufEncodeProgrammer {
305
419
  ],
306
420
  true,
307
421
  );
308
-
309
- // STARTS FROM ATOMIC TYPES
310
- // @todo
311
- const unions: IUnion[] = [];
312
- const numbers = Array.from(ProtobufUtil.getNumbers(props.metadata).keys());
313
- const bigints = Array.from(ProtobufUtil.getBigints(props.metadata).keys());
314
-
315
- for (const [atom] of ProtobufUtil.getAtomics(props.metadata))
316
- if (atom === "bool")
317
- unions.push({
318
- type: "bool",
319
- is: () =>
320
- ts.factory.createStrictEquality(
321
- ts.factory.createStringLiteral("boolean"),
322
- ts.factory.createTypeOfExpression(props.input),
323
- ),
324
- value: (index) =>
325
- decode_bool({
326
- index,
327
- input: props.input,
328
- }),
329
- });
330
- else if (
331
- atom === "int32" ||
332
- atom === "uint32" ||
333
- atom === "float" ||
334
- atom === "double"
335
- )
336
- unions.push(
337
- decode_number({
338
- candidates: numbers as ProtobufAtomic.Numeric[],
339
- type: atom,
340
- input: props.input,
341
- }),
342
- );
343
- else if (atom === "int64" || atom === "uint64")
344
- if (numbers.some((n) => n === atom))
345
- unions.push(
346
- decode_number({
347
- candidates: numbers as ProtobufAtomic.Numeric[],
348
- type: atom,
349
- input: props.input,
350
- }),
351
- );
352
- else
353
- unions.push(
354
- decode_bigint({
355
- candidates: bigints as ProtobufAtomic.BigNumeric[],
356
- type: atom,
357
- input: props.input,
358
- }),
359
- );
360
- else if (atom === "string")
361
- unions.push({
362
- type: "string",
363
- is: () =>
364
- ts.factory.createStrictEquality(
365
- ts.factory.createStringLiteral("string"),
366
- ts.factory.createTypeOfExpression(props.input),
367
- ),
368
- value: (index) =>
369
- decode_bytes({
370
- method: "string",
371
- index: index!,
372
- input: props.input,
373
- }),
374
- });
375
-
376
- // CONSIDER BYTES
377
- if (props.metadata.natives.length)
378
- unions.push({
379
- type: "bytes",
380
- is: () => ExpressionFactory.isInstanceOf("Uint8Array", props.input),
381
- value: (index) =>
382
- decode_bytes({
383
- method: "bytes",
384
- index: index!,
385
- input: props.input,
386
- }),
387
- });
388
-
389
- // CONSIDER ARRAYS
390
- if (props.metadata.arrays.length)
391
- unions.push({
392
- type: "array",
393
- is: () => ExpressionFactory.isArray(props.input),
394
- value: (index) =>
395
- decode_array({
396
- ...props,
397
- array: props.metadata.arrays[0]!,
398
- explore: {
399
- ...props.explore,
400
- from: "array",
401
- },
402
- index: index!,
403
- }),
404
- });
405
-
406
- // CONSIDER MAPS
407
- if (props.metadata.maps.length)
408
- unions.push({
409
- type: "map",
410
- is: () => ExpressionFactory.isInstanceOf("Map", props.input),
411
- value: (index) =>
412
- decode_map({
413
- ...props,
414
- index: index!,
415
- entry: props.metadata.maps[0]!,
416
- explore: {
417
- ...props.explore,
418
- from: "array",
419
- },
420
- }),
421
- });
422
-
423
- // CONSIDER OBJECTS
424
- if (props.metadata.objects.length)
425
- unions.push({
426
- type: "object",
427
- is: () =>
428
- ExpressionFactory.isObject({
429
- checkNull: true,
430
- checkArray: false,
431
- input: props.input,
432
- }),
433
- value: (index) =>
434
- explore_objects({
435
- ...props,
436
- level: 0,
437
- index,
438
- objects: props.metadata.objects.map((o) => o.type),
439
- explore: {
440
- ...props.explore,
441
- from: "object",
442
- },
443
- }),
444
- });
445
-
446
- // RETURNS
447
- if (unions.length === 1) return wrapper(unions[0]!.value(props.index));
448
- else
449
- return wrapper(
450
- iterate({
451
- context: props.context,
452
- functor: props.functor,
453
- index: props.index,
454
- unions,
455
- expected: props.metadata.getName(),
456
- input: props.input,
457
- }),
458
- );
459
- };
460
-
461
- const iterate = (props: {
462
- context: ITypiaContext;
463
- functor: FunctionProgrammer;
464
- index: number | null;
465
- unions: IUnion[];
466
- expected: string;
467
- input: ts.Expression;
468
- }) =>
469
- ts.factory.createBlock(
470
- [
471
- props.unions
472
- .map((u, i) =>
473
- ts.factory.createIfStatement(
474
- u.is(),
475
- u.value(props.index ? props.index + i : null),
476
- i === props.unions.length - 1
477
- ? create_throw_error(props)
478
- : undefined,
479
- ),
480
- )
481
- .reverse()
482
- .reduce((a, b) =>
483
- ts.factory.createIfStatement(b.expression, b.thenStatement, a),
484
- ),
485
- ],
486
- true,
487
- );
488
-
489
- const decode_map = (props: {
490
- context: ITypiaContext;
491
- functor: FunctionProgrammer;
492
- index: number;
493
- input: ts.Expression;
494
- entry: MetadataMap | MetadataProperty;
495
- explore: FeatureProgrammer.IExplore;
496
- }): ts.Block => {
497
- const each: ts.Statement[] = [
498
- ts.factory.createExpressionStatement(
499
- decode_tag({
500
- wire: ProtobufWire.LEN,
501
- index: props.index,
502
- }),
503
- ),
504
- ts.factory.createExpressionStatement(
505
- ts.factory.createCallExpression(
506
- IdentifierFactory.access(WRITER(), "fork"),
507
- undefined,
508
- undefined,
509
- ),
510
- ),
511
- ...decode({
512
- ...props,
513
- index: 1,
514
- input: ts.factory.createIdentifier("key"),
515
- metadata: props.entry.key,
516
- }).statements,
517
- ...decode({
518
- ...props,
519
- index: 2,
520
- input: ts.factory.createIdentifier("value"),
521
- metadata: props.entry.value,
522
- }).statements,
523
- ts.factory.createExpressionStatement(
524
- ts.factory.createCallExpression(
525
- IdentifierFactory.access(WRITER(), "ldelim"),
526
- undefined,
527
- undefined,
528
- ),
529
- ),
530
- ];
531
- return ts.factory.createBlock(
532
- [
533
- ts.factory.createForOfStatement(
534
- undefined,
535
- StatementFactory.entry({
536
- key: "key",
537
- value: "value",
538
- }),
539
- props.input,
540
- ts.factory.createBlock(each),
541
- ),
542
- ],
543
- true,
544
- );
545
- };
546
-
547
- const decode_object = (props: {
548
- context: ITypiaContext;
549
- functor: FunctionProgrammer;
550
- index: number | null;
551
- input: ts.Expression;
552
- object: MetadataObjectType;
553
- explore: FeatureProgrammer.IExplore;
554
- }): ts.Block => {
555
- const top: MetadataProperty = props.object.properties[0]!;
556
- if (top.key.isSoleLiteral() === false)
557
- return decode_map({
558
- ...props,
559
- index: props.index!,
560
- input: ts.factory.createCallExpression(
561
- ts.factory.createIdentifier("Object.entries"),
562
- [],
563
- [props.input],
564
- ),
565
- entry: MetadataProperty.create({
566
- ...top,
567
- key: (() => {
568
- const key: Metadata = Metadata.initialize();
569
- key.atomics.push(
570
- MetadataAtomic.create({
571
- type: "string",
572
- tags: [],
573
- }),
574
- );
575
- return key;
576
- })(),
577
- }),
578
- });
579
- return ts.factory.createBlock(
580
- [
581
- ts.factory.createIdentifier(
582
- `//${props.index !== null ? ` ${props.index} -> ` : ""}${props.object.name}`,
583
- ),
584
- ...(props.index !== null
585
- ? [
586
- decode_tag({
587
- wire: ProtobufWire.LEN,
588
- index: props.index,
589
- }),
590
- ts.factory.createCallExpression(
591
- IdentifierFactory.access(WRITER(), "fork"),
592
- undefined,
593
- undefined,
594
- ),
595
- ]
596
- : []),
597
- ts.factory.createCallExpression(
598
- ts.factory.createIdentifier(
599
- props.functor.useLocal(`${PREFIX}o${props.object.index}`),
600
- ),
601
- [],
602
- [props.input],
603
- ),
604
- ...(props.index !== null
605
- ? [
606
- ts.factory.createCallExpression(
607
- IdentifierFactory.access(WRITER(), "ldelim"),
608
- undefined,
609
- undefined,
610
- ),
611
- ]
612
- : []),
613
- ].map((expr) => ts.factory.createExpressionStatement(expr)),
614
- true,
615
- );
616
- };
617
-
618
- const decode_array = (props: {
619
- context: ITypiaContext;
620
- functor: FunctionProgrammer;
621
- index: number;
622
- input: ts.Expression;
623
- array: MetadataArray;
624
- explore: FeatureProgrammer.IExplore;
625
- }): ts.Block => {
626
- const wire = get_standalone_wire(props.array.type.value);
627
- const forLoop = (index: number | null) =>
628
- ts.factory.createForOfStatement(
629
- undefined,
630
- ts.factory.createVariableDeclarationList(
631
- [ts.factory.createVariableDeclaration("elem")],
632
- ts.NodeFlags.Const,
633
- ),
634
- props.input,
635
- decode({
636
- ...props,
637
- input: ts.factory.createIdentifier("elem"),
638
- index,
639
- metadata: props.array.type.value,
640
- }),
641
- );
642
- const length = (block: ts.Block) =>
643
- ts.factory.createBlock(
644
- [
645
- ts.factory.createIfStatement(
646
- ts.factory.createStrictInequality(
647
- ExpressionFactory.number(0),
648
- IdentifierFactory.access(props.input, "length"),
649
- ),
650
- block,
651
- ),
652
- ],
653
- true,
654
- );
655
-
656
- if (wire === ProtobufWire.LEN)
657
- return length(ts.factory.createBlock([forLoop(props.index)], true));
658
- return length(
422
+ if (union.length === 1) return wrapper(union[0]!.value());
423
+ return wrapper(
659
424
  ts.factory.createBlock(
660
425
  [
661
- ts.factory.createExpressionStatement(
662
- decode_tag({
663
- wire: ProtobufWire.LEN,
664
- index: props.index,
665
- }),
666
- ),
667
- ts.factory.createExpressionStatement(
668
- ts.factory.createCallExpression(
669
- IdentifierFactory.access(WRITER(), "fork"),
670
- undefined,
671
- undefined,
672
- ),
673
- ),
674
- forLoop(null),
675
- ts.factory.createExpressionStatement(
676
- ts.factory.createCallExpression(
677
- IdentifierFactory.access(WRITER(), "ldelim"),
678
- undefined,
679
- undefined,
426
+ union
427
+ .map((u, i) =>
428
+ ts.factory.createIfStatement(
429
+ u.is(),
430
+ u.value(),
431
+ i === union.length - 1
432
+ ? create_throw_error({
433
+ context: props.context,
434
+ functor: props.functor,
435
+ input: props.input,
436
+ expected: props.metadata.getName(),
437
+ })
438
+ : undefined,
439
+ ),
440
+ )
441
+ .reverse()
442
+ .reduce((a, b) =>
443
+ ts.factory.createIfStatement(b.expression, b.thenStatement, a),
680
444
  ),
681
- ),
682
445
  ],
683
446
  true,
684
447
  ),
685
448
  );
686
449
  };
687
450
 
688
- const decode_bool = (props: { index: number | null; input: ts.Expression }) =>
451
+ /* -----------------------------------------------------------
452
+ ATOMIC DECODERS
453
+ ----------------------------------------------------------- */
454
+ const decode_bool = (props: {
455
+ input: ts.Expression;
456
+ index: number | null;
457
+ }): ts.Block =>
689
458
  ts.factory.createBlock(
690
459
  [
691
460
  ...(props.index !== null
@@ -696,95 +465,128 @@ export namespace ProtobufEncodeProgrammer {
696
465
  }),
697
466
  ]
698
467
  : []),
699
- ts.factory.createCallExpression(
700
- IdentifierFactory.access(WRITER(), "bool"),
701
- undefined,
702
- [props.input],
703
- ),
468
+ callWriter("bool", [props.input]),
704
469
  ].map((exp) => ts.factory.createExpressionStatement(exp)),
705
470
  true,
706
471
  );
707
472
 
708
- const decode_number = (props: {
709
- candidates: ProtobufAtomic.Numeric[];
710
- type: ProtobufAtomic.Numeric;
473
+ const decode_bigint = (props: {
474
+ candidates: ProtobufAtomic.BigNumeric[];
475
+ type: ProtobufAtomic.BigNumeric;
711
476
  input: ts.Expression;
477
+ index: number | null;
712
478
  }): IUnion => ({
713
- type: props.type,
714
479
  is: () =>
715
480
  props.candidates.length === 1
716
481
  ? ts.factory.createStrictEquality(
717
- ts.factory.createStringLiteral("number"),
482
+ ts.factory.createStringLiteral("bigint"),
718
483
  ts.factory.createTypeOfExpression(props.input),
719
484
  )
720
485
  : ts.factory.createLogicalAnd(
721
486
  ts.factory.createStrictEquality(
722
- ts.factory.createStringLiteral("number"),
487
+ ts.factory.createStringLiteral("bigint"),
723
488
  ts.factory.createTypeOfExpression(props.input),
724
489
  ),
725
- NumericRangeFactory.number(props.type, props.input),
490
+ NumericRangeFactory.bigint(props.type, props.input),
726
491
  ),
727
- value: (index) =>
492
+ value: () =>
728
493
  ts.factory.createBlock(
729
494
  [
730
- ...(index !== null
495
+ ...(props.index !== null
731
496
  ? [
732
497
  decode_tag({
733
- wire: get_numeric_wire(props.type),
734
- index,
498
+ wire: ProtobufWire.VARIANT,
499
+ index: props.index,
735
500
  }),
736
501
  ]
737
502
  : []),
738
- ts.factory.createCallExpression(
739
- IdentifierFactory.access(WRITER(), props.type),
740
- undefined,
741
- [props.input],
742
- ),
503
+ callWriter(props.type, [props.input]),
743
504
  ].map((exp) => ts.factory.createExpressionStatement(exp)),
744
505
  true,
745
506
  ),
746
507
  });
747
508
 
748
- const decode_bigint = (props: {
749
- candidates: ProtobufAtomic.BigNumeric[];
750
- type: ProtobufAtomic.BigNumeric;
509
+ const decode_number = (props: {
510
+ candidates: ProtobufAtomic.Numeric[];
511
+ type: ProtobufAtomic.Numeric;
751
512
  input: ts.Expression;
513
+ index: number | null;
752
514
  }): IUnion => ({
753
- type: props.type,
754
515
  is: () =>
755
516
  props.candidates.length === 1
756
517
  ? ts.factory.createStrictEquality(
757
- ts.factory.createStringLiteral("bigint"),
518
+ ts.factory.createStringLiteral("number"),
758
519
  ts.factory.createTypeOfExpression(props.input),
759
520
  )
760
521
  : ts.factory.createLogicalAnd(
761
522
  ts.factory.createStrictEquality(
762
- ts.factory.createStringLiteral("bigint"),
523
+ ts.factory.createStringLiteral("number"),
763
524
  ts.factory.createTypeOfExpression(props.input),
764
525
  ),
765
- NumericRangeFactory.bigint(props.type, props.input),
526
+ NumericRangeFactory.number(props.type, props.input),
766
527
  ),
767
- value: (index) =>
528
+ value: () =>
768
529
  ts.factory.createBlock(
769
530
  [
770
- ...(index !== null
531
+ ...(props.index !== null
771
532
  ? [
772
533
  decode_tag({
773
- wire: ProtobufWire.VARIANT,
774
- index,
534
+ wire: get_numeric_wire(props.type),
535
+ index: props.index,
775
536
  }),
776
537
  ]
777
538
  : []),
778
- ts.factory.createCallExpression(
779
- IdentifierFactory.access(WRITER(), props.type),
780
- undefined,
781
- [props.input],
782
- ),
539
+ callWriter(props.type, [props.input]),
783
540
  ].map((exp) => ts.factory.createExpressionStatement(exp)),
784
541
  true,
785
542
  ),
786
543
  });
787
544
 
545
+ const decode_container_value = (props: {
546
+ context: ITypiaContext;
547
+ functor: FunctionProgrammer;
548
+ schema: IProtobufPropertyType.IArray["value"];
549
+ index: number;
550
+ kind: "array" | "map";
551
+ input: ts.Expression;
552
+ }): ts.Block => {
553
+ if (props.schema.type === "bool")
554
+ return decode_bool({
555
+ input: props.input,
556
+ index: props.kind === "array" ? null : props.index,
557
+ });
558
+ else if (props.schema.type === "bigint")
559
+ return decode_bigint({
560
+ input: props.input,
561
+ type: props.schema.name,
562
+ candidates: [props.schema.name],
563
+ index: props.kind === "array" ? null : props.index,
564
+ }).value();
565
+ else if (props.schema.type === "number")
566
+ return decode_number({
567
+ input: props.input,
568
+ type: props.schema.name,
569
+ candidates: [props.schema.name],
570
+ index: props.kind === "array" ? null : props.index,
571
+ }).value();
572
+ else if (props.schema.type === "string" || props.schema.type === "bytes")
573
+ return decode_bytes({
574
+ method: props.schema.type,
575
+ input: props.input,
576
+ index: props.index,
577
+ });
578
+ return decode_object({
579
+ context: props.context,
580
+ functor: props.functor,
581
+ schema: props.schema,
582
+ input: props.input,
583
+ index: props.index,
584
+ });
585
+ };
586
+
587
+ /* -----------------------------------------------------------
588
+ INSTANCE DECODERS
589
+ ----------------------------------------------------------- */
788
590
  const decode_bytes = (props: {
789
591
  method: "bytes" | "string";
790
592
  index: number;
@@ -796,92 +598,199 @@ export namespace ProtobufEncodeProgrammer {
796
598
  wire: ProtobufWire.LEN,
797
599
  index: props.index,
798
600
  }),
799
- ts.factory.createCallExpression(
800
- IdentifierFactory.access(WRITER(), props.method),
801
- undefined,
802
- [props.input],
803
- ),
601
+ callWriter(props.method, [props.input]),
804
602
  ].map((expr) => ts.factory.createExpressionStatement(expr)),
805
603
  true,
806
604
  );
807
605
 
808
- const decode_tag = (props: {
809
- wire: ProtobufWire;
810
- index: number;
811
- }): ts.CallExpression =>
812
- ts.factory.createCallExpression(
813
- IdentifierFactory.access(WRITER(), "uint32"),
814
- undefined,
815
- [ExpressionFactory.number((props.index << 3) | props.wire)],
606
+ const decode_array = (props: {
607
+ context: ITypiaContext;
608
+ functor: FunctionProgrammer;
609
+ schema: IProtobufPropertyType.IArray;
610
+ input: ts.Expression;
611
+ }): ts.Block => {
612
+ const value: IProtobufPropertyType.IArray["value"] = props.schema.value;
613
+ const wire: ProtobufWire = (() => {
614
+ if (
615
+ value.type === "object" ||
616
+ value.type === "bytes" ||
617
+ value.type === "string"
618
+ )
619
+ return ProtobufWire.LEN;
620
+ else if (value.type === "number" && value.name === "float")
621
+ return ProtobufWire.I32;
622
+ return ProtobufWire.VARIANT;
623
+ })();
624
+ const forLoop = () =>
625
+ ts.factory.createForOfStatement(
626
+ undefined,
627
+ ts.factory.createVariableDeclarationList(
628
+ [ts.factory.createVariableDeclaration("elem")],
629
+ ts.NodeFlags.Const,
630
+ ),
631
+ props.input,
632
+ decode_container_value({
633
+ kind: "array",
634
+ context: props.context,
635
+ functor: props.functor,
636
+ input: ts.factory.createIdentifier("elem"),
637
+ index: props.schema.index,
638
+ schema: props.schema.value,
639
+ }),
640
+ );
641
+ const length = (block: ts.Block) =>
642
+ ts.factory.createBlock(
643
+ [
644
+ ts.factory.createIfStatement(
645
+ ts.factory.createStrictInequality(
646
+ ExpressionFactory.number(0),
647
+ IdentifierFactory.access(props.input, "length"),
648
+ ),
649
+ block,
650
+ ),
651
+ ],
652
+ true,
653
+ );
654
+ if (wire === ProtobufWire.LEN)
655
+ return length(ts.factory.createBlock([forLoop()], true));
656
+ return length(
657
+ ts.factory.createBlock(
658
+ [
659
+ ts.factory.createExpressionStatement(
660
+ decode_tag({
661
+ wire: ProtobufWire.LEN,
662
+ index: props.schema.index,
663
+ }),
664
+ ),
665
+ ts.factory.createExpressionStatement(callWriter("fork")),
666
+ forLoop(),
667
+ ts.factory.createExpressionStatement(callWriter("ldelim")),
668
+ ],
669
+ true,
670
+ ),
816
671
  );
672
+ };
817
673
 
818
- const get_standalone_wire = (metadata: Metadata): ProtobufWire => {
819
- if (
820
- metadata.arrays.length ||
821
- metadata.objects.length ||
822
- metadata.maps.length ||
823
- metadata.natives.length
824
- )
825
- return ProtobufWire.LEN;
674
+ const decode_object = (props: {
675
+ context: ITypiaContext;
676
+ functor: FunctionProgrammer;
677
+ schema: IProtobufSchema.IObject;
678
+ index: number;
679
+ input: ts.Expression;
680
+ }): ts.Block =>
681
+ ts.factory.createBlock(
682
+ [
683
+ decode_tag({
684
+ wire: ProtobufWire.LEN,
685
+ index: props.index,
686
+ }),
687
+ callWriter("fork"),
688
+ ts.factory.createCallExpression(
689
+ ts.factory.createIdentifier(
690
+ props.functor.useLocal(`${PREFIX}o${props.schema.object.index}`),
691
+ ),
692
+ [],
693
+ [props.input],
694
+ ),
695
+ callWriter("ldelim"),
696
+ ].map(ts.factory.createExpressionStatement),
697
+ true,
698
+ );
826
699
 
827
- // @todo
828
- const v = ProtobufUtil.getAtomics(metadata).keys().next().value!;
829
- if (v === "string") return ProtobufWire.LEN;
830
- else if (
831
- v === "bool" ||
832
- v === "int32" ||
833
- v === "uint32" ||
834
- v === "int64" ||
835
- v === "uint64"
836
- )
837
- return ProtobufWire.VARIANT;
838
- else if (v === "float") return ProtobufWire.I32;
839
- return ProtobufWire.I64;
700
+ const decode_map = (props: {
701
+ context: ITypiaContext;
702
+ functor: FunctionProgrammer;
703
+ schema: IProtobufPropertyType.IMap;
704
+ input: ts.Expression;
705
+ }): ts.Block => {
706
+ const each: ts.Statement[] = [
707
+ ts.factory.createExpressionStatement(
708
+ decode_tag({
709
+ wire: ProtobufWire.LEN,
710
+ index: props.schema.index,
711
+ }),
712
+ ),
713
+ ts.factory.createExpressionStatement(callWriter("fork")),
714
+ ...decode_container_value({
715
+ kind: "map",
716
+ context: props.context,
717
+ functor: props.functor,
718
+ index: 1,
719
+ input: ts.factory.createIdentifier("key"),
720
+ schema: props.schema.key,
721
+ }).statements,
722
+ ...decode_container_value({
723
+ kind: "map",
724
+ context: props.context,
725
+ functor: props.functor,
726
+ index: 2,
727
+ input: ts.factory.createIdentifier("value"),
728
+ schema: props.schema.value,
729
+ }).statements,
730
+ ts.factory.createExpressionStatement(callWriter("ldelim")),
731
+ ];
732
+ return ts.factory.createBlock(
733
+ [
734
+ ts.factory.createForOfStatement(
735
+ undefined,
736
+ StatementFactory.entry({
737
+ key: "key",
738
+ value: "value",
739
+ }),
740
+ props.input,
741
+ ts.factory.createBlock(each),
742
+ ),
743
+ ],
744
+ true,
745
+ );
840
746
  };
841
747
 
842
- const get_numeric_wire = (type: ProtobufAtomic.Numeric) =>
843
- type === "double"
844
- ? ProtobufWire.I64
845
- : type === "float"
846
- ? ProtobufWire.I32
847
- : ProtobufWire.VARIANT;
848
-
849
- /* -----------------------------------------------------------
850
- EXPLORERS
851
- ----------------------------------------------------------- */
852
748
  const explore_objects = (props: {
853
749
  context: ITypiaContext;
854
750
  functor: FunctionProgrammer;
855
751
  level: number;
856
- index: number | null;
857
752
  input: ts.Expression;
858
- objects: MetadataObjectType[];
753
+ schemas: Array<IProtobufPropertyType.IObject | IProtobufPropertyType.IMap>;
859
754
  explore: FeatureProgrammer.IExplore;
860
- indexes?: Map<MetadataObjectType, number>;
861
755
  }): ts.Block => {
862
- if (props.objects.length === 1)
863
- return decode_object({
864
- context: props.context,
865
- functor: props.functor,
866
- index: props.indexes
867
- ? props.indexes.get(props.objects[0]!)!
868
- : props.index,
869
- input: props.input,
870
- object: props.objects[0]!,
871
- explore: props.explore,
872
- });
873
-
874
- const expected: string = `(${props.objects.map((t) => t.name).join(" | ")})`;
756
+ const out = (
757
+ schema: IProtobufPropertyType.IObject | IProtobufPropertyType.IMap,
758
+ ) =>
759
+ schema.type === "object"
760
+ ? decode_object({
761
+ context: props.context,
762
+ functor: props.functor,
763
+ schema,
764
+ index: schema.index,
765
+ input: props.input,
766
+ })
767
+ : decode_map({
768
+ context: props.context,
769
+ functor: props.functor,
770
+ schema,
771
+ input: ts.factory.createCallExpression(
772
+ IdentifierFactory.access(
773
+ ts.factory.createIdentifier("Object"),
774
+ "entries",
775
+ ),
776
+ undefined,
777
+ [props.input],
778
+ ),
779
+ });
780
+ if (props.schemas.length === 1) return out(props.schemas[0]!);
875
781
 
876
- // POSSIBLE TO SPECIALIZE?
877
- const specList: UnionPredicator.ISpecialized[] = UnionPredicator.object(
878
- props.objects,
782
+ const objects: MetadataObjectType[] = props.schemas.map((s) =>
783
+ s.type === "map" ? (s.map as MetadataObjectType) : s.object,
879
784
  );
880
- const indexes: Map<MetadataObjectType, number> =
881
- props.indexes ??
882
- new Map(props.objects.map((t, i) => [t, props.index! + i]));
883
-
884
- if (specList.length === 0) {
785
+ const expected: string = `(${objects.map((t) => t.name).join(" | ")})`;
786
+ const indexes: WeakMap<
787
+ MetadataObjectType,
788
+ IProtobufPropertyType.IObject | IProtobufPropertyType.IMap
789
+ > = new WeakMap(objects.map((o, i) => [o, props.schemas[i]!]));
790
+ const specifications: UnionPredicator.ISpecialized[] =
791
+ UnionPredicator.object(objects);
792
+
793
+ if (specifications.length === 0) {
885
794
  const condition: ts.Expression = decode_union_object({
886
795
  checker: (v) =>
887
796
  IsProgrammer.decode_object({
@@ -891,17 +800,7 @@ export namespace ProtobufEncodeProgrammer {
891
800
  input: v.input,
892
801
  explore: v.explore,
893
802
  }),
894
- decoder: (v) =>
895
- ExpressionFactory.selfCall(
896
- decode_object({
897
- context: props.context,
898
- functor: props.functor,
899
- index: indexes.get(v.object)!,
900
- input: v.input,
901
- object: v.object,
902
- explore: v.explore,
903
- }),
904
- ),
803
+ decoder: (v) => ExpressionFactory.selfCall(out(indexes.get(v.object)!)),
905
804
  success: (expr) => expr,
906
805
  escaper: (v) =>
907
806
  create_throw_error({
@@ -911,17 +810,17 @@ export namespace ProtobufEncodeProgrammer {
911
810
  input: v.input,
912
811
  }),
913
812
  input: props.input,
914
- objects: props.objects,
915
813
  explore: props.explore,
814
+ objects,
916
815
  });
917
816
  return StatementFactory.block(condition);
918
817
  }
919
- const remained: MetadataObjectType[] = props.objects.filter(
920
- (t) => specList.find((s) => s.object === t) === undefined,
818
+ const remained: MetadataObjectType[] = objects.filter(
819
+ (o) => specifications.find((s) => s.object === o) === undefined,
921
820
  );
922
821
 
923
822
  // DO SPECIALIZE
924
- const condition: ts.IfStatement = specList
823
+ const condition: ts.IfStatement = specifications
925
824
  .filter((spec) => spec.property.key.getSoleLiteral() !== null)
926
825
  .map((spec, i, array) => {
927
826
  const key: string = spec.property.key.getSoleLiteral()!;
@@ -942,19 +841,11 @@ export namespace ProtobufEncodeProgrammer {
942
841
  },
943
842
  })
944
843
  : ExpressionFactory.isRequired(accessor);
844
+ const schema = indexes.get(spec.object)!;
945
845
  return ts.factory.createIfStatement(
946
846
  pred,
947
847
  ts.factory.createExpressionStatement(
948
- ExpressionFactory.selfCall(
949
- decode_object({
950
- context: props.context,
951
- functor: props.functor,
952
- index: indexes.get(spec.object)!,
953
- input: props.input,
954
- object: spec.object,
955
- explore: props.explore,
956
- }),
957
- ),
848
+ ExpressionFactory.selfCall(out(schema)),
958
849
  ),
959
850
  i === array.length - 1
960
851
  ? remained.length
@@ -964,11 +855,9 @@ export namespace ProtobufEncodeProgrammer {
964
855
  context: props.context,
965
856
  functor: props.functor,
966
857
  level: props.level + 1,
967
- index: props.index,
968
858
  input: props.input,
969
- objects: remained,
859
+ schemas: remained.map((r) => indexes.get(r)!),
970
860
  explore: props.explore,
971
- indexes,
972
861
  }),
973
862
  ),
974
863
  )
@@ -991,10 +880,25 @@ export namespace ProtobufEncodeProgrammer {
991
880
  };
992
881
 
993
882
  /* -----------------------------------------------------------
994
- CONFIGURATIONS
995
- ----------------------------------------------------------- */
883
+ BACKGROUND FUNCTIONS
884
+ ----------------------------------------------------------- */
996
885
  const PREFIX = "$pe";
997
886
 
887
+ const decode_tag = (props: {
888
+ wire: ProtobufWire;
889
+ index: number;
890
+ }): ts.CallExpression =>
891
+ callWriter("uint32", [
892
+ ExpressionFactory.number((props.index << 3) | props.wire),
893
+ ]);
894
+
895
+ const get_numeric_wire = (type: ProtobufAtomic.Numeric) =>
896
+ type === "double"
897
+ ? ProtobufWire.I64
898
+ : type === "float"
899
+ ? ProtobufWire.I32
900
+ : ProtobufWire.VARIANT;
901
+
998
902
  const create_throw_error = (props: {
999
903
  context: ITypiaContext;
1000
904
  functor: FunctionProgrammer;
@@ -1025,10 +929,17 @@ export namespace ProtobufEncodeProgrammer {
1025
929
  );
1026
930
  }
1027
931
 
1028
- const WRITER = () => ts.factory.createIdentifier("writer");
932
+ const callWriter = (
933
+ method: string,
934
+ args?: ts.Expression[],
935
+ ): ts.CallExpression =>
936
+ ts.factory.createCallExpression(
937
+ IdentifierFactory.access(ts.factory.createIdentifier("writer"), method),
938
+ undefined,
939
+ args,
940
+ );
1029
941
 
1030
942
  interface IUnion {
1031
- type: string;
1032
943
  is: () => ts.Expression;
1033
- value: (index: number | null) => ts.Block;
944
+ value: () => ts.Block;
1034
945
  }