@typeberry/trie
Advanced tools
Comparing version
{ | ||
"name": "@typeberry/trie", | ||
"version": "0.0.1-46c9206", | ||
"version": "0.0.1-92a540f", | ||
"main": "trie.js", | ||
@@ -5,0 +5,0 @@ "author": "Fluffy Labs", |
@@ -0,1 +1,7 @@ | ||
/** | ||
* A variable-length blob of bytes with a concise text representation. | ||
* | ||
* The structure is used as convenience wrapper for [`Uint8Array`], | ||
* especially if the data is coming from a hex-encoded string. | ||
*/ | ||
export declare class BytesBlob { | ||
@@ -5,18 +11,38 @@ readonly buffer: Uint8Array; | ||
private constructor(); | ||
/** | ||
* Display a hex-encoded version of this byte blob. | ||
*/ | ||
toString(): string; | ||
/** Create a new [`BytesBlob`] from existing [`Uint8Array`]. */ | ||
static fromBlob(v: Uint8Array): BytesBlob; | ||
/** Create a new [`BytesBlob`] from an array of bytes. */ | ||
static fromNumbers(v: number[]): BytesBlob; | ||
/** Parse a hex-encoded bytes blob without `0x` prefix. */ | ||
static parseBlobNoPrefix(v: string): BytesBlob; | ||
/** Parse a hex-encoded bytes blob with `0x` prefix. */ | ||
static parseBlob(v: string): BytesBlob; | ||
} | ||
/** | ||
* A convenience wrapper for a fix-length sequence of bytes. | ||
*/ | ||
export declare class Bytes<T extends number> { | ||
/** Raw bytes array. */ | ||
readonly raw: Uint8Array; | ||
/** Length of the bytes array. */ | ||
readonly length: T; | ||
private constructor(); | ||
/** Return hex encoding of the sequence. */ | ||
toString(): string; | ||
/** Compare the sequence to another one. */ | ||
isEqualTo(other: Bytes<T>): boolean; | ||
/** Create new [`Bytes<X>`] given a backing buffer and it's length. */ | ||
static fromBlob<X extends number>(v: Uint8Array, len: X): Bytes<X>; | ||
/** Create an empty [`Bytes<X>`] of given length. */ | ||
static zero<X extends number>(len: X): Bytes<X>; | ||
/** Create a [`Bytes<X>`] with all bytes filled with given input number. */ | ||
static fill<X extends number>(len: X, input: number): Bytes<X>; | ||
/** Parse a hex-encoded fixed-length bytes without `0x` prefix. */ | ||
static parseBytesNoPrefix<X extends number>(v: string, len: X): Bytes<X>; | ||
/** Parse a hex-encoded fixed-length bytes with `0x` prefix. */ | ||
static parseBytes<X extends number>(v: string, len: X): Bytes<X>; | ||
} |
86
trie.js
@@ -16,10 +16,8 @@ 'use strict'; | ||
function bytesToHexString(buffer) { | ||
// TODO [ToDr] consider using TextDecoder API? | ||
let s = "0x"; | ||
for (const v of buffer) { | ||
s += v.toString(16).padStart(2, "0"); | ||
} | ||
return s; | ||
} | ||
/** | ||
* A variable-length blob of bytes with a concise text representation. | ||
* | ||
* The structure is used as convenience wrapper for [`Uint8Array`], | ||
* especially if the data is coming from a hex-encoded string. | ||
*/ | ||
class BytesBlob { | ||
@@ -32,12 +30,19 @@ constructor(data) { | ||
} | ||
/** | ||
* Display a hex-encoded version of this byte blob. | ||
*/ | ||
toString() { | ||
return bytesToHexString(this.buffer); | ||
} | ||
/** Create a new [`BytesBlob`] from existing [`Uint8Array`]. */ | ||
static fromBlob(v) { | ||
return new BytesBlob(v); | ||
} | ||
/** Create a new [`BytesBlob`] from an array of bytes. */ | ||
static fromNumbers(v) { | ||
check(v.find((x) => (x & 0xff) !== x) === undefined, "BytesBlob.fromNumbers used with non-byte number array."); | ||
const arr = new Uint8Array(v); | ||
return new BytesBlob(arr); | ||
} | ||
/** Parse a hex-encoded bytes blob without `0x` prefix. */ | ||
static parseBlobNoPrefix(v) { | ||
@@ -48,3 +53,2 @@ const len = v.length; | ||
} | ||
// NOTE [ToDr] alloc | ||
const buffer = new ArrayBuffer(len / 2); | ||
@@ -54,12 +58,7 @@ const bytes = new Uint8Array(buffer); | ||
const c = v.substring(i, i + 2); | ||
// TODO [ToDr] [opti] Remove string concat and simply parse each nibble manually | ||
// (switch from 0..f) | ||
const parsed = Number(`0x${c}`); | ||
if (Number.isNaN(parsed)) { | ||
throw new Error(`Invalid characters in hex byte string: ${c}`); | ||
} | ||
bytes[i / 2] = parsed; | ||
bytes[i / 2] = byteFromString(c); | ||
} | ||
return new BytesBlob(bytes); | ||
} | ||
/** Parse a hex-encoded bytes blob with `0x` prefix. */ | ||
static parseBlob(v) { | ||
@@ -72,2 +71,5 @@ if (!v.startsWith("0x")) { | ||
} | ||
/** | ||
* A convenience wrapper for a fix-length sequence of bytes. | ||
*/ | ||
class Bytes { | ||
@@ -79,5 +81,7 @@ constructor(raw, len) { | ||
} | ||
/** Return hex encoding of the sequence. */ | ||
toString() { | ||
return bytesToHexString(this.raw); | ||
} | ||
/** Compare the sequence to another one. */ | ||
isEqualTo(other) { | ||
@@ -94,8 +98,18 @@ if (this.length !== other.length) { | ||
} | ||
/** Create new [`Bytes<X>`] given a backing buffer and it's length. */ | ||
static fromBlob(v, len) { | ||
return new Bytes(v, len); | ||
} | ||
/** Create an empty [`Bytes<X>`] of given length. */ | ||
static zero(len) { | ||
return new Bytes(new Uint8Array(len), len); | ||
} | ||
/** Create a [`Bytes<X>`] with all bytes filled with given input number. */ | ||
static fill(len, input) { | ||
check((input & 0xff) === input, "Input has to be a byte."); | ||
const bytes = Bytes.zero(len); | ||
bytes.raw.fill(input, 0, len); | ||
return bytes; | ||
} | ||
/** Parse a hex-encoded fixed-length bytes without `0x` prefix. */ | ||
static parseBytesNoPrefix(v, len) { | ||
@@ -108,2 +122,3 @@ if (v.length > 2 * len) { | ||
} | ||
/** Parse a hex-encoded fixed-length bytes with `0x` prefix. */ | ||
static parseBytes(v, len) { | ||
@@ -117,2 +132,41 @@ if (v.length > 2 * len + 2) { | ||
} | ||
function byteFromString(s) { | ||
check(s.length === 2, "Two-character string expected"); | ||
const a = numberFromCharCode(s.charCodeAt(0)); | ||
const b = numberFromCharCode(s.charCodeAt(1)); | ||
return (a << 4) | b; | ||
} | ||
const CODE_OF_0 = "0".charCodeAt(0); | ||
const CODE_OF_9 = "9".charCodeAt(0); | ||
const CODE_OF_a = "a".charCodeAt(0); | ||
const CODE_OF_f = "f".charCodeAt(0); | ||
const CODE_OF_A = "A".charCodeAt(0); | ||
const CODE_OF_F = "F".charCodeAt(0); | ||
const VALUE_OF_A = 0xa; | ||
function numberFromCharCode(x) { | ||
if (x >= CODE_OF_0 && x <= CODE_OF_9) { | ||
return x - CODE_OF_0; | ||
} | ||
if (x >= CODE_OF_a && x <= CODE_OF_f) { | ||
return x - CODE_OF_a + VALUE_OF_A; | ||
} | ||
if (x >= CODE_OF_A && x <= CODE_OF_F) { | ||
return x - CODE_OF_A + VALUE_OF_A; | ||
} | ||
throw new Error(`Invalid characters in hex byte string: ${String.fromCharCode(x)}`); | ||
} | ||
function bytesToHexString(buffer) { | ||
const nibbleToString = (n) => { | ||
if (n >= VALUE_OF_A) { | ||
return String.fromCharCode(n + CODE_OF_a - VALUE_OF_A); | ||
} | ||
return String.fromCharCode(n + CODE_OF_0); | ||
}; | ||
let s = "0x"; | ||
for (const v of buffer) { | ||
s += nibbleToString(v >>> 4); | ||
s += nibbleToString(v & 0xf); | ||
} | ||
return s; | ||
} | ||
@@ -119,0 +173,0 @@ /** |
35353
10.22%957
9.12%