This is an automated email from the ASF dual-hosted git repository.
wangweipeng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fory.git
The following commit(s) were added to refs/heads/main by this push:
new e13399532 feat(JavaScript): Impl xlang Map and Collection (#3249)
e13399532 is described below
commit e13399532c21a7413381f7a7fc53feaa7bd7f210
Author: weipeng <[email protected]>
AuthorDate: Sun Feb 1 00:57:38 2026 +0800
feat(JavaScript): Impl xlang Map and Collection (#3249)
---
javascript/packages/fory/lib/gen/any.ts | 2 +-
javascript/packages/fory/lib/gen/collection.ts | 214 ++++++++++-------
javascript/packages/fory/lib/gen/map.ts | 303 +++++++++++++------------
javascript/packages/fory/lib/meta/TypeMeta.ts | 2 +-
javascript/packages/fory/lib/type.ts | 2 +-
5 files changed, 298 insertions(+), 225 deletions(-)
diff --git a/javascript/packages/fory/lib/gen/any.ts
b/javascript/packages/fory/lib/gen/any.ts
index fb2163316..96da6d219 100644
--- a/javascript/packages/fory/lib/gen/any.ts
+++ b/javascript/packages/fory/lib/gen/any.ts
@@ -25,7 +25,7 @@ import { Mode, RefFlags, Serializer, TypeId } from "../type";
import { Scope } from "./scope";
import Fory from "../fory";
-class AnyHelper {
+export class AnyHelper {
static detectSerializer(fory: Fory) {
const typeId = fory.binaryReader.readVarUint32Small7();
let serializer: Serializer | undefined;
diff --git a/javascript/packages/fory/lib/gen/collection.ts
b/javascript/packages/fory/lib/gen/collection.ts
index c9741373a..34ddd828a 100644
--- a/javascript/packages/fory/lib/gen/collection.ts
+++ b/javascript/packages/fory/lib/gen/collection.ts
@@ -24,6 +24,7 @@ import { CodegenRegistry } from "./router";
import { TypeId, RefFlags, Serializer } from "../type";
import { Scope } from "./scope";
import Fory from "../fory";
+import { AnyHelper } from "./any";
export const CollectionFlags = {
/** Whether track elements ref. */
@@ -33,10 +34,10 @@ export const CollectionFlags = {
HAS_NULL: 0b10,
/** Whether collection elements type is not declare type. */
- NOT_DECL_ELEMENT_TYPE: 0b100,
+ DECL_ELEMENT_TYPE: 0b100,
/** Whether collection elements type different. */
- NOT_SAME_TYPE: 0b1000,
+ SAME_TYPE: 0b1000,
};
class CollectionAnySerializer {
@@ -49,13 +50,20 @@ class CollectionAnySerializer {
let isSame = true;
let serializer: Serializer | null | undefined = null;
let includeNone = false;
+ let trackingRef = false;
for (const item of arr) {
if ((item === undefined || item === null) && !includeNone) {
includeNone = true;
}
+ const current = this.fory.classResolver.getSerializerByData(item);
+ if (!current) {
+ throw new Error("can't detect the type of item in list");
+ }
+ if (!trackingRef) {
+ trackingRef = current.needToWriteRef();
+ }
if (isSame) {
- const current = this.fory.classResolver.getSerializerByData(item);
if (serializer !== null && serializer !== undefined && current !==
serializer) {
isSame = false;
} else {
@@ -64,74 +72,133 @@ class CollectionAnySerializer {
}
}
- if (!isSame) {
- flag |= CollectionFlags.NOT_SAME_TYPE;
+ if (isSame) {
+ flag |= CollectionFlags.SAME_TYPE;
}
if (includeNone) {
flag |= CollectionFlags.HAS_NULL;
}
- if (serializer && serializer!.needToWriteRef()) {
+ if (trackingRef) {
flag |= CollectionFlags.TRACKING_REF;
}
this.fory.binaryWriter.uint8(flag);
- if (isSame) {
- this.fory.binaryWriter.int16(serializer ? serializer!.getTypeId() : 0);
- }
return {
serializer,
isSame,
flag,
includeNone,
+ trackingRef,
};
}
write(value: any, size: number) {
- const { serializer, isSame, includeNone } =
this.writeElementsHeader(value);
- this.fory.binaryWriter.varUInt32(size);
- for (const item of value) {
- if (includeNone) {
- if (item === null || item === undefined) {
- this.fory.binaryWriter.uint8(RefFlags.NullFlag);
- continue;
- } else {
- this.fory.binaryWriter.uint8(RefFlags.NotNullValueFlag);
+ this.fory.binaryWriter.writeVarUint32Small7(size);
+ const { serializer, isSame, includeNone, trackingRef } =
this.writeElementsHeader(value);
+ if (isSame) {
+ serializer!.writeClassInfo(value);
+ if (trackingRef) {
+ for (const item of value) {
+ if (!serializer!.writeRefOrNull(item)) {
+ serializer!.write(item);
+ }
+ }
+ } else if (includeNone) {
+ for (const item of value) {
+ if (item === null || item === undefined) {
+ this.fory.binaryWriter.uint8(RefFlags.NullFlag);
+ } else {
+ this.fory.binaryWriter.uint8(RefFlags.NotNullValueFlag);
+ serializer!.write(item);
+ }
+ }
+ } else {
+ for (const item of value) {
+ serializer!.write(item);
}
}
- let finalSerializer = serializer;
- if (!isSame) {
- finalSerializer = this.fory.classResolver.getSerializerByData(item);
- this.fory.binaryWriter.uint16(finalSerializer!.getTypeId());
+ } else {
+ if (trackingRef) {
+ for (const item of value) {
+ const serializer = this.fory.classResolver.getSerializerByData(item);
+ serializer?.writeRef(item);
+ }
+ } else if (includeNone) {
+ for (const item of value) {
+ if (item === null || item === undefined) {
+ this.fory.binaryWriter.uint8(RefFlags.NullFlag);
+ } else {
+ const serializer =
this.fory.classResolver.getSerializerByData(item);
+ this.fory.binaryWriter.uint8(RefFlags.NotNullValueFlag);
+ serializer!.write(item);
+ }
+ }
+ } else {
+ for (const item of value) {
+ serializer!.write(item);
+ }
}
- finalSerializer!.write(item);
}
}
read(accessor: (result: any, index: number, v: any) => void,
createCollection: (len: number) => any, fromRef: boolean): any {
+ const len = this.fory.binaryReader.readVarUint32Small7();
const flags = this.fory.binaryReader.uint8();
- const isSame = !(flags & CollectionFlags.NOT_SAME_TYPE);
+ const isSame = flags & CollectionFlags.SAME_TYPE;
const includeNone = flags & CollectionFlags.HAS_NULL;
+ const refTracking = flags & CollectionFlags.TRACKING_REF;
+ const result = createCollection(len);
- let serializer: Serializer;
if (isSame) {
- serializer =
this.fory.classResolver.getSerializerById(this.fory.binaryReader.int16());
- }
- const len = this.fory.binaryReader.varUInt32();
- const result = createCollection(len);
- if (fromRef) {
- this.fory.referenceResolver.reference(result);
- }
- for (let index = 0; index < len; index++) {
- if (includeNone) {
- const refFlag = this.fory.binaryReader.uint8();
- if (RefFlags.NullFlag === refFlag) {
- accessor(result, index, null);
- continue;
+ const serializer = AnyHelper.detectSerializer(this.fory);
+ if (refTracking) {
+ for (let i = 0; i < len; i++) {
+ serializer.readRef();
+ const refFlag = this.fory.referenceResolver.readRefFlag();
+ if (refFlag === RefFlags.RefFlag) {
+ const refId = this.fory.binaryReader.varUInt32();
+ accessor(result, i,
this.fory.referenceResolver.getReadObject(refId));
+ } else if (refFlag === RefFlags.RefValueFlag) {
+ accessor(result, i, serializer!.read(true));
+ } else {
+ accessor(result, i, null);
+ }
+ }
+ } else if (includeNone) {
+ for (let i = 0; i < len; i++) {
+ const flag = this.fory.binaryReader.uint8();
+ if (flag === RefFlags.NullFlag) {
+ accessor(result, i, null);
+ } else {
+ accessor(result, i, serializer!.read(false));
+ }
+ }
+ } else {
+ for (let i = 0; i < len; i++) {
+ accessor(result, i, serializer!.read(false));
}
}
- if (!isSame) {
- serializer =
this.fory.classResolver.getSerializerById(this.fory.binaryReader.int16());
+ } else {
+ if (refTracking) {
+ for (let i = 0; i < len; i++) {
+ const itemSerializer = AnyHelper.detectSerializer(this.fory);
+ accessor(result, i, itemSerializer!.readRef());
+ }
+ } else if (includeNone) {
+ for (let i = 0; i < len; i++) {
+ const flag = this.fory.binaryReader.uint8();
+ if (flag === RefFlags.NullFlag) {
+ accessor(result, i, null);
+ } else {
+ const itemSerializer = AnyHelper.detectSerializer(this.fory);
+ accessor(result, i, itemSerializer!.read(false));
+ }
+ }
+ } else {
+ for (let i = 0; i < len; i++) {
+ const itemSerializer = AnyHelper.detectSerializer(this.fory);
+ accessor(result, i, itemSerializer!.read(false));
+ }
}
- accessor(result, index, serializer!.read(false));
}
return result;
}
@@ -164,9 +231,6 @@ export abstract class CollectionSerializerGenerator extends
BaseSerializerGenera
const item = this.scope.uniqueName("item");
const stmts = [
];
- if (this.innerGenerator.needToWriteRef()) {
- stmts.push(`${flagAccessor} |= ${CollectionFlags.TRACKING_REF}`);
- }
stmts.push(`
for (const ${item} of ${accessor}) {
if (${item} === null || ${item} === undefined) {
@@ -183,15 +247,13 @@ export abstract class CollectionSerializerGenerator
extends BaseSerializerGenera
const item = this.scope.uniqueName("item");
const flags = this.scope.uniqueName("flags");
const existsId = this.scope.uniqueName("existsId");
-
+ const flag = CollectionFlags.SAME_TYPE | CollectionFlags.DECL_ELEMENT_TYPE;
return `
- let ${flags} = 0;
+ let ${flags} = ${(this.innerGenerator.needToWriteRef() ?
CollectionFlags.TRACKING_REF : 0) | flag};
+
${this.builder.writer.writeVarUint32Small7(`${accessor}.${this.sizeProp()}`)}
${this.writeElementsHeader(accessor, flags)}
- ${this.builder.writer.int16(this.typeInfo.typeId)}
- ${this.builder.writer.varUInt32(`${accessor}.${this.sizeProp()}`)}
${this.builder.writer.reserve(`${this.innerGenerator.getFixedSize()} *
${accessor}.${this.sizeProp()}`)};
if (${flags} & ${CollectionFlags.TRACKING_REF}) {
-
for (const ${item} of ${accessor}) {
if (${accessor} !== null && ${accessor} !== undefined) {
const ${existsId} =
${this.builder.referenceResolver.existsWriteObject(item)};
@@ -207,40 +269,33 @@ export abstract class CollectionSerializerGenerator
extends BaseSerializerGenera
${this.builder.writer.int8(RefFlags.NullFlag)};
}
}
- } else {
- if (${flags} & ${CollectionFlags.HAS_NULL}) {
- for (const ${item} of ${accessor}) {
- if (${accessor} !== null && ${accessor} !== undefined)
{
-
${this.builder.writer.int8(RefFlags.NotNullValueFlag)};
- ${this.innerGenerator.writeEmbed().write(item)}
- } else {
- ${this.builder.writer.int8(RefFlags.NullFlag)};
- }
- }
- } else {
- for (const ${item} of ${accessor}) {
+ } else if (${flags} & ${CollectionFlags.HAS_NULL}) {
+ for (const ${item} of ${accessor}) {
+ if (${accessor} !== null && ${accessor} !== undefined) {
+ ${this.builder.writer.int8(RefFlags.NotNullValueFlag)};
${this.innerGenerator.writeEmbed().write(item)}
+ } else {
+ ${this.builder.writer.int8(RefFlags.NullFlag)};
}
}
+ } else {
+ for (const ${item} of ${accessor}) {
+ ${this.innerGenerator.writeEmbed().write(item)}
+ }
}
`;
}
- readStmtSpecificType(accessor: (expr: string) => string, refState: string):
string {
+ readSpecificType(accessor: (expr: string) => string, refState: string):
string {
const result = this.scope.uniqueName("result");
const len = this.scope.uniqueName("len");
const flags = this.scope.uniqueName("flags");
const idx = this.scope.uniqueName("idx");
const refFlag = this.scope.uniqueName("refFlag");
- // If track elements ref, use first bit 0b1 of header to flag it.
- // If collection has null, use second bit 0b10 of header to flag it. If
ref tracking is enabled for this element type, this flag is invalid.
- // If collection element types is not declared type, use 3rd bit 0b100 of
header to flag it.
- // If collection element types different, use 4th bit 0b1000 of header to
flag it.
return `
+ const ${len} = ${this.builder.reader.readVarUint32Small7()};
const ${flags} = ${this.builder.reader.uint8()};
- ${this.builder.reader.skip(2)};
- const ${len} = ${this.builder.reader.varUInt32()};
const ${result} = ${this.newCollection(len)};
${this.maybeReference(result, refState)}
if (${flags} & ${CollectionFlags.TRACKING_REF}) {
@@ -259,19 +314,18 @@ export abstract class CollectionSerializerGenerator
extends BaseSerializerGenera
break;
}
}
- } else {
- if (!(${flags} & ${CollectionFlags.HAS_NULL})) {
- for (let ${idx} = 0; ${idx} < ${len}; ${idx}++) {
+ } else if (${flags} & ${CollectionFlags.HAS_NULL}) {
+ for (let ${idx} = 0; ${idx} < ${len}; ${idx}++) {
+ if (${this.builder.reader.uint8()} ==
${RefFlags.NullFlag}) {
+ ${this.putAccessor(result, "null", idx)}
+ } else {
${this.innerGenerator.read(x =>
`${this.putAccessor(result, x, idx)}`, "false")}
}
- } else {
- for (let ${idx} = 0; ${idx} < ${len}; ${idx}++) {
- if (${this.builder.reader.uint8()} ==
${RefFlags.NullFlag}) {
- ${this.putAccessor(result, "null", idx)}
- } else {
- ${this.innerGenerator.read(x =>
`${this.putAccessor(result, x, idx)}`, "false")}
- }
- }
+ }
+
+ } else {
+ for (let ${idx} = 0; ${idx} < ${len}; ${idx}++) {
+ ${this.innerGenerator.read(x =>
`${this.putAccessor(result, x, idx)}`, "false")}
}
}
${accessor(result)}
@@ -294,7 +348,7 @@ export abstract class CollectionSerializerGenerator extends
BaseSerializerGenera
}, (len) => ${this.newCollection("len")}, ${refState});
`);
}
- return this.readStmtSpecificType(accessor, refState);
+ return this.readSpecificType(accessor, refState);
}
}
diff --git a/javascript/packages/fory/lib/gen/map.ts
b/javascript/packages/fory/lib/gen/map.ts
index ea9b5870c..8632b005e 100644
--- a/javascript/packages/fory/lib/gen/map.ts
+++ b/javascript/packages/fory/lib/gen/map.ts
@@ -24,6 +24,7 @@ import { CodegenRegistry } from "./router";
import { TypeId, RefFlags, Serializer } from "../type";
import { Scope } from "./scope";
import Fory from "../fory";
+import { AnyHelper } from "./any";
const MapFlags = {
/** Whether track elements ref. */
@@ -33,10 +34,7 @@ const MapFlags = {
HAS_NULL: 0b10,
/** Whether collection elements type is not declare type. */
- NOT_DECL_ELEMENT_TYPE: 0b100,
-
- /** Whether collection elements type different. */
- NOT_SAME_TYPE: 0b1000,
+ DECL_ELEMENT_TYPE: 0b100,
};
class MapHeadUtil {
@@ -63,25 +61,31 @@ class MapChunkWriter {
private chunkOffset = 0;
private header = 0;
- constructor(private fory: Fory) {
+ constructor(private fory: Fory, private keySerializer?: Serializer | null,
private valueSerializer?: Serializer | null) {
}
private getHead(keyInfo: number, valueInfo: number) {
let flag = 0;
- if (MapHeadUtil.isNull(keyInfo)) {
+ if (MapHeadUtil.isNull(valueInfo)) {
flag |= MapFlags.HAS_NULL;
}
- if (MapHeadUtil.trackingRef(keyInfo)) {
+ if (MapHeadUtil.trackingRef(valueInfo)) {
flag |= MapFlags.TRACKING_REF;
}
- flag <<= 4;
- if (MapHeadUtil.isNull(valueInfo)) {
+ if (this.valueSerializer) {
+ flag |= MapFlags.DECL_ELEMENT_TYPE;
+ }
+ flag <<= 3;
+ if (MapHeadUtil.isNull(keyInfo)) {
flag |= MapFlags.HAS_NULL;
}
- if (MapHeadUtil.trackingRef(valueInfo)) {
+ if (MapHeadUtil.trackingRef(keyInfo)) {
flag |= MapFlags.TRACKING_REF;
}
+ if (this.keySerializer) {
+ flag |= MapFlags.DECL_ELEMENT_TYPE;
+ }
return flag;
}
@@ -91,9 +95,13 @@ class MapChunkWriter {
// KV header
const header = this.getHead(keyInfo, valueInfo);
// chunkSize default 0 | KV header
- this.fory.binaryWriter.uint16(header << 8);
- // key TypeId | value TypeId
- this.fory.binaryWriter.uint32((keyInfo >> 16) | (valueInfo & 0xFFFF0000));
+ this.fory.binaryWriter.uint16(header);
+ if (this.keySerializer) {
+ this.keySerializer.writeClassInfo(null);
+ }
+ if (this.valueSerializer) {
+ this.valueSerializer.writeClassInfo(null);
+ }
return header;
}
@@ -117,7 +125,7 @@ class MapChunkWriter {
endChunk() {
if (this.chunkOffset > 0) {
- this.fory.binaryWriter.setUint8Position(this.chunkOffset,
this.chunkSize);
+ this.fory.binaryWriter.setUint8Position(this.chunkOffset + 1,
this.chunkSize);
this.chunkSize = 0;
}
}
@@ -136,30 +144,36 @@ class MapAnySerializer {
}
}
- private writeHead(header: number, v: any) {
- if (header !== 0) {
- if (header & MapFlags.HAS_NULL) {
- if (v === null || v === undefined) {
- this.fory.binaryWriter.uint8(RefFlags.NullFlag);
- }
+ private writeFlag(header: number, v: any) {
+ if (header & MapFlags.TRACKING_REF) {
+ if (v === null || v === undefined) {
+ this.fory.binaryWriter.uint8(RefFlags.NullFlag);
+ return true;
}
- if (header & MapFlags.TRACKING_REF) {
- const keyRef = this.fory.referenceResolver.existsWriteObject(v);
- if (keyRef !== undefined) {
- this.fory.binaryWriter.uint8(RefFlags.RefFlag);
- this.fory.binaryWriter.uint16(keyRef);
- } else {
- this.fory.binaryWriter.uint8(RefFlags.RefValueFlag);
- }
+ const keyRef = this.fory.referenceResolver.existsWriteObject(v);
+ if (keyRef !== undefined) {
+ this.fory.binaryWriter.uint8(RefFlags.RefFlag);
+ this.fory.binaryWriter.uint16(keyRef);
+ return true;
+ } else {
+ this.fory.binaryWriter.uint8(RefFlags.RefValueFlag);
+ return false;
+ }
+ } else if (header & MapFlags.HAS_NULL) {
+ if (v === null || v === undefined) {
+ this.fory.binaryWriter.uint8(RefFlags.NullFlag);
+ return true;
} else {
this.fory.binaryWriter.uint8(RefFlags.NotNullValueFlag);
+ return false;
}
}
+ return false;
}
write(value: Map<any, any>) {
- const mapChunkWriter = new MapChunkWriter(this.fory);
- this.fory.binaryWriter.varInt32(value.size);
+ const mapChunkWriter = new MapChunkWriter(this.fory, this.keySerializer,
this.valueSerializer);
+ this.fory.binaryWriter.writeVarUint32Small7(value.size);
for (const [k, v] of value.entries()) {
const keySerializer = this.keySerializer !== null ? this.keySerializer :
this.fory.classResolver.getSerializerByData(k);
const valueSerializer = this.valueSerializer !== null ?
this.valueSerializer : this.fory.classResolver.getSerializerByData(v);
@@ -168,30 +182,36 @@ class MapAnySerializer {
MapHeadUtil.elementInfo(keySerializer!.getTypeId()!, k == null ? 1 :
0, keySerializer!.needToWriteRef() ? 1 : 0),
MapHeadUtil.elementInfo(valueSerializer!.getTypeId()!, v == null ? 1 :
0, valueSerializer!.needToWriteRef() ? 1 : 0)
);
-
- this.writeHead(header >> 4, k);
- keySerializer!.write(k);
- this.writeHead(header & 0b00001111, v);
- valueSerializer!.write(v);
+ if (!this.writeFlag(header & 0b00001111, k)) {
+ if (this.keySerializer) {
+ keySerializer!.write(k);
+ } else {
+ keySerializer!.writeNoRef(k);
+ }
+ }
+ if (!this.writeFlag(header >> 4, v)) {
+ if (this.valueSerializer) {
+ valueSerializer!.write(v);
+ } else {
+ valueSerializer!.writeNoRef(v);
+ }
+ }
}
mapChunkWriter.endChunk();
}
private readElement(header: number, serializer: Serializer | null) {
- if (header === 0) {
- return serializer!.read(false);
- }
- const isSame = !(header & MapFlags.NOT_SAME_TYPE);
+ const declared = header & MapFlags.DECL_ELEMENT_TYPE;
const includeNone = header & MapFlags.HAS_NULL;
const trackingRef = header & MapFlags.TRACKING_REF;
- let flag = 0;
- if (trackingRef || includeNone) {
- flag = this.fory.binaryReader.uint8();
+ if (!declared) {
+ serializer = AnyHelper.detectSerializer(this.fory);
}
- if (!isSame) {
- serializer =
this.fory.classResolver.getSerializerById(this.fory.binaryReader.readVarUint32Small7());
+ if (!trackingRef && !includeNone) {
+ return serializer!.read(false);
}
+ const flag = this.fory.binaryReader.uint8();
switch (flag) {
case RefFlags.RefValueFlag:
return serializer!.read(true);
@@ -205,30 +225,32 @@ class MapAnySerializer {
}
read(fromRef: boolean): any {
- let count = this.fory.binaryReader.varInt32();
+ let count = this.fory.binaryReader.readVarUint32Small7();
const result = new Map();
if (fromRef) {
this.fory.referenceResolver.reference(result);
}
while (count > 0) {
const header = this.fory.binaryReader.uint16();
- const keyHeader = header >> 12;
- const valueHeader = (header >> 8) & 0b00001111;
- const chunkSize = header & 0b11111111;
+ const valueHeader = (header >> 3) & 0b111;
+ const keyHeader = header & 0b111;
+ const chunkSize = header >> 8;
let keySerializer = null;
let valueSerializer = null;
- if (!(keyHeader & MapFlags.NOT_SAME_TYPE)) {
- keySerializer =
this.fory.classResolver.getSerializerById(this.fory.binaryReader.uint16());
+ if (keyHeader & MapFlags.DECL_ELEMENT_TYPE) {
+ keySerializer = AnyHelper.detectSerializer(this.fory);
}
- if (!(valueHeader & MapFlags.NOT_SAME_TYPE)) {
- valueSerializer =
this.fory.classResolver.getSerializerById(this.fory.binaryReader.uint16());
+ if (valueHeader & MapFlags.DECL_ELEMENT_TYPE) {
+ valueSerializer = AnyHelper.detectSerializer(this.fory);
}
for (let index = 0; index < chunkSize; index++) {
+ const key = this.readElement(keyHeader, keySerializer);
+ const value = this.readElement(valueHeader, valueSerializer);
result.set(
- this.readElement(keyHeader, keySerializer),
- this.readElement(valueHeader, valueSerializer)
+ key,
+ value
);
count--;
}
@@ -256,9 +278,10 @@ export class MapSerializerGenerator extends
BaseSerializerGenerator {
private writeSpecificType(accessor: string) {
const k = this.scope.uniqueName("k");
const v = this.scope.uniqueName("v");
- const keyHeader = (this.keyGenerator.needToWriteRef() ?
MapFlags.TRACKING_REF : 0);
- const valueHeader = (this.valueGenerator.needToWriteRef() ?
MapFlags.TRACKING_REF : 0);
- const typeId = (this.keyGenerator.getTypeId()! << 8) |
(this.valueGenerator.getTypeId()!);
+ let keyHeader = (this.keyGenerator.needToWriteRef() ?
MapFlags.TRACKING_REF : 0);
+ keyHeader |= MapFlags.DECL_ELEMENT_TYPE;
+ let valueHeader = (this.valueGenerator.needToWriteRef() ?
MapFlags.TRACKING_REF : 0);
+ valueHeader |= MapFlags.DECL_ELEMENT_TYPE;
const lastKeyIsNull = this.scope.uniqueName("lastKeyIsNull");
const lastValueIsNull = this.scope.uniqueName("lastValueIsNull");
const chunkSize = this.scope.uniqueName("chunkSize");
@@ -267,7 +290,7 @@ export class MapSerializerGenerator extends
BaseSerializerGenerator {
const valueRef = this.scope.uniqueName("valueRef");
return `
- ${this.builder.writer.varInt32(`${accessor}.size`)}
+ ${this.builder.writer.writeVarUint32Small7(`${accessor}.size`)}
let ${lastKeyIsNull} = false;
let ${lastValueIsNull} = false;
let ${chunkSize} = 0;
@@ -276,61 +299,58 @@ export class MapSerializerGenerator extends
BaseSerializerGenerator {
for (const [${k}, ${v}] of ${accessor}.entries()) {
let keyIsNull = ${k} === null || ${k} === undefined;
let valueIsNull = ${v} === null || ${v} === undefined;
-
if (${lastKeyIsNull} !== keyIsNull || ${lastValueIsNull} !==
valueIsNull || ${chunkSize} === 0 || ${chunkSize} === 255) {
if (${chunkSize} > 0) {
- ${this.builder.writer.setUint8Position(chunkSizeOffset,
chunkSize)};
+ ${this.builder.writer.setUint8Position(`${chunkSizeOffset} + 1`,
chunkSize)};
${chunkSize} = 0;
}
${chunkSizeOffset} = ${this.builder.writer.getCursor()}
- ${
- this.builder.writer.uint16(
- `(((${keyHeader} | (keyIsNull ? ${MapFlags.HAS_NULL} : 0)) << 4)
| (${valueHeader} | (valueIsNull ? ${MapFlags.HAS_NULL} : 0))) << 8`
+ debugger;
+ ${this.builder.writer.uint16(
+ `((${valueHeader} | (valueIsNull ? ${MapFlags.HAS_NULL} : 0)) <<
3) | (${keyHeader} | (keyIsNull ? ${MapFlags.HAS_NULL} : 0))`
)
}
- ${this.builder.writer.uint32(typeId)};
-
${lastKeyIsNull} = keyIsNull;
${lastValueIsNull} = valueIsNull;
}
if (keyIsNull) {
${this.builder.writer.uint8(RefFlags.NullFlag)}
+ } else {
+ ${this.keyGenerator.needToWriteRef()
+ ? `
+ const ${keyRef} =
${this.builder.referenceResolver.existsWriteObject(v)};
+ if (${keyRef} !== undefined) {
+ ${this.builder.writer.uint8(RefFlags.RefFlag)};
+ ${this.builder.writer.uint16(keyRef)};
+ } else {
+ ${this.builder.writer.uint8(RefFlags.RefValueFlag)};
+ ${this.keyGenerator.writeEmbed().write(k)}
+ }
+ `
+ : this.keyGenerator.writeEmbed().write(k)}
}
- ${this.keyGenerator.needToWriteRef()
-? `
- const ${keyRef} =
${this.builder.referenceResolver.existsWriteObject(v)};
- if (${keyRef} !== undefined) {
- ${this.builder.writer.uint8(RefFlags.RefFlag)};
- ${this.builder.writer.uint16(keyRef)};
- } else {
- ${this.builder.writer.uint8(RefFlags.RefValueFlag)};
- ${this.keyGenerator.writeEmbed().write(k)}
- }
- `
-: this.keyGenerator.writeEmbed().write(k)}
-
if (valueIsNull) {
${this.builder.writer.uint8(RefFlags.NullFlag)}
+ } else {
+ ${this.valueGenerator.needToWriteRef()
+ ? `
+ const ${valueRef} =
${this.builder.referenceResolver.existsWriteObject(v)};
+ if (${valueRef} !== undefined) {
+ ${this.builder.writer.uint8(RefFlags.RefFlag)};
+ ${this.builder.writer.uint16(valueRef)};
+ } else {
+ ${this.builder.writer.uint8(RefFlags.RefValueFlag)};
+ ${this.valueGenerator.writeEmbed().write(v)};
+ }
+ `
+ : this.valueGenerator.writeEmbed().write(v)}
}
- ${this.valueGenerator.needToWriteRef()
-? `
- const ${valueRef} =
${this.builder.referenceResolver.existsWriteObject(v)};
- if (${valueRef} !== undefined) {
- ${this.builder.writer.uint8(RefFlags.RefFlag)};
- ${this.builder.writer.uint16(valueRef)};
- } else {
- ${this.builder.writer.uint8(RefFlags.RefValueFlag)};
- ${this.valueGenerator.writeEmbed().write(v)};
- }
- `
-: this.valueGenerator.writeEmbed().write(v)}
-
${chunkSize}++;
}
if (${chunkSize} > 0) {
- ${this.builder.writer.setUint8Position(chunkSizeOffset, chunkSize)};
+ ${this.builder.writer.setUint8Position(`${chunkSizeOffset} + 1`,
chunkSize)};
}
`;
}
@@ -340,73 +360,74 @@ export class MapSerializerGenerator extends
BaseSerializerGenerator {
if (!this.isAny()) {
return this.writeSpecificType(accessor);
}
- return `new (${anySerializer})(${this.builder.getForyName()}, ${
- this.typeInfo.options.key.typeId !== TypeId.UNKNOWN ?
this.typeInfo.options.key.typeId : null
- }, ${
- this.typeInfo.options.value.typeId !== TypeId.UNKNOWN ?
this.typeInfo.options.value.typeId : null
- }).write(${accessor})`;
+ return `new (${anySerializer})(${this.builder.getForyName()},
${this.typeInfo.options.key.typeId !== TypeId.UNKNOWN ?
this.typeInfo.options.key.typeId : null
+ }, ${this.typeInfo.options.value.typeId !== TypeId.UNKNOWN ?
this.typeInfo.options.value.typeId : null
+ }).write(${accessor})`;
}
- private readStmtSpecificType(accessor: (expr: string) => string, refState:
string) {
+ private readSpecificType(accessor: (expr: string) => string, refState:
string) {
const count = this.scope.uniqueName("count");
const result = this.scope.uniqueName("result");
return `
- let ${count} = ${this.builder.reader.varInt32()};
+ let ${count} = ${this.builder.reader.readVarUint32Small7()};
+ debugger;
const ${result} = new Map();
if (${refState}) {
${this.builder.referenceResolver.reference(result)}
}
while (${count} > 0) {
const header = ${this.builder.reader.uint16()};
- const keyHeader = header >> 12;
- const valueHeader = (header >> 8) & 0b00001111;
- const chunkSize = header & 0b11111111;
- ${this.builder.reader.skip(4)};
+ const keyHeader = header & 0b111;
+ const valueHeader = (header >> 3) & 0b111;
+ const chunkSize = header >> 8;
const keyIncludeNone = keyHeader & ${MapFlags.HAS_NULL};
const keyTrackingRef = keyHeader & ${MapFlags.TRACKING_REF};
const valueIncludeNone = valueHeader & ${MapFlags.HAS_NULL};
const valueTrackingRef = valueHeader & ${MapFlags.TRACKING_REF};
-
for (let index = 0; index < chunkSize; index++) {
let key;
let value;
- let flag = 0;
if (keyTrackingRef || keyIncludeNone) {
- flag = ${this.builder.reader.uint8()};
- }
- switch (flag) {
- case ${RefFlags.RefValueFlag}:
- ${this.keyGenerator.read(x => `key = ${x}`, "true")}
- break;
- case ${RefFlags.RefFlag}:
- key =
${this.builder.referenceResolver.getReadObject(this.builder.reader.varInt32())}
- break;
- case ${RefFlags.NullFlag}:
- key = null;
- break;
- case ${RefFlags.NotNullValueFlag}:
- ${this.keyGenerator.read(x => `key = ${x}`, "true")}
- break;
+ const flag = ${this.builder.reader.uint8()};
+ switch (flag) {
+ case ${RefFlags.RefValueFlag}:
+ ${this.keyGenerator.read(x => `key = ${x}`, "true")}
+ break;
+ case ${RefFlags.RefFlag}:
+ key =
${this.builder.referenceResolver.getReadObject(this.builder.reader.varInt32())}
+ break;
+ case ${RefFlags.NullFlag}:
+ key = null;
+ break;
+ case ${RefFlags.NotNullValueFlag}:
+ ${this.keyGenerator.read(x => `key = ${x}`, "false")}
+ break;
+ }
+ } else {
+ ${this.keyGenerator.read(x => `key = ${x}`, "false")}
}
- flag = 0;
+
if (valueTrackingRef || valueIncludeNone) {
- flag = ${this.builder.reader.uint8()};
- }
- switch (flag) {
- case ${RefFlags.RefValueFlag}:
- ${this.valueGenerator.read(x => `value = ${x}`, "true")}
- break;
- case ${RefFlags.RefFlag}:
- value =
${this.builder.referenceResolver.getReadObject(this.builder.reader.varInt32())}
- break;
- case ${RefFlags.NullFlag}:
- value = null;
- break;
- case ${RefFlags.NotNullValueFlag}:
- ${this.valueGenerator.read(x => `value = ${x}`, "false")}
- break;
+ const flag = ${this.builder.reader.uint8()};
+ switch (flag) {
+ case ${RefFlags.RefValueFlag}:
+ ${this.valueGenerator.read(x => `value = ${x}`, "true")}
+ break;
+ case ${RefFlags.RefFlag}:
+ value =
${this.builder.referenceResolver.getReadObject(this.builder.reader.varInt32())}
+ break;
+ case ${RefFlags.NullFlag}:
+ value = null;
+ break;
+ case ${RefFlags.NotNullValueFlag}:
+ ${this.valueGenerator.read(x => `value = ${x}`, "false")}
+ break;
+ }
+ } else {
+ ${this.valueGenerator.read(x => `value = ${x}`, "false")}
}
+
${result}.set(
key,
value
@@ -421,13 +442,11 @@ export class MapSerializerGenerator extends
BaseSerializerGenerator {
read(accessor: (expr: string) => string, refState: string): string {
const anySerializer = this.builder.getExternal(MapAnySerializer.name);
if (!this.isAny()) {
- return this.readStmtSpecificType(accessor, refState);
+ return this.readSpecificType(accessor, refState);
}
- return accessor(`new (${anySerializer})(${this.builder.getForyName()}, ${
- this.typeInfo.options.key.typeId !== TypeId.UNKNOWN ?
(this.typeInfo.options.key.typeId) : null
- }, ${
- this.typeInfo.options.value.typeId !== TypeId.UNKNOWN ?
(this.typeInfo.options.value.typeId) : null
- }).read(${refState})`);
+ return accessor(`new (${anySerializer})(${this.builder.getForyName()},
${this.typeInfo.options.key.typeId !== TypeId.UNKNOWN ?
(this.typeInfo.options.key.typeId) : null
+ }, ${this.typeInfo.options.value.typeId !== TypeId.UNKNOWN ?
(this.typeInfo.options.value.typeId) : null
+ }).read(${refState})`);
}
getFixedSize(): number {
diff --git a/javascript/packages/fory/lib/meta/TypeMeta.ts
b/javascript/packages/fory/lib/meta/TypeMeta.ts
index 111128e7d..89b8cd320 100644
--- a/javascript/packages/fory/lib/meta/TypeMeta.ts
+++ b/javascript/packages/fory/lib/meta/TypeMeta.ts
@@ -51,7 +51,7 @@ export const isPrimitiveTypeId = (typeId: number): boolean =>
{
};
export const refTrackingAbleTypeId = (typeId: number): boolean => {
- return PRIMITIVE_TYPE_IDS.includes(typeId as any) || [TypeId.DURATION,
TypeId.DATE, TypeId.TIMESTAMP].includes(typeId as any);
+ return PRIMITIVE_TYPE_IDS.includes(typeId as any) || [TypeId.DURATION,
TypeId.DATE, TypeId.TIMESTAMP, TypeId.STRING].includes(typeId as any);
};
export const isInternalTypeId = (typeId: number): boolean => {
diff --git a/javascript/packages/fory/lib/type.ts
b/javascript/packages/fory/lib/type.ts
index 0ab273661..8be2fd953 100644
--- a/javascript/packages/fory/lib/type.ts
+++ b/javascript/packages/fory/lib/type.ts
@@ -182,7 +182,7 @@ export type Serializer<T = any, T2 = any> = {
write: (v: T2) => void;
writeRef: (v: T2) => void;
writeNoRef: (v: T2) => void;
- writeRefOrNull: (v: T2) => void;
+ writeRefOrNull: (v: T2) => boolean;
writeClassInfo: (v: T2) => void;
read: (fromRef: boolean) => T2;
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]