blob: 2889ecc39b5f58ff4d73553a45f8c3ec6a07611e [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 ClassResolver from "./classResolver";
import { BinaryWriter } from "./writer";
import { BinaryReader } from "./reader";
import { ReferenceResolver } from "./referenceResolver";
import { ConfigFlags, Serializer, Config, Language } from "./type";
import { OwnershipError } from "./error";
import { InputType, ResultType, TypeDescription } from "./description";
import { generateSerializer, AnySerializer } from "./gen";
export default class {
binaryReader: BinaryReader;
binaryWriter: BinaryWriter;
classResolver = new ClassResolver();
referenceResolver: ReferenceResolver;
anySerializer: AnySerializer;
constructor(public config: Config = {
refTracking: false,
useSliceString: false,
hooks: {
},
}) {
this.binaryReader = new BinaryReader(config);
this.binaryWriter = new BinaryWriter(config);
this.referenceResolver = new ReferenceResolver(this.binaryReader);
this.classResolver.init(this);
this.anySerializer = new AnySerializer(this);
}
registerSerializer<T extends TypeDescription>(description: T) {
const serializer = generateSerializer(this, description);
return {
serializer,
serialize: (data: InputType<T>) => {
return this.serialize(data, serializer);
},
serializeVolatile: (data: InputType<T>) => {
return this.serializeVolatile(data, serializer);
},
deserialize: (bytes: Uint8Array) => {
return this.deserialize(bytes, serializer) as ResultType<T>;
},
};
}
deserialize<T = any>(bytes: Uint8Array, serializer: Serializer = this.anySerializer): T | null {
this.referenceResolver.reset();
this.classResolver.reset();
this.binaryReader.reset(bytes);
const bitmap = this.binaryReader.uint8();
if ((bitmap & ConfigFlags.isNullFlag) === ConfigFlags.isNullFlag) {
return null;
}
const isLittleEndian = (bitmap & ConfigFlags.isLittleEndianFlag) === ConfigFlags.isLittleEndianFlag;
if (!isLittleEndian) {
throw new Error("big endian is not supported now");
}
const isCrossLanguage = (bitmap & ConfigFlags.isCrossLanguageFlag) == ConfigFlags.isCrossLanguageFlag;
if (!isCrossLanguage) {
throw new Error("support crosslanguage mode only");
}
const isOutOfBandEnabled = (bitmap & ConfigFlags.isOutOfBandFlag) === ConfigFlags.isOutOfBandFlag;
if (isOutOfBandEnabled) {
throw new Error("outofband mode is not supported now");
}
this.binaryReader.uint8(); // skip language
this.binaryReader.int32(); // native object offset. should skip. javascript support cross mode only
this.binaryReader.int32(); // native object size. should skip.
return serializer.read();
}
private serializeInternal<T = any>(data: T, serializer: Serializer) {
try {
this.binaryWriter.reset();
} catch (e) {
if (e instanceof OwnershipError) {
throw new Error("Permission denied. To release the serialization ownership, you must call the dispose function returned by serializeVolatile.");
}
throw e;
}
this.referenceResolver.reset();
this.classResolver.reset();
let bitmap = 0;
if (data === null) {
bitmap |= ConfigFlags.isNullFlag;
}
bitmap |= ConfigFlags.isLittleEndianFlag;
bitmap |= ConfigFlags.isCrossLanguageFlag;
this.binaryWriter.uint8(bitmap);
this.binaryWriter.uint8(Language.XLANG);
const cursor = this.binaryWriter.getCursor();
this.binaryWriter.skip(4); // preserve 4-byte for nativeObjects start offsets.
this.binaryWriter.uint32(0); // nativeObjects length.
// reserve fixed size
this.binaryWriter.reserve(serializer.meta.fixedSize);
// start write
serializer.write(data);
this.binaryWriter.setUint32Position(cursor, this.binaryWriter.getCursor()); // nativeObjects start offsets;
return this.binaryWriter;
}
serialize<T = any>(data: T, serializer: Serializer = this.anySerializer) {
return this.serializeInternal(data, serializer).dump();
}
serializeVolatile<T = any>(data: T, serializer: Serializer = this.anySerializer) {
return this.serializeInternal(data, serializer).dumpAndOwn();
}
}