@cloudpss/ubjson
Version:
Opinionated UBJSON encoder/decoder for CloudPSS.
206 lines • 7.48 kB
JavaScript
import { unsupportedView } from './errors.js';
/** 创建数据包装 */
export function EncodeCursor(length) {
const data = new Uint8Array(length);
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
return {
data,
view,
length: 0,
ensureCapacity(capacity) {
if (this.length + capacity > this.data.length) {
throw new RangeError('Out of capacity');
}
},
};
}
/** 写入标签 */
export function writeMarker(cursor, marker) {
cursor.ensureCapacity(1);
cursor.data[cursor.length++] = marker;
}
export const I8_MASK = 105 /* constants.INT8 */ << 8;
export const U8_MASK = 85 /* constants.UINT8 */ << 8;
/** 写入长度 */
export function writeLength(cursor, length) {
if (length < 0x80) {
cursor.ensureCapacity(2);
cursor.view.setUint16(cursor.length, I8_MASK | length);
cursor.length += 2;
}
else if (length < 0x8000) {
cursor.ensureCapacity(3);
cursor.data[cursor.length++] = 73 /* constants.INT16 */;
cursor.view.setInt16(cursor.length, length);
cursor.length += 2;
}
else if (length < 0x8000_0000) {
cursor.ensureCapacity(5);
cursor.data[cursor.length++] = 108 /* constants.INT32 */;
cursor.view.setInt32(cursor.length, length);
cursor.length += 4;
}
else if (length < Number.MAX_SAFE_INTEGER) {
cursor.ensureCapacity(9);
cursor.data[cursor.length++] = 76 /* constants.INT64 */;
cursor.view.setBigInt64(cursor.length, BigInt(length));
cursor.length += 8;
}
else {
throw new RangeError('Invalid length');
}
}
/** 写入数字 */
export function writeNumber(cursor, value) {
// eslint-disable-next-line unicorn/prefer-math-trunc
if (value >> 0 === value) {
if (value >= 0 && value <= 0xff) {
cursor.ensureCapacity(2);
const { length } = cursor;
cursor.view.setUint16(length, U8_MASK | value);
cursor.length = length + 2;
}
else if (value < 0x80 && value >= -0x80) {
cursor.ensureCapacity(2);
const { length } = cursor;
cursor.view.setUint16(length, I8_MASK | (value & 0xff));
cursor.length = length + 2;
}
else if (value < 0x8000 && value >= -0x8000) {
cursor.ensureCapacity(3);
const { length } = cursor;
cursor.data[length] = 73 /* constants.INT16 */;
cursor.view.setInt16(length + 1, value);
cursor.length = length + 3;
}
else {
// must be 32 bit
cursor.ensureCapacity(5);
const { length } = cursor;
cursor.data[length] = 108 /* constants.INT32 */;
cursor.view.setInt32(length + 1, value);
cursor.length = length + 5;
}
}
else if (Number.isNaN(value) || Math.fround(value) === value) {
// 如果不会损失精度,使用 32 位浮点
cursor.ensureCapacity(5);
const { length } = cursor;
cursor.data[length] = 100 /* constants.FLOAT32 */;
cursor.view.setFloat32(length + 1, value);
cursor.length = length + 5;
}
else {
cursor.ensureCapacity(9);
const { length } = cursor;
cursor.data[length] = 68 /* constants.FLOAT64 */;
cursor.view.setFloat64(length + 1, value);
cursor.length = length + 9;
}
return;
}
const T_ARR_HEADER = (type) => (91 /* constants.ARRAY */ << 24) | (36 /* constants.TYPE_MARKER */ << 16) | (type << 8) | 35 /* constants.COUNT_MARKER */;
export const U8_ARR_HEADER = T_ARR_HEADER(85 /* constants.UINT8 */);
export const I8_ARR_HEADER = T_ARR_HEADER(105 /* constants.INT8 */);
export const I16_ARR_HEADER = T_ARR_HEADER(73 /* constants.INT16 */);
export const I32_ARR_HEADER = T_ARR_HEADER(108 /* constants.INT32 */);
export const I64_ARR_HEADER = T_ARR_HEADER(76 /* constants.INT64 */);
export const F32_ARR_HEADER = T_ARR_HEADER(100 /* constants.FLOAT32 */);
export const F64_ARR_HEADER = T_ARR_HEADER(68 /* constants.FLOAT64 */);
/** 写入 TypedArray 前导,包括 marker 和长度 */
export function writeTypedArrayHeader(cursor, value) {
// ARRAY(1) + TYPE_MARKER(1) + TYPE(1) + COUNT_MARKER(1) + COUNT(MIN2 MAX5) + DATA
cursor.ensureCapacity(9);
let type;
const { length } = cursor;
if (value instanceof Uint8Array) {
cursor.view.setUint32(length, U8_ARR_HEADER);
type = 85 /* constants.UINT8 */;
}
else if (value instanceof Float64Array) {
cursor.view.setUint32(length, F64_ARR_HEADER);
type = 68 /* constants.FLOAT64 */;
}
else if (value instanceof Int32Array) {
cursor.view.setUint32(length, I32_ARR_HEADER);
type = 108 /* constants.INT32 */;
}
else if (value instanceof BigInt64Array) {
cursor.view.setUint32(length, I64_ARR_HEADER);
type = 76 /* constants.INT64 */;
}
else if (value instanceof Float32Array) {
cursor.view.setUint32(length, F32_ARR_HEADER);
type = 100 /* constants.FLOAT32 */;
}
else if (value instanceof Int8Array) {
cursor.view.setUint32(length, I8_ARR_HEADER);
type = 105 /* constants.INT8 */;
}
else if (value instanceof Int16Array) {
cursor.view.setUint32(length, I16_ARR_HEADER);
type = 73 /* constants.INT16 */;
}
else {
unsupportedView(value);
}
cursor.length = length + 4;
writeLength(cursor, value.length);
return type;
}
/** 写入 TypedArray */
export function writeTypedArray(cursor, value) {
cursor.ensureCapacity(9 + value.byteLength);
const type = writeTypedArrayHeader(cursor, value);
writeTypedArrayData(cursor, type, value);
}
/** 写入 TypedArray 数据 */
export function writeTypedArrayData(cursor, type, value) {
const { byteLength } = value;
cursor.ensureCapacity(byteLength);
let pointer = cursor.length;
cursor.length = pointer + byteLength;
if (type === 85 /* constants.UINT8 */ || type === 105 /* constants.INT8 */) {
// fast path for typed arrays with `BYTES_PER_ELEMENT` of 1
cursor.data.set(value, pointer);
return;
}
const { view } = cursor;
if (type === 68 /* constants.FLOAT64 */) {
const arrayLength = byteLength / 8;
for (let i = 0; i < arrayLength; i++) {
view.setFloat64(pointer, value[i]);
pointer += 8;
}
}
else if (type === 108 /* constants.INT32 */) {
const arrayLength = byteLength / 4;
for (let i = 0; i < arrayLength; i++) {
view.setInt32(pointer, value[i]);
pointer += 4;
}
}
else if (type === 76 /* constants.INT64 */) {
const arrayLength = byteLength / 8;
for (let i = 0; i < arrayLength; i++) {
view.setBigInt64(pointer, value[i]);
pointer += 8;
}
}
else if (type === 100 /* constants.FLOAT32 */) {
const arrayLength = byteLength / 4;
for (let i = 0; i < arrayLength; i++) {
view.setFloat32(pointer, value[i]);
pointer += 4;
}
}
else {
(type);
const arrayLength = byteLength / 2;
for (let i = 0; i < arrayLength; i++) {
view.setInt16(pointer, value[i]);
pointer += 2;
}
}
}
//# sourceMappingURL=encode.js.map