blob: cc3900fb57cbaa6095c1eaafc92b3257b9e48264 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { Type, TypeDescription } from "../description";
import { CodecBuilder } from "./builder";
import { BaseSerializerGenerator } from "./serializer";
import { CodegenRegistry } from "./router";
import { InternalSerializerType, RefFlags, Serializer } from "../type";
import { Scope } from "./scope";
import Fury from "../fury";
import { Meta, getMeta } from "../meta";
import SerializerResolver from "../classResolver";
export class AnySerializer {
meta: Meta;
constructor(private fury: Fury) {
this.meta = getMeta(Type.any(), fury);
}
readInner() {
throw new Error("Anonymous serializer can't call directly");
}
writeInner() {
throw new Error("Anonymous serializer can't call directly");
}
detectSerializer() {
const typeId = this.fury.binaryReader.int16();
let serializer: Serializer;
if (typeId === SerializerResolver.getTypeIdByInternalSerializerType(InternalSerializerType.OBJECT)) {
const tag = this.fury.classResolver.readTag(this.fury.binaryReader)();
serializer = this.fury.classResolver.getSerializerByTag(tag);
} else {
serializer = this.fury.classResolver.getSerializerById(typeId);
}
if (!serializer) {
throw new Error(`cant find implements of typeId: ${typeId}`);
}
return serializer;
}
read() {
const flag = this.fury.referenceResolver.readRefFlag();
switch (flag) {
case RefFlags.RefValueFlag:
return this.detectSerializer().readInner(true);
case RefFlags.RefFlag:
return this.fury.referenceResolver.getReadObject(this.fury.binaryReader.varUInt32());
case RefFlags.NullFlag:
return null;
case RefFlags.NotNullValueFlag:
return this.detectSerializer().readInner(false);
}
}
write(v: any) {
if (v === null || v === undefined) {
this.fury.binaryWriter.reserve(1);
this.fury.binaryWriter.int8(RefFlags.NullFlag); // null
return;
}
const serializer = this.fury.classResolver.getSerializerByData(v);
if (!serializer) {
throw new Error(`Failed to detect the Fury serializer from JavaScript type: ${typeof v}`);
}
this.fury.binaryWriter.reserve(serializer.meta.fixedSize);
serializer.write(v);
}
}
class AnySerializerGenerator extends BaseSerializerGenerator {
description: TypeDescription;
constructor(description: TypeDescription, builder: CodecBuilder, scope: Scope) {
super(description, builder, scope);
this.description = description;
}
writeStmt(): string {
throw new Error("Type Any writeStmt can't inline");
}
readStmt(): string {
throw new Error("Type Any readStmt can't inline");
}
toReadEmbed(accessor: (expr: string) => string, excludeHead = false): string {
if (excludeHead) {
throw new Error("Anonymous can't excludeHead");
}
return accessor(`${this.builder.furyName()}.anySerializer.read()`);
}
toWriteEmbed(accessor: string, excludeHead = false): string {
if (excludeHead) {
throw new Error("Anonymous can't excludeHead");
}
return `${this.builder.furyName()}.anySerializer.write(${accessor})`;
}
toSerializer() {
this.scope.assertNameNotDuplicate("read");
this.scope.assertNameNotDuplicate("readInner");
this.scope.assertNameNotDuplicate("write");
this.scope.assertNameNotDuplicate("writeInner");
const declare = `
const readInner = (fromRef) => {
throw new Error("Type Any readInner can't call directly");
};
const read = () => {
${this.toReadEmbed(expr => `return ${expr}`)}
};
const writeInner = (v) => {
throw new Error("Type Any writeInner can't call directly");
};
const write = (v) => {
${this.toWriteEmbed("v")}
};
`;
return `
return function (fury, external) {
${this.scope.generate()}
${declare}
return {
read,
readInner,
write,
writeInner,
meta: ${JSON.stringify(this.builder.meta(this.description))}
};
}
`;
}
}
CodegenRegistry.register(InternalSerializerType.ANY, AnySerializerGenerator);
CodegenRegistry.registerExternal(AnySerializer);