| /* |
| * 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); |