packstream-v1.js•20.8 kB
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Unpacker = exports.Packer = void 0;
/**
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [https://neo4j.com]
*
* Licensed 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.
*/
var channel_1 = require("../channel");
var lang_1 = require("../lang");
var structure_1 = require("./structure");
var neo4j_driver_core_1 = require("neo4j-driver-core");
var PROTOCOL_ERROR = neo4j_driver_core_1.error.PROTOCOL_ERROR;
var TINY_STRING = 0x80;
var TINY_LIST = 0x90;
var TINY_MAP = 0xa0;
var TINY_STRUCT = 0xb0;
var NULL = 0xc0;
var FLOAT_64 = 0xc1;
var FALSE = 0xc2;
var TRUE = 0xc3;
var INT_8 = 0xc8;
var INT_16 = 0xc9;
var INT_32 = 0xca;
var INT_64 = 0xcb;
var STRING_8 = 0xd0;
var STRING_16 = 0xd1;
var STRING_32 = 0xd2;
var LIST_8 = 0xd4;
var LIST_16 = 0xd5;
var LIST_32 = 0xd6;
var BYTES_8 = 0xcc;
var BYTES_16 = 0xcd;
var BYTES_32 = 0xce;
var MAP_8 = 0xd8;
var MAP_16 = 0xd9;
var MAP_32 = 0xda;
var STRUCT_8 = 0xdc;
var STRUCT_16 = 0xdd;
/**
* Class to pack
* @access private
*/
var Packer = /** @class */ (function () {
/**
* @constructor
* @param {Chunker} channel the chunker backed by a network channel.
*/
function Packer(channel) {
this._ch = channel;
this._byteArraysSupported = true;
}
/**
* Creates a packable function out of the provided value
* @param x the value to pack
* @returns Function
*/
Packer.prototype.packable = function (x, dehydrateStruct) {
var _this = this;
if (dehydrateStruct === void 0) { dehydrateStruct = lang_1.functional.identity; }
try {
x = dehydrateStruct(x);
}
catch (ex) {
return function () { throw ex; };
}
if (x === null) {
return function () { return _this._ch.writeUInt8(NULL); };
}
else if (x === true) {
return function () { return _this._ch.writeUInt8(TRUE); };
}
else if (x === false) {
return function () { return _this._ch.writeUInt8(FALSE); };
}
else if (typeof x === 'number') {
return function () { return _this.packFloat(x); };
}
else if (typeof x === 'string') {
return function () { return _this.packString(x); };
}
else if (typeof x === 'bigint') {
return function () { return _this.packInteger((0, neo4j_driver_core_1.int)(x)); };
}
else if ((0, neo4j_driver_core_1.isInt)(x)) {
return function () { return _this.packInteger(x); };
}
else if (x instanceof Int8Array) {
return function () { return _this.packBytes(x); };
}
else if (x instanceof Array) {
return function () {
_this.packListHeader(x.length);
for (var i = 0; i < x.length; i++) {
_this.packable(x[i] === undefined ? null : x[i], dehydrateStruct)();
}
};
}
else if (isIterable(x)) {
return this.packableIterable(x, dehydrateStruct);
}
else if (x instanceof structure_1.Structure) {
var packableFields_1 = [];
for (var i = 0; i < x.fields.length; i++) {
packableFields_1[i] = this.packable(x.fields[i], dehydrateStruct);
}
return function () { return _this.packStruct(x.signature, packableFields_1); };
}
else if (typeof x === 'object') {
return function () {
var keys = Object.keys(x);
var count = 0;
for (var i = 0; i < keys.length; i++) {
if (x[keys[i]] !== undefined) {
count++;
}
}
_this.packMapHeader(count);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (x[key] !== undefined) {
_this.packString(key);
_this.packable(x[key], dehydrateStruct)();
}
}
};
}
else {
return this._nonPackableValue("Unable to pack the given value: ".concat(x));
}
};
Packer.prototype.packableIterable = function (iterable, dehydrateStruct) {
try {
var array = Array.from(iterable);
return this.packable(array, dehydrateStruct);
}
catch (e) {
// handle errors from iterable to array conversion
throw (0, neo4j_driver_core_1.newError)("Cannot pack given iterable, ".concat(e.message, ": ").concat(iterable));
}
};
/**
* Packs a struct
* @param signature the signature of the struct
* @param packableFields the fields of the struct, make sure you call `packable on all fields`
*/
Packer.prototype.packStruct = function (signature, packableFields) {
packableFields = packableFields || [];
this.packStructHeader(packableFields.length, signature);
for (var i = 0; i < packableFields.length; i++) {
packableFields[i]();
}
};
Packer.prototype.packInteger = function (x) {
var high = x.high;
var low = x.low;
if (x.greaterThanOrEqual(-0x10) && x.lessThan(0x80)) {
this._ch.writeInt8(low);
}
else if (x.greaterThanOrEqual(-0x80) && x.lessThan(-0x10)) {
this._ch.writeUInt8(INT_8);
this._ch.writeInt8(low);
}
else if (x.greaterThanOrEqual(-0x8000) && x.lessThan(0x8000)) {
this._ch.writeUInt8(INT_16);
this._ch.writeInt16(low);
}
else if (x.greaterThanOrEqual(-0x80000000) && x.lessThan(0x80000000)) {
this._ch.writeUInt8(INT_32);
this._ch.writeInt32(low);
}
else {
this._ch.writeUInt8(INT_64);
this._ch.writeInt32(high);
this._ch.writeInt32(low);
}
};
Packer.prototype.packFloat = function (x) {
this._ch.writeUInt8(FLOAT_64);
this._ch.writeFloat64(x);
};
Packer.prototype.packString = function (x) {
var bytes = channel_1.utf8.encode(x);
var size = bytes.length;
if (size < 0x10) {
this._ch.writeUInt8(TINY_STRING | size);
this._ch.writeBytes(bytes);
}
else if (size < 0x100) {
this._ch.writeUInt8(STRING_8);
this._ch.writeUInt8(size);
this._ch.writeBytes(bytes);
}
else if (size < 0x10000) {
this._ch.writeUInt8(STRING_16);
this._ch.writeUInt8((size / 256) >> 0);
this._ch.writeUInt8(size % 256);
this._ch.writeBytes(bytes);
}
else if (size < 0x100000000) {
this._ch.writeUInt8(STRING_32);
this._ch.writeUInt8(((size / 16777216) >> 0) % 256);
this._ch.writeUInt8(((size / 65536) >> 0) % 256);
this._ch.writeUInt8(((size / 256) >> 0) % 256);
this._ch.writeUInt8(size % 256);
this._ch.writeBytes(bytes);
}
else {
throw (0, neo4j_driver_core_1.newError)('UTF-8 strings of size ' + size + ' are not supported');
}
};
Packer.prototype.packListHeader = function (size) {
if (size < 0x10) {
this._ch.writeUInt8(TINY_LIST | size);
}
else if (size < 0x100) {
this._ch.writeUInt8(LIST_8);
this._ch.writeUInt8(size);
}
else if (size < 0x10000) {
this._ch.writeUInt8(LIST_16);
this._ch.writeUInt8(((size / 256) >> 0) % 256);
this._ch.writeUInt8(size % 256);
}
else if (size < 0x100000000) {
this._ch.writeUInt8(LIST_32);
this._ch.writeUInt8(((size / 16777216) >> 0) % 256);
this._ch.writeUInt8(((size / 65536) >> 0) % 256);
this._ch.writeUInt8(((size / 256) >> 0) % 256);
this._ch.writeUInt8(size % 256);
}
else {
throw (0, neo4j_driver_core_1.newError)('Lists of size ' + size + ' are not supported');
}
};
Packer.prototype.packBytes = function (array) {
if (this._byteArraysSupported) {
this.packBytesHeader(array.length);
for (var i = 0; i < array.length; i++) {
this._ch.writeInt8(array[i]);
}
}
else {
throw (0, neo4j_driver_core_1.newError)('Byte arrays are not supported by the database this driver is connected to');
}
};
Packer.prototype.packBytesHeader = function (size) {
if (size < 0x100) {
this._ch.writeUInt8(BYTES_8);
this._ch.writeUInt8(size);
}
else if (size < 0x10000) {
this._ch.writeUInt8(BYTES_16);
this._ch.writeUInt8(((size / 256) >> 0) % 256);
this._ch.writeUInt8(size % 256);
}
else if (size < 0x100000000) {
this._ch.writeUInt8(BYTES_32);
this._ch.writeUInt8(((size / 16777216) >> 0) % 256);
this._ch.writeUInt8(((size / 65536) >> 0) % 256);
this._ch.writeUInt8(((size / 256) >> 0) % 256);
this._ch.writeUInt8(size % 256);
}
else {
throw (0, neo4j_driver_core_1.newError)('Byte arrays of size ' + size + ' are not supported');
}
};
Packer.prototype.packMapHeader = function (size) {
if (size < 0x10) {
this._ch.writeUInt8(TINY_MAP | size);
}
else if (size < 0x100) {
this._ch.writeUInt8(MAP_8);
this._ch.writeUInt8(size);
}
else if (size < 0x10000) {
this._ch.writeUInt8(MAP_16);
this._ch.writeUInt8((size / 256) >> 0);
this._ch.writeUInt8(size % 256);
}
else if (size < 0x100000000) {
this._ch.writeUInt8(MAP_32);
this._ch.writeUInt8(((size / 16777216) >> 0) % 256);
this._ch.writeUInt8(((size / 65536) >> 0) % 256);
this._ch.writeUInt8(((size / 256) >> 0) % 256);
this._ch.writeUInt8(size % 256);
}
else {
throw (0, neo4j_driver_core_1.newError)('Maps of size ' + size + ' are not supported');
}
};
Packer.prototype.packStructHeader = function (size, signature) {
if (size < 0x10) {
this._ch.writeUInt8(TINY_STRUCT | size);
this._ch.writeUInt8(signature);
}
else if (size < 0x100) {
this._ch.writeUInt8(STRUCT_8);
this._ch.writeUInt8(size);
this._ch.writeUInt8(signature);
}
else if (size < 0x10000) {
this._ch.writeUInt8(STRUCT_16);
this._ch.writeUInt8((size / 256) >> 0);
this._ch.writeUInt8(size % 256);
}
else {
throw (0, neo4j_driver_core_1.newError)('Structures of size ' + size + ' are not supported');
}
};
Packer.prototype.disableByteArrays = function () {
this._byteArraysSupported = false;
};
Packer.prototype._nonPackableValue = function (message) {
return function () {
throw (0, neo4j_driver_core_1.newError)(message, PROTOCOL_ERROR);
};
};
return Packer;
}());
exports.Packer = Packer;
/**
* Class to unpack
* @access private
*/
var Unpacker = /** @class */ (function () {
/**
* @constructor
* @param {boolean} disableLosslessIntegers if this unpacker should convert all received integers to native JS numbers.
* @param {boolean} useBigInt if this unpacker should convert all received integers to Bigint
*/
function Unpacker(disableLosslessIntegers, useBigInt) {
if (disableLosslessIntegers === void 0) { disableLosslessIntegers = false; }
if (useBigInt === void 0) { useBigInt = false; }
this._disableLosslessIntegers = disableLosslessIntegers;
this._useBigInt = useBigInt;
}
Unpacker.prototype.unpack = function (buffer, hydrateStructure) {
if (hydrateStructure === void 0) { hydrateStructure = lang_1.functional.identity; }
var marker = buffer.readUInt8();
var markerHigh = marker & 0xf0;
var markerLow = marker & 0x0f;
if (marker === NULL) {
return null;
}
var boolean = this._unpackBoolean(marker);
if (boolean !== null) {
return boolean;
}
var numberOrInteger = this._unpackNumberOrInteger(marker, buffer);
if (numberOrInteger !== null) {
if ((0, neo4j_driver_core_1.isInt)(numberOrInteger)) {
if (this._useBigInt) {
return numberOrInteger.toBigInt();
}
else if (this._disableLosslessIntegers) {
return numberOrInteger.toNumberOrInfinity();
}
}
return numberOrInteger;
}
var string = this._unpackString(marker, markerHigh, markerLow, buffer);
if (string !== null) {
return string;
}
var list = this._unpackList(marker, markerHigh, markerLow, buffer, hydrateStructure);
if (list !== null) {
return list;
}
var byteArray = this._unpackByteArray(marker, buffer);
if (byteArray !== null) {
return byteArray;
}
var map = this._unpackMap(marker, markerHigh, markerLow, buffer, hydrateStructure);
if (map !== null) {
return map;
}
var struct = this._unpackStruct(marker, markerHigh, markerLow, buffer, hydrateStructure);
if (struct !== null) {
return struct;
}
throw (0, neo4j_driver_core_1.newError)('Unknown packed value with marker ' + marker.toString(16));
};
Unpacker.prototype.unpackInteger = function (buffer) {
var marker = buffer.readUInt8();
var result = this._unpackInteger(marker, buffer);
if (result == null) {
throw (0, neo4j_driver_core_1.newError)('Unable to unpack integer value with marker ' + marker.toString(16));
}
return result;
};
Unpacker.prototype._unpackBoolean = function (marker) {
if (marker === TRUE) {
return true;
}
else if (marker === FALSE) {
return false;
}
else {
return null;
}
};
Unpacker.prototype._unpackNumberOrInteger = function (marker, buffer) {
if (marker === FLOAT_64) {
return buffer.readFloat64();
}
else {
return this._unpackInteger(marker, buffer);
}
};
Unpacker.prototype._unpackInteger = function (marker, buffer) {
if (marker >= 0 && marker < 128) {
return (0, neo4j_driver_core_1.int)(marker);
}
else if (marker >= 240 && marker < 256) {
return (0, neo4j_driver_core_1.int)(marker - 256);
}
else if (marker === INT_8) {
return (0, neo4j_driver_core_1.int)(buffer.readInt8());
}
else if (marker === INT_16) {
return (0, neo4j_driver_core_1.int)(buffer.readInt16());
}
else if (marker === INT_32) {
var b = buffer.readInt32();
return (0, neo4j_driver_core_1.int)(b);
}
else if (marker === INT_64) {
var high = buffer.readInt32();
var low = buffer.readInt32();
return new neo4j_driver_core_1.Integer(low, high);
}
else {
return null;
}
};
Unpacker.prototype._unpackString = function (marker, markerHigh, markerLow, buffer) {
if (markerHigh === TINY_STRING) {
return channel_1.utf8.decode(buffer, markerLow);
}
else if (marker === STRING_8) {
return channel_1.utf8.decode(buffer, buffer.readUInt8());
}
else if (marker === STRING_16) {
return channel_1.utf8.decode(buffer, buffer.readUInt16());
}
else if (marker === STRING_32) {
return channel_1.utf8.decode(buffer, buffer.readUInt32());
}
else {
return null;
}
};
Unpacker.prototype._unpackList = function (marker, markerHigh, markerLow, buffer, hydrateStructure) {
if (markerHigh === TINY_LIST) {
return this._unpackListWithSize(markerLow, buffer, hydrateStructure);
}
else if (marker === LIST_8) {
return this._unpackListWithSize(buffer.readUInt8(), buffer, hydrateStructure);
}
else if (marker === LIST_16) {
return this._unpackListWithSize(buffer.readUInt16(), buffer, hydrateStructure);
}
else if (marker === LIST_32) {
return this._unpackListWithSize(buffer.readUInt32(), buffer, hydrateStructure);
}
else {
return null;
}
};
Unpacker.prototype._unpackListWithSize = function (size, buffer, hydrateStructure) {
var value = [];
for (var i = 0; i < size; i++) {
value.push(this.unpack(buffer, hydrateStructure));
}
return value;
};
Unpacker.prototype._unpackByteArray = function (marker, buffer) {
if (marker === BYTES_8) {
return this._unpackByteArrayWithSize(buffer.readUInt8(), buffer);
}
else if (marker === BYTES_16) {
return this._unpackByteArrayWithSize(buffer.readUInt16(), buffer);
}
else if (marker === BYTES_32) {
return this._unpackByteArrayWithSize(buffer.readUInt32(), buffer);
}
else {
return null;
}
};
Unpacker.prototype._unpackByteArrayWithSize = function (size, buffer) {
var value = new Int8Array(size);
for (var i = 0; i < size; i++) {
value[i] = buffer.readInt8();
}
return value;
};
Unpacker.prototype._unpackMap = function (marker, markerHigh, markerLow, buffer, hydrateStructure) {
if (markerHigh === TINY_MAP) {
return this._unpackMapWithSize(markerLow, buffer, hydrateStructure);
}
else if (marker === MAP_8) {
return this._unpackMapWithSize(buffer.readUInt8(), buffer, hydrateStructure);
}
else if (marker === MAP_16) {
return this._unpackMapWithSize(buffer.readUInt16(), buffer, hydrateStructure);
}
else if (marker === MAP_32) {
return this._unpackMapWithSize(buffer.readUInt32(), buffer, hydrateStructure);
}
else {
return null;
}
};
Unpacker.prototype._unpackMapWithSize = function (size, buffer, hydrateStructure) {
var value = {};
for (var i = 0; i < size; i++) {
var key = this.unpack(buffer, hydrateStructure);
value[key] = this.unpack(buffer, hydrateStructure);
}
return value;
};
Unpacker.prototype._unpackStruct = function (marker, markerHigh, markerLow, buffer, hydrateStructure) {
if (markerHigh === TINY_STRUCT) {
return this._unpackStructWithSize(markerLow, buffer, hydrateStructure);
}
else if (marker === STRUCT_8) {
return this._unpackStructWithSize(buffer.readUInt8(), buffer, hydrateStructure);
}
else if (marker === STRUCT_16) {
return this._unpackStructWithSize(buffer.readUInt16(), buffer, hydrateStructure);
}
else {
return null;
}
};
Unpacker.prototype._unpackStructWithSize = function (structSize, buffer, hydrateStructure) {
var signature = buffer.readUInt8();
var structure = new structure_1.Structure(signature, []);
for (var i = 0; i < structSize; i++) {
structure.fields.push(this.unpack(buffer, hydrateStructure));
}
return hydrateStructure(structure);
};
return Unpacker;
}());
exports.Unpacker = Unpacker;
function isIterable(obj) {
if (obj == null) {
return false;
}
return typeof obj[Symbol.iterator] === 'function';
}