lib0
Version:
> Monorepo of isomorphic utility functions
1,868 lines (1,743 loc) • 54.3 kB
JavaScript
'use strict';
var string = require('./string-6d104757.cjs');
var environment = require('./environment-ad129e4d.cjs');
var array = require('./array-704ca50e.cjs');
var math = require('./math-08e068f9.cjs');
var binary = require('./binary-ac8e39e2.cjs');
var number = require('./number-466d8922.cjs');
var error = require('./error-8582d695.cjs');
/**
* Efficient schema-less binary encoding with support for variable length encoding.
*
* Use [lib0/encoding] with [lib0/decoding]. Every encoding function has a corresponding decoding function.
*
* Encodes numbers in little-endian order (least to most significant byte order)
* and is compatible with Golang's binary encoding (https://golang.org/pkg/encoding/binary/)
* which is also used in Protocol Buffers.
*
* ```js
* // encoding step
* const encoder = encoding.createEncoder()
* encoding.writeVarUint(encoder, 256)
* encoding.writeVarString(encoder, 'Hello world!')
* const buf = encoding.toUint8Array(encoder)
* ```
*
* ```js
* // decoding step
* const decoder = decoding.createDecoder(buf)
* decoding.readVarUint(decoder) // => 256
* decoding.readVarString(decoder) // => 'Hello world!'
* decoding.hasContent(decoder) // => false - all data is read
* ```
*
* @module encoding
*/
/**
* A BinaryEncoder handles the encoding to an Uint8Array.
*/
class Encoder {
constructor () {
this.cpos = 0;
this.cbuf = new Uint8Array(100);
/**
* @type {Array<Uint8Array>}
*/
this.bufs = [];
}
}
/**
* @function
* @return {Encoder}
*/
const createEncoder = () => new Encoder();
/**
* @param {function(Encoder):void} f
*/
const encode = (f) => {
const encoder = createEncoder();
f(encoder);
return toUint8Array(encoder)
};
/**
* The current length of the encoded data.
*
* @function
* @param {Encoder} encoder
* @return {number}
*/
const length = encoder => {
let len = encoder.cpos;
for (let i = 0; i < encoder.bufs.length; i++) {
len += encoder.bufs[i].length;
}
return len
};
/**
* Check whether encoder is empty.
*
* @function
* @param {Encoder} encoder
* @return {boolean}
*/
const hasContent$1 = encoder => encoder.cpos > 0 || encoder.bufs.length > 0;
/**
* Transform to Uint8Array.
*
* @function
* @param {Encoder} encoder
* @return {Uint8Array} The created ArrayBuffer.
*/
const toUint8Array = encoder => {
const uint8arr = new Uint8Array(length(encoder));
let curPos = 0;
for (let i = 0; i < encoder.bufs.length; i++) {
const d = encoder.bufs[i];
uint8arr.set(d, curPos);
curPos += d.length;
}
uint8arr.set(createUint8ArrayViewFromArrayBuffer(encoder.cbuf.buffer, 0, encoder.cpos), curPos);
return uint8arr
};
/**
* Verify that it is possible to write `len` bytes wtihout checking. If
* necessary, a new Buffer with the required length is attached.
*
* @param {Encoder} encoder
* @param {number} len
*/
const verifyLen = (encoder, len) => {
const bufferLen = encoder.cbuf.length;
if (bufferLen - encoder.cpos < len) {
encoder.bufs.push(createUint8ArrayViewFromArrayBuffer(encoder.cbuf.buffer, 0, encoder.cpos));
encoder.cbuf = new Uint8Array(math.max(bufferLen, len) * 2);
encoder.cpos = 0;
}
};
/**
* Write one byte to the encoder.
*
* @function
* @param {Encoder} encoder
* @param {number} num The byte that is to be encoded.
*/
const write = (encoder, num) => {
const bufferLen = encoder.cbuf.length;
if (encoder.cpos === bufferLen) {
encoder.bufs.push(encoder.cbuf);
encoder.cbuf = new Uint8Array(bufferLen * 2);
encoder.cpos = 0;
}
encoder.cbuf[encoder.cpos++] = num;
};
/**
* Write one byte at a specific position.
* Position must already be written (i.e. encoder.length > pos)
*
* @function
* @param {Encoder} encoder
* @param {number} pos Position to which to write data
* @param {number} num Unsigned 8-bit integer
*/
const set = (encoder, pos, num) => {
let buffer = null;
// iterate all buffers and adjust position
for (let i = 0; i < encoder.bufs.length && buffer === null; i++) {
const b = encoder.bufs[i];
if (pos < b.length) {
buffer = b; // found buffer
} else {
pos -= b.length;
}
}
if (buffer === null) {
// use current buffer
buffer = encoder.cbuf;
}
buffer[pos] = num;
};
/**
* Write one byte as an unsigned integer.
*
* @function
* @param {Encoder} encoder
* @param {number} num The number that is to be encoded.
*/
const writeUint8 = write;
/**
* Write one byte as an unsigned Integer at a specific location.
*
* @function
* @param {Encoder} encoder
* @param {number} pos The location where the data will be written.
* @param {number} num The number that is to be encoded.
*/
const setUint8 = set;
/**
* Write two bytes as an unsigned integer.
*
* @function
* @param {Encoder} encoder
* @param {number} num The number that is to be encoded.
*/
const writeUint16 = (encoder, num) => {
write(encoder, num & binary.BITS8);
write(encoder, (num >>> 8) & binary.BITS8);
};
/**
* Write two bytes as an unsigned integer at a specific location.
*
* @function
* @param {Encoder} encoder
* @param {number} pos The location where the data will be written.
* @param {number} num The number that is to be encoded.
*/
const setUint16 = (encoder, pos, num) => {
set(encoder, pos, num & binary.BITS8);
set(encoder, pos + 1, (num >>> 8) & binary.BITS8);
};
/**
* Write two bytes as an unsigned integer
*
* @function
* @param {Encoder} encoder
* @param {number} num The number that is to be encoded.
*/
const writeUint32 = (encoder, num) => {
for (let i = 0; i < 4; i++) {
write(encoder, num & binary.BITS8);
num >>>= 8;
}
};
/**
* Write two bytes as an unsigned integer in big endian order.
* (most significant byte first)
*
* @function
* @param {Encoder} encoder
* @param {number} num The number that is to be encoded.
*/
const writeUint32BigEndian = (encoder, num) => {
for (let i = 3; i >= 0; i--) {
write(encoder, (num >>> (8 * i)) & binary.BITS8);
}
};
/**
* Write two bytes as an unsigned integer at a specific location.
*
* @function
* @param {Encoder} encoder
* @param {number} pos The location where the data will be written.
* @param {number} num The number that is to be encoded.
*/
const setUint32 = (encoder, pos, num) => {
for (let i = 0; i < 4; i++) {
set(encoder, pos + i, num & binary.BITS8);
num >>>= 8;
}
};
/**
* Write a variable length unsigned integer. Max encodable integer is 2^53.
*
* @function
* @param {Encoder} encoder
* @param {number} num The number that is to be encoded.
*/
const writeVarUint = (encoder, num) => {
while (num > binary.BITS7) {
write(encoder, binary.BIT8 | (binary.BITS7 & num));
num = math.floor(num / 128); // shift >>> 7
}
write(encoder, binary.BITS7 & num);
};
/**
* Write a variable length integer.
*
* We use the 7th bit instead for signaling that this is a negative number.
*
* @function
* @param {Encoder} encoder
* @param {number} num The number that is to be encoded.
*/
const writeVarInt = (encoder, num) => {
const isNegative = math.isNegativeZero(num);
if (isNegative) {
num = -num;
}
// |- whether to continue reading |- whether is negative |- number
write(encoder, (num > binary.BITS6 ? binary.BIT8 : 0) | (isNegative ? binary.BIT7 : 0) | (binary.BITS6 & num));
num = math.floor(num / 64); // shift >>> 6
// We don't need to consider the case of num === 0 so we can use a different
// pattern here than above.
while (num > 0) {
write(encoder, (num > binary.BITS7 ? binary.BIT8 : 0) | (binary.BITS7 & num));
num = math.floor(num / 128); // shift >>> 7
}
};
/**
* A cache to store strings temporarily
*/
const _strBuffer = new Uint8Array(30000);
const _maxStrBSize = _strBuffer.length / 3;
/**
* Write a variable length string.
*
* @function
* @param {Encoder} encoder
* @param {String} str The string that is to be encoded.
*/
const _writeVarStringNative = (encoder, str) => {
if (str.length < _maxStrBSize) {
// We can encode the string into the existing buffer
/* c8 ignore next */
const written = string.utf8TextEncoder.encodeInto(str, _strBuffer).written || 0;
writeVarUint(encoder, written);
for (let i = 0; i < written; i++) {
write(encoder, _strBuffer[i]);
}
} else {
writeVarUint8Array(encoder, string.encodeUtf8(str));
}
};
/**
* Write a variable length string.
*
* @function
* @param {Encoder} encoder
* @param {String} str The string that is to be encoded.
*/
const _writeVarStringPolyfill = (encoder, str) => {
const encodedString = unescape(encodeURIComponent(str));
const len = encodedString.length;
writeVarUint(encoder, len);
for (let i = 0; i < len; i++) {
write(encoder, /** @type {number} */ (encodedString.codePointAt(i)));
}
};
/**
* Write a variable length string.
*
* @function
* @param {Encoder} encoder
* @param {String} str The string that is to be encoded.
*/
/* c8 ignore next */
const writeVarString = (string.utf8TextEncoder && /** @type {any} */ (string.utf8TextEncoder).encodeInto) ? _writeVarStringNative : _writeVarStringPolyfill;
/**
* Write a string terminated by a special byte sequence. This is not very performant and is
* generally discouraged. However, the resulting byte arrays are lexiographically ordered which
* makes this a nice feature for databases.
*
* The string will be encoded using utf8 and then terminated and escaped using writeTerminatingUint8Array.
*
* @function
* @param {Encoder} encoder
* @param {String} str The string that is to be encoded.
*/
const writeTerminatedString = (encoder, str) =>
writeTerminatedUint8Array(encoder, string.encodeUtf8(str));
/**
* Write a terminating Uint8Array. Note that this is not performant and is generally
* discouraged. There are few situations when this is needed.
*
* We use 0x0 as a terminating character. 0x1 serves as an escape character for 0x0 and 0x1.
*
* Example: [0,1,2] is encoded to [1,0,1,1,2,0]. 0x0, and 0x1 needed to be escaped using 0x1. Then
* the result is terminated using the 0x0 character.
*
* This is basically how many systems implement null terminated strings. However, we use an escape
* character 0x1 to avoid issues and potenial attacks on our database (if this is used as a key
* encoder for NoSql databases).
*
* @function
* @param {Encoder} encoder
* @param {Uint8Array} buf The string that is to be encoded.
*/
const writeTerminatedUint8Array = (encoder, buf) => {
for (let i = 0; i < buf.length; i++) {
const b = buf[i];
if (b === 0 || b === 1) {
write(encoder, 1);
}
write(encoder, buf[i]);
}
write(encoder, 0);
};
/**
* Write the content of another Encoder.
*
* @TODO: can be improved!
* - Note: Should consider that when appending a lot of small Encoders, we should rather clone than referencing the old structure.
* Encoders start with a rather big initial buffer.
*
* @function
* @param {Encoder} encoder The enUint8Arr
* @param {Encoder} append The BinaryEncoder to be written.
*/
const writeBinaryEncoder = (encoder, append) => writeUint8Array(encoder, toUint8Array(append));
/**
* Append fixed-length Uint8Array to the encoder.
*
* @function
* @param {Encoder} encoder
* @param {Uint8Array} uint8Array
*/
const writeUint8Array = (encoder, uint8Array) => {
const bufferLen = encoder.cbuf.length;
const cpos = encoder.cpos;
const leftCopyLen = math.min(bufferLen - cpos, uint8Array.length);
const rightCopyLen = uint8Array.length - leftCopyLen;
encoder.cbuf.set(uint8Array.subarray(0, leftCopyLen), cpos);
encoder.cpos += leftCopyLen;
if (rightCopyLen > 0) {
// Still something to write, write right half..
// Append new buffer
encoder.bufs.push(encoder.cbuf);
// must have at least size of remaining buffer
encoder.cbuf = new Uint8Array(math.max(bufferLen * 2, rightCopyLen));
// copy array
encoder.cbuf.set(uint8Array.subarray(leftCopyLen));
encoder.cpos = rightCopyLen;
}
};
/**
* Append an Uint8Array to Encoder.
*
* @function
* @param {Encoder} encoder
* @param {Uint8Array} uint8Array
*/
const writeVarUint8Array = (encoder, uint8Array) => {
writeVarUint(encoder, uint8Array.byteLength);
writeUint8Array(encoder, uint8Array);
};
/**
* Create an DataView of the next `len` bytes. Use it to write data after
* calling this function.
*
* ```js
* // write float32 using DataView
* const dv = writeOnDataView(encoder, 4)
* dv.setFloat32(0, 1.1)
* // read float32 using DataView
* const dv = readFromDataView(encoder, 4)
* dv.getFloat32(0) // => 1.100000023841858 (leaving it to the reader to find out why this is the correct result)
* ```
*
* @param {Encoder} encoder
* @param {number} len
* @return {DataView}
*/
const writeOnDataView = (encoder, len) => {
verifyLen(encoder, len);
const dview = new DataView(encoder.cbuf.buffer, encoder.cpos, len);
encoder.cpos += len;
return dview
};
/**
* @param {Encoder} encoder
* @param {number} num
*/
const writeFloat32 = (encoder, num) => writeOnDataView(encoder, 4).setFloat32(0, num, false);
/**
* @param {Encoder} encoder
* @param {number} num
*/
const writeFloat64 = (encoder, num) => writeOnDataView(encoder, 8).setFloat64(0, num, false);
/**
* @param {Encoder} encoder
* @param {bigint} num
*/
const writeBigInt64 = (encoder, num) => /** @type {any} */ (writeOnDataView(encoder, 8)).setBigInt64(0, num, false);
/**
* @param {Encoder} encoder
* @param {bigint} num
*/
const writeBigUint64 = (encoder, num) => /** @type {any} */ (writeOnDataView(encoder, 8)).setBigUint64(0, num, false);
const floatTestBed = new DataView(new ArrayBuffer(4));
/**
* Check if a number can be encoded as a 32 bit float.
*
* @param {number} num
* @return {boolean}
*/
const isFloat32 = num => {
floatTestBed.setFloat32(0, num);
return floatTestBed.getFloat32(0) === num
};
/**
* Encode data with efficient binary format.
*
* Differences to JSON:
* • Transforms data to a binary format (not to a string)
* • Encodes undefined, NaN, and ArrayBuffer (these can't be represented in JSON)
* • Numbers are efficiently encoded either as a variable length integer, as a
* 32 bit float, as a 64 bit float, or as a 64 bit bigint.
*
* Encoding table:
*
* | Data Type | Prefix | Encoding Method | Comment |
* | ------------------- | -------- | ------------------ | ------- |
* | undefined | 127 | | Functions, symbol, and everything that cannot be identified is encoded as undefined |
* | null | 126 | | |
* | integer | 125 | writeVarInt | Only encodes 32 bit signed integers |
* | float32 | 124 | writeFloat32 | |
* | float64 | 123 | writeFloat64 | |
* | bigint | 122 | writeBigInt64 | |
* | boolean (false) | 121 | | True and false are different data types so we save the following byte |
* | boolean (true) | 120 | | - 0b01111000 so the last bit determines whether true or false |
* | string | 119 | writeVarString | |
* | object<string,any> | 118 | custom | Writes {length} then {length} key-value pairs |
* | array<any> | 117 | custom | Writes {length} then {length} json values |
* | Uint8Array | 116 | writeVarUint8Array | We use Uint8Array for any kind of binary data |
*
* Reasons for the decreasing prefix:
* We need the first bit for extendability (later we may want to encode the
* prefix with writeVarUint). The remaining 7 bits are divided as follows:
* [0-30] the beginning of the data range is used for custom purposes
* (defined by the function that uses this library)
* [31-127] the end of the data range is used for data encoding by
* lib0/encoding.js
*
* @param {Encoder} encoder
* @param {undefined|null|number|bigint|boolean|string|Object<string,any>|Array<any>|Uint8Array} data
*/
const writeAny = (encoder, data) => {
switch (typeof data) {
case 'string':
// TYPE 119: STRING
write(encoder, 119);
writeVarString(encoder, data);
break
case 'number':
if (number.isInteger(data) && math.abs(data) <= binary.BITS31) {
// TYPE 125: INTEGER
write(encoder, 125);
writeVarInt(encoder, data);
} else if (isFloat32(data)) {
// TYPE 124: FLOAT32
write(encoder, 124);
writeFloat32(encoder, data);
} else {
// TYPE 123: FLOAT64
write(encoder, 123);
writeFloat64(encoder, data);
}
break
case 'bigint':
// TYPE 122: BigInt
write(encoder, 122);
writeBigInt64(encoder, data);
break
case 'object':
if (data === null) {
// TYPE 126: null
write(encoder, 126);
} else if (array.isArray(data)) {
// TYPE 117: Array
write(encoder, 117);
writeVarUint(encoder, data.length);
for (let i = 0; i < data.length; i++) {
writeAny(encoder, data[i]);
}
} else if (data instanceof Uint8Array) {
// TYPE 116: ArrayBuffer
write(encoder, 116);
writeVarUint8Array(encoder, data);
} else {
// TYPE 118: Object
write(encoder, 118);
const keys = Object.keys(data);
writeVarUint(encoder, keys.length);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
writeVarString(encoder, key);
writeAny(encoder, data[key]);
}
}
break
case 'boolean':
// TYPE 120/121: boolean (true/false)
write(encoder, data ? 120 : 121);
break
default:
// TYPE 127: undefined
write(encoder, 127);
}
};
/**
* Now come a few stateful encoder that have their own classes.
*/
/**
* Basic Run Length Encoder - a basic compression implementation.
*
* Encodes [1,1,1,7] to [1,3,7,1] (3 times 1, 1 time 7). This encoder might do more harm than good if there are a lot of values that are not repeated.
*
* It was originally used for image compression. Cool .. article http://csbruce.com/cbm/transactor/pdfs/trans_v7_i06.pdf
*
* @note T must not be null!
*
* @template T
*/
class RleEncoder extends Encoder {
/**
* @param {function(Encoder, T):void} writer
*/
constructor (writer) {
super();
/**
* The writer
*/
this.w = writer;
/**
* Current state
* @type {T|null}
*/
this.s = null;
this.count = 0;
}
/**
* @param {T} v
*/
write (v) {
if (this.s === v) {
this.count++;
} else {
if (this.count > 0) {
// flush counter, unless this is the first value (count = 0)
writeVarUint(this, this.count - 1); // since count is always > 0, we can decrement by one. non-standard encoding ftw
}
this.count = 1;
// write first value
this.w(this, v);
this.s = v;
}
}
}
/**
* Basic diff decoder using variable length encoding.
*
* Encodes the values [3, 1100, 1101, 1050, 0] to [3, 1097, 1, -51, -1050] using writeVarInt.
*/
class IntDiffEncoder extends Encoder {
/**
* @param {number} start
*/
constructor (start) {
super();
/**
* Current state
* @type {number}
*/
this.s = start;
}
/**
* @param {number} v
*/
write (v) {
writeVarInt(this, v - this.s);
this.s = v;
}
}
/**
* A combination of IntDiffEncoder and RleEncoder.
*
* Basically first writes the IntDiffEncoder and then counts duplicate diffs using RleEncoding.
*
* Encodes the values [1,1,1,2,3,4,5,6] as [1,1,0,2,1,5] (RLE([1,0,0,1,1,1,1,1]) ⇒ RleIntDiff[1,1,0,2,1,5])
*/
class RleIntDiffEncoder extends Encoder {
/**
* @param {number} start
*/
constructor (start) {
super();
/**
* Current state
* @type {number}
*/
this.s = start;
this.count = 0;
}
/**
* @param {number} v
*/
write (v) {
if (this.s === v && this.count > 0) {
this.count++;
} else {
if (this.count > 0) {
// flush counter, unless this is the first value (count = 0)
writeVarUint(this, this.count - 1); // since count is always > 0, we can decrement by one. non-standard encoding ftw
}
this.count = 1;
// write first value
writeVarInt(this, v - this.s);
this.s = v;
}
}
}
/**
* @param {UintOptRleEncoder} encoder
*/
const flushUintOptRleEncoder = encoder => {
if (encoder.count > 0) {
// flush counter, unless this is the first value (count = 0)
// case 1: just a single value. set sign to positive
// case 2: write several values. set sign to negative to indicate that there is a length coming
writeVarInt(encoder.encoder, encoder.count === 1 ? encoder.s : -encoder.s);
if (encoder.count > 1) {
writeVarUint(encoder.encoder, encoder.count - 2); // since count is always > 1, we can decrement by one. non-standard encoding ftw
}
}
};
/**
* Optimized Rle encoder that does not suffer from the mentioned problem of the basic Rle encoder.
*
* Internally uses VarInt encoder to write unsigned integers. If the input occurs multiple times, we write
* write it as a negative number. The UintOptRleDecoder then understands that it needs to read a count.
*
* Encodes [1,2,3,3,3] as [1,2,-3,3] (once 1, once 2, three times 3)
*/
class UintOptRleEncoder {
constructor () {
this.encoder = new Encoder();
/**
* @type {number}
*/
this.s = 0;
this.count = 0;
}
/**
* @param {number} v
*/
write (v) {
if (this.s === v) {
this.count++;
} else {
flushUintOptRleEncoder(this);
this.count = 1;
this.s = v;
}
}
toUint8Array () {
flushUintOptRleEncoder(this);
return toUint8Array(this.encoder)
}
}
/**
* Increasing Uint Optimized RLE Encoder
*
* The RLE encoder counts the number of same occurences of the same value.
* The IncUintOptRle encoder counts if the value increases.
* I.e. 7, 8, 9, 10 will be encoded as [-7, 4]. 1, 3, 5 will be encoded
* as [1, 3, 5].
*/
class IncUintOptRleEncoder {
constructor () {
this.encoder = new Encoder();
/**
* @type {number}
*/
this.s = 0;
this.count = 0;
}
/**
* @param {number} v
*/
write (v) {
if (this.s + this.count === v) {
this.count++;
} else {
flushUintOptRleEncoder(this);
this.count = 1;
this.s = v;
}
}
toUint8Array () {
flushUintOptRleEncoder(this);
return toUint8Array(this.encoder)
}
}
/**
* @param {IntDiffOptRleEncoder} encoder
*/
const flushIntDiffOptRleEncoder = encoder => {
if (encoder.count > 0) {
// 31 bit making up the diff | wether to write the counter
// const encodedDiff = encoder.diff << 1 | (encoder.count === 1 ? 0 : 1)
const encodedDiff = encoder.diff * 2 + (encoder.count === 1 ? 0 : 1);
// flush counter, unless this is the first value (count = 0)
// case 1: just a single value. set first bit to positive
// case 2: write several values. set first bit to negative to indicate that there is a length coming
writeVarInt(encoder.encoder, encodedDiff);
if (encoder.count > 1) {
writeVarUint(encoder.encoder, encoder.count - 2); // since count is always > 1, we can decrement by one. non-standard encoding ftw
}
}
};
/**
* A combination of the IntDiffEncoder and the UintOptRleEncoder.
*
* The count approach is similar to the UintDiffOptRleEncoder, but instead of using the negative bitflag, it encodes
* in the LSB whether a count is to be read. Therefore this Encoder only supports 31 bit integers!
*
* Encodes [1, 2, 3, 2] as [3, 1, 6, -1] (more specifically [(1 << 1) | 1, (3 << 0) | 0, -1])
*
* Internally uses variable length encoding. Contrary to normal UintVar encoding, the first byte contains:
* * 1 bit that denotes whether the next value is a count (LSB)
* * 1 bit that denotes whether this value is negative (MSB - 1)
* * 1 bit that denotes whether to continue reading the variable length integer (MSB)
*
* Therefore, only five bits remain to encode diff ranges.
*
* Use this Encoder only when appropriate. In most cases, this is probably a bad idea.
*/
class IntDiffOptRleEncoder {
constructor () {
this.encoder = new Encoder();
/**
* @type {number}
*/
this.s = 0;
this.count = 0;
this.diff = 0;
}
/**
* @param {number} v
*/
write (v) {
if (this.diff === v - this.s) {
this.s = v;
this.count++;
} else {
flushIntDiffOptRleEncoder(this);
this.count = 1;
this.diff = v - this.s;
this.s = v;
}
}
toUint8Array () {
flushIntDiffOptRleEncoder(this);
return toUint8Array(this.encoder)
}
}
/**
* Optimized String Encoder.
*
* Encoding many small strings in a simple Encoder is not very efficient. The function call to decode a string takes some time and creates references that must be eventually deleted.
* In practice, when decoding several million small strings, the GC will kick in more and more often to collect orphaned string objects (or maybe there is another reason?).
*
* This string encoder solves the above problem. All strings are concatenated and written as a single string using a single encoding call.
*
* The lengths are encoded using a UintOptRleEncoder.
*/
class StringEncoder {
constructor () {
/**
* @type {Array<string>}
*/
this.sarr = [];
this.s = '';
this.lensE = new UintOptRleEncoder();
}
/**
* @param {string} string
*/
write (string) {
this.s += string;
if (this.s.length > 19) {
this.sarr.push(this.s);
this.s = '';
}
this.lensE.write(string.length);
}
toUint8Array () {
const encoder = new Encoder();
this.sarr.push(this.s);
this.s = '';
writeVarString(encoder, this.sarr.join(''));
writeUint8Array(encoder, this.lensE.toUint8Array());
return toUint8Array(encoder)
}
}
var encoding = /*#__PURE__*/Object.freeze({
__proto__: null,
Encoder: Encoder,
createEncoder: createEncoder,
encode: encode,
length: length,
hasContent: hasContent$1,
toUint8Array: toUint8Array,
verifyLen: verifyLen,
write: write,
set: set,
writeUint8: writeUint8,
setUint8: setUint8,
writeUint16: writeUint16,
setUint16: setUint16,
writeUint32: writeUint32,
writeUint32BigEndian: writeUint32BigEndian,
setUint32: setUint32,
writeVarUint: writeVarUint,
writeVarInt: writeVarInt,
_writeVarStringNative: _writeVarStringNative,
_writeVarStringPolyfill: _writeVarStringPolyfill,
writeVarString: writeVarString,
writeTerminatedString: writeTerminatedString,
writeTerminatedUint8Array: writeTerminatedUint8Array,
writeBinaryEncoder: writeBinaryEncoder,
writeUint8Array: writeUint8Array,
writeVarUint8Array: writeVarUint8Array,
writeOnDataView: writeOnDataView,
writeFloat32: writeFloat32,
writeFloat64: writeFloat64,
writeBigInt64: writeBigInt64,
writeBigUint64: writeBigUint64,
writeAny: writeAny,
RleEncoder: RleEncoder,
IntDiffEncoder: IntDiffEncoder,
RleIntDiffEncoder: RleIntDiffEncoder,
UintOptRleEncoder: UintOptRleEncoder,
IncUintOptRleEncoder: IncUintOptRleEncoder,
IntDiffOptRleEncoder: IntDiffOptRleEncoder,
StringEncoder: StringEncoder
});
/**
* Efficient schema-less binary decoding with support for variable length encoding.
*
* Use [lib0/decoding] with [lib0/encoding]. Every encoding function has a corresponding decoding function.
*
* Encodes numbers in little-endian order (least to most significant byte order)
* and is compatible with Golang's binary encoding (https://golang.org/pkg/encoding/binary/)
* which is also used in Protocol Buffers.
*
* ```js
* // encoding step
* const encoder = encoding.createEncoder()
* encoding.writeVarUint(encoder, 256)
* encoding.writeVarString(encoder, 'Hello world!')
* const buf = encoding.toUint8Array(encoder)
* ```
*
* ```js
* // decoding step
* const decoder = decoding.createDecoder(buf)
* decoding.readVarUint(decoder) // => 256
* decoding.readVarString(decoder) // => 'Hello world!'
* decoding.hasContent(decoder) // => false - all data is read
* ```
*
* @module decoding
*/
const errorUnexpectedEndOfArray = error.create('Unexpected end of array');
const errorIntegerOutOfRange = error.create('Integer out of Range');
/**
* A Decoder handles the decoding of an Uint8Array.
*/
class Decoder {
/**
* @param {Uint8Array} uint8Array Binary data to decode
*/
constructor (uint8Array) {
/**
* Decoding target.
*
* @type {Uint8Array}
*/
this.arr = uint8Array;
/**
* Current decoding position.
*
* @type {number}
*/
this.pos = 0;
}
}
/**
* @function
* @param {Uint8Array} uint8Array
* @return {Decoder}
*/
const createDecoder = uint8Array => new Decoder(uint8Array);
/**
* @function
* @param {Decoder} decoder
* @return {boolean}
*/
const hasContent = decoder => decoder.pos !== decoder.arr.length;
/**
* Clone a decoder instance.
* Optionally set a new position parameter.
*
* @function
* @param {Decoder} decoder The decoder instance
* @param {number} [newPos] Defaults to current position
* @return {Decoder} A clone of `decoder`
*/
const clone = (decoder, newPos = decoder.pos) => {
const _decoder = createDecoder(decoder.arr);
_decoder.pos = newPos;
return _decoder
};
/**
* Create an Uint8Array view of the next `len` bytes and advance the position by `len`.
*
* Important: The Uint8Array still points to the underlying ArrayBuffer. Make sure to discard the result as soon as possible to prevent any memory leaks.
* Use `buffer.copyUint8Array` to copy the result into a new Uint8Array.
*
* @function
* @param {Decoder} decoder The decoder instance
* @param {number} len The length of bytes to read
* @return {Uint8Array}
*/
const readUint8Array = (decoder, len) => {
const view = createUint8ArrayViewFromArrayBuffer(decoder.arr.buffer, decoder.pos + decoder.arr.byteOffset, len);
decoder.pos += len;
return view
};
/**
* Read variable length Uint8Array.
*
* Important: The Uint8Array still points to the underlying ArrayBuffer. Make sure to discard the result as soon as possible to prevent any memory leaks.
* Use `buffer.copyUint8Array` to copy the result into a new Uint8Array.
*
* @function
* @param {Decoder} decoder
* @return {Uint8Array}
*/
const readVarUint8Array = decoder => readUint8Array(decoder, readVarUint(decoder));
/**
* Read the rest of the content as an ArrayBuffer
* @function
* @param {Decoder} decoder
* @return {Uint8Array}
*/
const readTailAsUint8Array = decoder => readUint8Array(decoder, decoder.arr.length - decoder.pos);
/**
* Skip one byte, jump to the next position.
* @function
* @param {Decoder} decoder The decoder instance
* @return {number} The next position
*/
const skip8 = decoder => decoder.pos++;
/**
* Read one byte as unsigned integer.
* @function
* @param {Decoder} decoder The decoder instance
* @return {number} Unsigned 8-bit integer
*/
const readUint8 = decoder => decoder.arr[decoder.pos++];
/**
* Read 2 bytes as unsigned integer.
*
* @function
* @param {Decoder} decoder
* @return {number} An unsigned integer.
*/
const readUint16 = decoder => {
const uint =
decoder.arr[decoder.pos] +
(decoder.arr[decoder.pos + 1] << 8);
decoder.pos += 2;
return uint
};
/**
* Read 4 bytes as unsigned integer.
*
* @function
* @param {Decoder} decoder
* @return {number} An unsigned integer.
*/
const readUint32 = decoder => {
const uint =
(decoder.arr[decoder.pos] +
(decoder.arr[decoder.pos + 1] << 8) +
(decoder.arr[decoder.pos + 2] << 16) +
(decoder.arr[decoder.pos + 3] << 24)) >>> 0;
decoder.pos += 4;
return uint
};
/**
* Read 4 bytes as unsigned integer in big endian order.
* (most significant byte first)
*
* @function
* @param {Decoder} decoder
* @return {number} An unsigned integer.
*/
const readUint32BigEndian = decoder => {
const uint =
(decoder.arr[decoder.pos + 3] +
(decoder.arr[decoder.pos + 2] << 8) +
(decoder.arr[decoder.pos + 1] << 16) +
(decoder.arr[decoder.pos] << 24)) >>> 0;
decoder.pos += 4;
return uint
};
/**
* Look ahead without incrementing the position
* to the next byte and read it as unsigned integer.
*
* @function
* @param {Decoder} decoder
* @return {number} An unsigned integer.
*/
const peekUint8 = decoder => decoder.arr[decoder.pos];
/**
* Look ahead without incrementing the position
* to the next byte and read it as unsigned integer.
*
* @function
* @param {Decoder} decoder
* @return {number} An unsigned integer.
*/
const peekUint16 = decoder =>
decoder.arr[decoder.pos] +
(decoder.arr[decoder.pos + 1] << 8);
/**
* Look ahead without incrementing the position
* to the next byte and read it as unsigned integer.
*
* @function
* @param {Decoder} decoder
* @return {number} An unsigned integer.
*/
const peekUint32 = decoder => (
decoder.arr[decoder.pos] +
(decoder.arr[decoder.pos + 1] << 8) +
(decoder.arr[decoder.pos + 2] << 16) +
(decoder.arr[decoder.pos + 3] << 24)
) >>> 0;
/**
* Read unsigned integer (32bit) with variable length.
* 1/8th of the storage is used as encoding overhead.
* * numbers < 2^7 is stored in one bytlength
* * numbers < 2^14 is stored in two bylength
*
* @function
* @param {Decoder} decoder
* @return {number} An unsigned integer.length
*/
const readVarUint = decoder => {
let num = 0;
let mult = 1;
const len = decoder.arr.length;
while (decoder.pos < len) {
const r = decoder.arr[decoder.pos++];
// num = num | ((r & binary.BITS7) << len)
num = num + (r & binary.BITS7) * mult; // shift $r << (7*#iterations) and add it to num
mult *= 128; // next iteration, shift 7 "more" to the left
if (r < binary.BIT8) {
return num
}
/* c8 ignore start */
if (num > number.MAX_SAFE_INTEGER) {
throw errorIntegerOutOfRange
}
/* c8 ignore stop */
}
throw errorUnexpectedEndOfArray
};
/**
* Read signed integer (32bit) with variable length.
* 1/8th of the storage is used as encoding overhead.
* * numbers < 2^7 is stored in one bytlength
* * numbers < 2^14 is stored in two bylength
* @todo This should probably create the inverse ~num if number is negative - but this would be a breaking change.
*
* @function
* @param {Decoder} decoder
* @return {number} An unsigned integer.length
*/
const readVarInt = decoder => {
let r = decoder.arr[decoder.pos++];
let num = r & binary.BITS6;
let mult = 64;
const sign = (r & binary.BIT7) > 0 ? -1 : 1;
if ((r & binary.BIT8) === 0) {
// don't continue reading
return sign * num
}
const len = decoder.arr.length;
while (decoder.pos < len) {
r = decoder.arr[decoder.pos++];
// num = num | ((r & binary.BITS7) << len)
num = num + (r & binary.BITS7) * mult;
mult *= 128;
if (r < binary.BIT8) {
return sign * num
}
/* c8 ignore start */
if (num > number.MAX_SAFE_INTEGER) {
throw errorIntegerOutOfRange
}
/* c8 ignore stop */
}
throw errorUnexpectedEndOfArray
};
/**
* Look ahead and read varUint without incrementing position
*
* @function
* @param {Decoder} decoder
* @return {number}
*/
const peekVarUint = decoder => {
const pos = decoder.pos;
const s = readVarUint(decoder);
decoder.pos = pos;
return s
};
/**
* Look ahead and read varUint without incrementing position
*
* @function
* @param {Decoder} decoder
* @return {number}
*/
const peekVarInt = decoder => {
const pos = decoder.pos;
const s = readVarInt(decoder);
decoder.pos = pos;
return s
};
/**
* We don't test this function anymore as we use native decoding/encoding by default now.
* Better not modify this anymore..
*
* Transforming utf8 to a string is pretty expensive. The code performs 10x better
* when String.fromCodePoint is fed with all characters as arguments.
* But most environments have a maximum number of arguments per functions.
* For effiency reasons we apply a maximum of 10000 characters at once.
*
* @function
* @param {Decoder} decoder
* @return {String} The read String.
*/
/* c8 ignore start */
const _readVarStringPolyfill = decoder => {
let remainingLen = readVarUint(decoder);
if (remainingLen === 0) {
return ''
} else {
let encodedString = String.fromCodePoint(readUint8(decoder)); // remember to decrease remainingLen
if (--remainingLen < 100) { // do not create a Uint8Array for small strings
while (remainingLen--) {
encodedString += String.fromCodePoint(readUint8(decoder));
}
} else {
while (remainingLen > 0) {
const nextLen = remainingLen < 10000 ? remainingLen : 10000;
// this is dangerous, we create a fresh array view from the existing buffer
const bytes = decoder.arr.subarray(decoder.pos, decoder.pos + nextLen);
decoder.pos += nextLen;
// Starting with ES5.1 we can supply a generic array-like object as arguments
encodedString += String.fromCodePoint.apply(null, /** @type {any} */ (bytes));
remainingLen -= nextLen;
}
}
return decodeURIComponent(escape(encodedString))
}
};
/* c8 ignore stop */
/**
* @function
* @param {Decoder} decoder
* @return {String} The read String
*/
const _readVarStringNative = decoder =>
/** @type any */ (string.utf8TextDecoder).decode(readVarUint8Array(decoder));
/**
* Read string of variable length
* * varUint is used to store the length of the string
*
* @function
* @param {Decoder} decoder
* @return {String} The read String
*
*/
/* c8 ignore next */
const readVarString = string.utf8TextDecoder ? _readVarStringNative : _readVarStringPolyfill;
/**
* @param {Decoder} decoder
* @return {Uint8Array}
*/
const readTerminatedUint8Array = decoder => {
const encoder = createEncoder();
let b;
while (true) {
b = readUint8(decoder);
if (b === 0) {
return toUint8Array(encoder)
}
if (b === 1) {
b = readUint8(decoder);
}
write(encoder, b);
}
};
/**
* @param {Decoder} decoder
* @return {string}
*/
const readTerminatedString = decoder => string.decodeUtf8(readTerminatedUint8Array(decoder));
/**
* Look ahead and read varString without incrementing position
*
* @function
* @param {Decoder} decoder
* @return {string}
*/
const peekVarString = decoder => {
const pos = decoder.pos;
const s = readVarString(decoder);
decoder.pos = pos;
return s
};
/**
* @param {Decoder} decoder
* @param {number} len
* @return {DataView}
*/
const readFromDataView = (decoder, len) => {
const dv = new DataView(decoder.arr.buffer, decoder.arr.byteOffset + decoder.pos, len);
decoder.pos += len;
return dv
};
/**
* @param {Decoder} decoder
*/
const readFloat32 = decoder => readFromDataView(decoder, 4).getFloat32(0, false);
/**
* @param {Decoder} decoder
*/
const readFloat64 = decoder => readFromDataView(decoder, 8).getFloat64(0, false);
/**
* @param {Decoder} decoder
*/
const readBigInt64 = decoder => /** @type {any} */ (readFromDataView(decoder, 8)).getBigInt64(0, false);
/**
* @param {Decoder} decoder
*/
const readBigUint64 = decoder => /** @type {any} */ (readFromDataView(decoder, 8)).getBigUint64(0, false);
/**
* @type {Array<function(Decoder):any>}
*/
const readAnyLookupTable = [
decoder => undefined, // CASE 127: undefined
decoder => null, // CASE 126: null
readVarInt, // CASE 125: integer
readFloat32, // CASE 124: float32
readFloat64, // CASE 123: float64
readBigInt64, // CASE 122: bigint
decoder => false, // CASE 121: boolean (false)
decoder => true, // CASE 120: boolean (true)
readVarString, // CASE 119: string
decoder => { // CASE 118: object<string,any>
const len = readVarUint(decoder);
/**
* @type {Object<string,any>}
*/
const obj = {};
for (let i = 0; i < len; i++) {
const key = readVarString(decoder);
obj[key] = readAny(decoder);
}
return obj
},
decoder => { // CASE 117: array<any>
const len = readVarUint(decoder);
const arr = [];
for (let i = 0; i < len; i++) {
arr.push(readAny(decoder));
}
return arr
},
readVarUint8Array // CASE 116: Uint8Array
];
/**
* @param {Decoder} decoder
*/
const readAny = decoder => readAnyLookupTable[127 - readUint8(decoder)](decoder);
/**
* T must not be null.
*
* @template T
*/
class RleDecoder extends Decoder {
/**
* @param {Uint8Array} uint8Array
* @param {function(Decoder):T} reader
*/
constructor (uint8Array, reader) {
super(uint8Array);
/**
* The reader
*/
this.reader = reader;
/**
* Current state
* @type {T|null}
*/
this.s = null;
this.count = 0;
}
read () {
if (this.count === 0) {
this.s = this.reader(this);
if (hasContent(this)) {
this.count = readVarUint(this) + 1; // see encoder implementation for the reason why this is incremented
} else {
this.count = -1; // read the current value forever
}
}
this.count--;
return /** @type {T} */ (this.s)
}
}
class IntDiffDecoder extends Decoder {
/**
* @param {Uint8Array} uint8Array
* @param {number} start
*/
constructor (uint8Array, start) {
super(uint8Array);
/**
* Current state
* @type {number}
*/
this.s = start;
}
/**
* @return {number}
*/
read () {
this.s += readVarInt(this);
return this.s
}
}
class RleIntDiffDecoder extends Decoder {
/**
* @param {Uint8Array} uint8Array
* @param {number} start
*/
constructor (uint8Array, start) {
super(uint8Array);
/**
* Current state
* @type {number}
*/
this.s = start;
this.count = 0;
}
/**
* @return {number}
*/
read () {
if (this.count === 0) {
this.s += readVarInt(this);
if (hasContent(this)) {
this.count = readVarUint(this) + 1; // see encoder implementation for the reason why this is incremented
} else {
this.count = -1; // read the current value forever
}
}
this.count--;
return /** @type {number} */ (this.s)
}
}
class UintOptRleDecoder extends Decoder {
/**
* @param {Uint8Array} uint8Array
*/
constructor (uint8Array) {
super(uint8Array);
/**
* @type {number}
*/
this.s = 0;
this.count = 0;
}
read () {
if (this.count === 0) {
this.s = readVarInt(this);
// if the sign is negative, we read the count too, otherwise count is 1
const isNegative = math.isNegativeZero(this.s);
this.count = 1;
if (isNegative) {
this.s = -this.s;
this.count = readVarUint(this) + 2;
}
}
this.count--;
return /** @type {number} */ (this.s)
}
}
class IncUintOptRleDecoder extends Decoder {
/**
* @param {Uint8Array} uint8Array
*/
constructor (uint8Array) {
super(uint8Array);
/**
* @type {number}
*/
this.s = 0;
this.count = 0;
}
read () {
if (this.count === 0) {
this.s = readVarInt(this);
// if the sign is negative, we read the count too, otherwise count is 1
const isNegative = math.isNegativeZero(this.s);
this.count = 1;
if (isNegative) {
this.s = -this.s;
this.count = readVarUint(this) + 2;
}
}
this.count--;
return /** @type {number} */ (this.s++)
}
}
class IntDiffOptRleDecoder extends Decoder {
/**
* @param {Uint8Array} uint8Array
*/
constructor (uint8Array) {
super(uint8Array);
/**
* @type {number}
*/
this.s = 0;
this.count = 0;
this.diff = 0;
}
/**
* @return {number}
*/
read () {
if (this.count === 0) {
const diff = readVarInt(this);
// if the first bit is set, we read more data
const hasCount = diff & 1;
this.diff = math.floor(diff / 2); // shift >> 1
this.count = 1;
if (hasCount) {
this.count = readVarUint(this) + 2;
}
}
this.s += this.diff;
this.count--;
return this.s
}
}
class StringDecoder {
/**
* @param {Uint8Array} uint8Array
*/
constructor (uint8Array) {
this.decoder = new UintOptRleDecoder(uint8Array);
this.str = readVarString(this.decoder);
/**
* @type {number}
*/
this.spos = 0;
}
/**
* @return {string}
*/
read () {
const end = this.spos + this.decoder.read();
const res = this.str.slice(this.spos, end);
this.spos = end;
return res
}
}
var decoding = /*#__PURE__*/Object.freeze({
__proto__: null,
Decoder: Decoder,
createDecoder: createDecoder,
hasContent: hasContent,
clone: clone,
readUint8Array: readUint8Array,
readVarUint8Array: readVarUint8Array,
readTailAsUint8Array: readTailAsUint8Array,
skip8: skip8,
readUint8: readUint8,
readUint16: readUint16,
readUint32: readUint32,
readUint32BigEndian: readUint32BigEndian,
peekUint8: peekUint8,
peekUint16: peekUint16,
peekUint32: peekUint32,
readVarUint: readVarUint,
readVarInt: readVarInt,
peekVarUint: peekVarUint,
peekVarInt: peekVarInt,
_readVarStringPolyfill: _readVarStringPolyfill,
_readVarStringNative: _readVarStringNative,
readVarString: readVarString,
readTerminatedUint8Array: readTerminatedUint8Array,
readTerminatedString: readTerminatedString,
peekVarString: peekVarString,
readFromDataView: readFromDataView,
readFloat32: readFloat32,
readFloat64: readFloat64,
readBigInt64: readBigInt64,
readBigUint64: readBigUint64,
readAny: readAny,
RleDecoder: RleDecoder,
IntDiffDecoder: IntDiffDecoder,
RleIntDiffDecoder: RleIntDiffDecoder,
UintOptRleDecoder: UintOptRleDecoder,
IncUintOptRleDecoder: IncUintOptRleDecoder,
IntDiffOptRleDecoder: IntDiffOptRleDecoder,
StringDecoder: StringDecoder
});
/**
* Utility functions to work with buffers (Uint8Array).
*
* @module buffer
*/
/**
* @param {number} len
*/
const createUint8ArrayFromLen = len => new Uint8Array(len);
/**
* Create Uint8Array with initial content from buffer
*
* @param {ArrayBuffer} buffer
* @param {number} byteOffset
* @param {number} length
*/
const createUint8ArrayViewFromArrayBuffer = (buffer, byteOffset, length) => new Uint8Array(buffer, byteOffset, length);
/**
* Create Uint8Array with initial content from buffer
*
* @param {ArrayBuffer} buffer
*/
const createUint8ArrayFromArrayBuffer = buffer => new Uint8Array(buffer);
/* c8 ignore start */
/**
* @param {Uint8Array} bytes
* @return {string}
*/
const toBase64Browser = bytes => {
let s = '';
for (let i = 0; i < bytes.byteLength; i++) {
s += string.fromCharCode(bytes[i]);
}
// eslint-disable-next-line no-undef
return btoa(s)
};
/* c8 ignore stop */
/**
* @param {Uint8Array} bytes
* @return {string}
*/
const toBase64Node = bytes => Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString('base64');
/* c8 ignore start */
/**
* @param {string} s
* @return {Uint8Array}
*/
const fromBase64Browser = s => {
// eslint-disable-next-line no-undef
const a = atob(s);
const bytes = createUint8ArrayFromLen(a.length);
for (let i = 0; i < a.length; i++) {
bytes[i] = a.charCodeAt(i);
}
return bytes
};
/* c8 ignore stop */
/**
* @param {string} s
*/
const fromBase64Node = s => {
const buf = Buffer.from(s, 'base64');
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength)
};
/* c8 ignore next */
const toBase64 = environment.isBrowser ? toBase64Browser : toBase64Node;
/* c8 ignore next */
const fromBase64 = environment.isBrowser ? fromBase64Browser : fromBase64Node;
/**
* Implements base64url - see https://datatracker.ietf.org/doc/html/rfc4648#section-5
* @param {Uint8Array} buf
*/
const toBase64UrlEncoded = buf => toBase64(buf).replaceAll('+', '-').replaceAll('/', '_').replaceAll('=', '');
/**
* @param {string} base64
*/
const fromBase64UrlEncoded = base64 => fromBase64(base64.replaceAll('-', '+').replaceAll('_', '/'));
/**
* Base64 is always a more efficient choice. This exists for utility purposes only.
*
* @param {Uint8Array} buf
*/
const toHexString = buf => array.map(buf, b => b.toString(16).padStart(2, '0')).join('');
/**
* Note: This function expects that the hex doesn't start with 0x..
*
* @param {string} hex
*/
const fromHexString = hex => {
const hlen = hex.length;
const buf = new Uint8Array(math.ceil(hlen / 2));
for (let i = 0; i < hlen; i += 2) {
buf[buf.length - i / 2 - 1] = Number.parseInt(hex.slice(hlen - i - 2, hlen - i), 16);
}
return buf
};
/**
* Copy the content of an Uint8Array view to a new ArrayBuffer.
*
* @param {Uint8Array} uint8Array
* @return {Uint8Array}
*/
const copyUint8Array = uint8Array => {
const newBuf = createUint8ArrayFromLen(uint8Array.byteLength);
newBuf.set(uint8Array);
return newBuf
};
/**
* Encode anything as a UInt8Array. It's a pun on typescripts's `any` type.
* See encoding.writeAny for more information.
*
* @param {any} data
* @return {Uint8Array}
*/
const encodeAny = data => {
const encoder = createEncoder();
writeAny(encoder, data);
return toUint8Array(encoder)
};
/**
* Decode an any-encoded value.
*
* @param {Uint8Array} buf
* @return {any}
*/
const decodeAny = buf => readAny(createDecoder(buf));
/**
* Shift Byte Array {N} bits to the left. Does not expand byte array.
*
* @param {Uint8Array} bs
* @param {number} N should be in the range of [0-7]
*/
const shiftNBitsLeft = (bs, N) => {
if (N === 0) return bs
bs = new Uint8Array(bs);
bs[0] <<= N;
for (let i = 1; i < bs.length; i++) {
bs[i - 1] |= bs[i] >>> (8 - N);
bs[i] <<= N;
}
return bs
};
var buffer = /*#__PURE__*/Object.freeze({
__proto__: null,
createUin