blob: 325f2c18c8966402c6ecd73198769139b58a2baa [file]
/*
* 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 { TypeId } from "../type";
import { Scope } from "./scope";
import { CodecBuilder } from "./builder";
import { TypeInfo } from "../typeInfo";
import { CodegenRegistry } from "./router";
import { BaseSerializerGenerator } from "./serializer";
import { TypeMeta } from "../meta/TypeMeta";
class ExtSerializerGenerator extends BaseSerializerGenerator {
typeInfo: TypeInfo;
typeMeta: TypeMeta;
serializerExpr: string;
ownTypeInfoExpr: string;
constructor(typeInfo: TypeInfo, builder: CodecBuilder, scope: Scope) {
super(typeInfo, builder, scope);
this.typeInfo = typeInfo;
this.typeMeta = TypeMeta.fromTypeInfo(this.typeInfo, this.builder.resolver);
this.serializerExpr = TypeId.isNamedType(typeInfo.typeId)
? `${this.builder.getTypeResolverName()}.getSerializerByName("${CodecBuilder.replaceBackslashAndQuote(typeInfo.named!)}")`
: `${this.builder.getTypeResolverName()}.getSerializerById(${typeInfo.typeId}, ${typeInfo.userTypeId})`;
this.ownTypeInfoExpr = `${this.serializerExpr}.getTypeInfo()`;
}
write(accessor: string): string {
return `
${this.builder.getOptions("customSerializer")}.write(${this.builder.getWriteContextName()}, ${accessor})
`;
}
read(accessor: (expr: string) => string, refState: string): string {
const result = this.scope.uniqueName("result");
return `
${this.typeInfo.options!.withConstructor
? `
const ${result} = new ${this.builder.getOptions("creator")}();
`
: `
const ${result} = {};
`
}
${this.maybeReference(result, refState)}
${this.builder.getOptions("customSerializer")}.read(${this.builder.getReadContextName()}, ${result})
${
accessor(result)
}
`;
}
readNoRef(assignStmt: (v: string) => string, refState: string): string {
const result = this.scope.uniqueName("result");
return `
${this.readTypeInfo()}
${this.builder.getReadContextName()}.incReadDepth();
let ${result};
${this.read(v => `${result} = ${v}`, refState)};
${this.builder.getReadContextName()}.decReadDepth();
${assignStmt(result)};
`;
}
readTypeInfo(): string {
const typeMeta = this.scope.uniqueName("typeMeta");
const internalTypeId = this.getInternalTypeId();
let namesStmt = "";
let typeMetaStmt = "";
let readUserTypeIdStmt = "";
switch (internalTypeId) {
case TypeId.EXT:
readUserTypeIdStmt = `${this.builder.reader.readVarUint32Small7()};`;
break;
case TypeId.NAMED_EXT:
if (!this.builder.resolver.isCompatible()) {
namesStmt = `
${
this.builder.metaStringResolver.readNamespace()
};
${
this.builder.metaStringResolver.readTypeName()
};
`;
} else {
typeMetaStmt = `
const ${typeMeta} = ${this.builder.typeMetaResolver.readTypeMeta()};
`;
}
break;
}
return `
${
this.builder.reader.readUint8()
};
${readUserTypeIdStmt}
${
namesStmt
}
${
typeMetaStmt
}
`;
}
readEmbed() {
return new Proxy({}, {
get: (target, prop: string) => {
return (accessor: (expr: string) => string, ...args: string[]) => {
const name = this.scope.declare(
"ext_ser",
TypeId.isNamedType(this.typeInfo.typeId)
? this.builder.typeResolver.getSerializerByName(CodecBuilder.replaceBackslashAndQuote(this.typeInfo.named!))
: this.builder.typeResolver.getSerializerById(this.typeInfo.typeId, this.typeInfo.userTypeId)
);
return accessor(`${name}.${prop}(${args.join(",")})`);
};
},
});
}
writeEmbed() {
return new Proxy({}, {
get: (target, prop: string) => {
return (accessor: string) => {
const name = this.scope.declare(
"ext_ser",
TypeId.isNamedType(this.typeInfo.typeId)
? this.builder.typeResolver.getSerializerByName(CodecBuilder.replaceBackslashAndQuote(this.typeInfo.named!))
: this.builder.typeResolver.getSerializerById(this.typeInfo.typeId, this.typeInfo.userTypeId)
);
return `${name}.${prop}(${accessor})`;
};
},
});
}
writeTypeInfo(): string {
const internalTypeId = this.getInternalTypeId();
let typeMeta = "";
let writeUserTypeIdStmt = "";
switch (internalTypeId) {
case TypeId.EXT:
writeUserTypeIdStmt = this.builder.writer.writeVarUint32Small7(this.typeInfo.userTypeId);
break;
case TypeId.NAMED_EXT:
if (!this.builder.resolver.isCompatible()) {
const typeInfo = this.typeInfo;
const nsBytes = this.scope.declare("nsBytes", this.builder.metaStringResolver.encodeNamespace(CodecBuilder.replaceBackslashAndQuote(typeInfo.namespace)));
const typeNameBytes = this.scope.declare("typeNameBytes", this.builder.metaStringResolver.encodeTypeName(CodecBuilder.replaceBackslashAndQuote(typeInfo.typeName)));
typeMeta = `
${this.builder.metaStringResolver.writeBytes(nsBytes)}
${this.builder.metaStringResolver.writeBytes(typeNameBytes)}
`;
} else {
const bytes = this.scope.declare("typeInfoBytes", `new Uint8Array([${TypeMeta.fromTypeInfo(this.typeInfo, this.builder.resolver).toBytes().join(",")}])`);
typeMeta = this.builder.typeMetaResolver.writeTypeMeta(this.builder.getTypeInfo(), bytes);
}
break;
default:
break;
}
return `
${this.builder.writer.writeUint8(this.getTypeId())};
${writeUserTypeIdStmt}
${typeMeta}
`;
}
getFixedSize(): number {
return 5;
}
getHash(): string {
return "0";
}
}
CodegenRegistry.register(TypeId.EXT, ExtSerializerGenerator);
CodegenRegistry.register(TypeId.NAMED_EXT, ExtSerializerGenerator);