mirror of
https://github.com/pezkuwichain/pezkuwi-common.git
synced 2026-04-27 17:28:01 +00:00
Initial rebrand: @polkadot -> @pezkuwi (14 packages)
- Package namespace: @polkadot/* -> @pezkuwi/* - Repository: polkadot-js/common -> pezkuwichain/pezkuwi-common - Author: Pezkuwi Team <team@pezkuwichain.io> Core packages: - @pezkuwi/util (utilities) - @pezkuwi/util-crypto (crypto primitives) - @pezkuwi/keyring (account management) - @pezkuwi/networks (chain metadata) - @pezkuwi/hw-ledger (Ledger hardware wallet) - @pezkuwi/x-* (10 polyfill packages) Total: 14 packages Upstream: polkadot-js/common v14.0.1
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/// <reference types="@polkadot/dev-test/globals.d.ts" />
|
||||
|
||||
import { perf } from '../test/index.js';
|
||||
import { u8aCmp } from './index.js';
|
||||
|
||||
const ltest = new Uint8Array(32768);
|
||||
const stest = new Uint8Array(256);
|
||||
const ztest = new Uint8Array(64);
|
||||
|
||||
for (let i = 0, count = ltest.length; i < count; i++) {
|
||||
if (i < ztest.length) {
|
||||
ztest[i] = i % 256;
|
||||
}
|
||||
|
||||
if (i < stest.length) {
|
||||
stest[i] = i % 256;
|
||||
}
|
||||
|
||||
ltest[i] = i % 256;
|
||||
}
|
||||
|
||||
describe('u8aCmp', (): void => {
|
||||
it('has the same result as localCompare (equal length)', (): void => {
|
||||
const a = 'test abc';
|
||||
const b = 'test def';
|
||||
|
||||
expect(
|
||||
u8aCmp(a, b)
|
||||
).toEqual(a.localeCompare(b));
|
||||
expect(
|
||||
u8aCmp(b, a)
|
||||
).toEqual(b.localeCompare(a));
|
||||
});
|
||||
|
||||
it('has the same result as localCompare (diff length)', (): void => {
|
||||
const a = 'test';
|
||||
const b = 'test abc';
|
||||
|
||||
expect(
|
||||
u8aCmp(a, b)
|
||||
).toEqual(a.localeCompare(b));
|
||||
expect(
|
||||
u8aCmp(b, a)
|
||||
).toEqual(b.localeCompare(a));
|
||||
});
|
||||
|
||||
it('compares between string and Uint8Array', (): void => {
|
||||
expect(
|
||||
u8aCmp(
|
||||
'0x12345678',
|
||||
new Uint8Array([0x12, 0x34, 0x56, 0x78])
|
||||
)
|
||||
).toEqual(0);
|
||||
});
|
||||
|
||||
perf('u8aCmp (64 cmp)', 100_000, [[ztest, ztest]], u8aCmp);
|
||||
perf('u8aCmp (256 cmp)', 50_000, [[stest, stest]], u8aCmp);
|
||||
perf('u8aCmp (32k cmp)', 500, [[ltest, ltest]], u8aCmp);
|
||||
});
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { u8aToU8a } from './toU8a.js';
|
||||
|
||||
/**
|
||||
* @name u8aCmp
|
||||
* @summary Compares two Uint8Arrays for sorting.
|
||||
* @description
|
||||
* For `UInt8Array` (or hex string) input values returning -1, 0 or +1
|
||||
* @example
|
||||
* <BR>
|
||||
*
|
||||
* ```javascript
|
||||
* import { u8aCmp } from '@pezkuwi/util';
|
||||
*
|
||||
* u8aCmp(new Uint8Array([0x67, 0x65]), new Uint8Array([0x68, 0x65])); // -1
|
||||
* u8aCmp(new Uint8Array([0x68, 0x65]), new Uint8Array([0x68, 0x65])); // 0
|
||||
* u8aCmp(new Uint8Array([0x69, 0x65]), new Uint8Array([0x68, 0x65])); // +1
|
||||
* ```
|
||||
*/
|
||||
export function u8aCmp (a: string | Uint8Array, b: string | Uint8Array): number {
|
||||
const u8aa = u8aToU8a(a);
|
||||
const u8ab = u8aToU8a(b);
|
||||
let i = 0;
|
||||
|
||||
while (true) {
|
||||
const overA = i >= u8aa.length;
|
||||
const overB = i >= u8ab.length;
|
||||
|
||||
if (overA && overB) {
|
||||
// both ends reached
|
||||
return 0;
|
||||
} else if (overA) {
|
||||
// a has no more data, b has data
|
||||
return -1;
|
||||
} else if (overB) {
|
||||
// b has no more data, a has data
|
||||
return 1;
|
||||
} else if (u8aa[i] !== u8ab[i]) {
|
||||
// the number in this index doesn't match
|
||||
// (we don't use u8aa[i] - u8ab[i] since that doesn't match with localeCompare)
|
||||
return u8aa[i] > u8ab[i]
|
||||
? 1
|
||||
: -1;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/// <reference types="@polkadot/dev-test/globals.d.ts" />
|
||||
|
||||
import { getRandomValues } from '@pezkuwi/x-randomvalues';
|
||||
|
||||
import { arrayRange } from '../array/index.js';
|
||||
import { perf } from '../test/index.js';
|
||||
import { u8aConcat, u8aConcatStrict } from './index.js';
|
||||
|
||||
const ptest = arrayRange(10).map(() => getRandomValues(new Uint8Array(32)));
|
||||
|
||||
describe('u8aConcat', (): void => {
|
||||
it('concatenates arrays', (): void => {
|
||||
expect(
|
||||
u8aConcat(
|
||||
new Uint8Array([1, 2, 3, 4]),
|
||||
new Uint8Array([5, 6]),
|
||||
new Uint8Array([7, 8, 9])
|
||||
)
|
||||
).toEqual(
|
||||
new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9])
|
||||
);
|
||||
});
|
||||
|
||||
it('concatenates arrays & hex values', (): void => {
|
||||
expect(
|
||||
u8aConcat(
|
||||
new Uint8Array([1, 2, 3, 4]),
|
||||
'0x0506',
|
||||
'0x070809'
|
||||
)
|
||||
).toEqual(
|
||||
new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9])
|
||||
);
|
||||
});
|
||||
|
||||
perf('u8aConcat', 10000, [[ptest]], u8aConcat);
|
||||
perf('u8aConcatStrict', 10000, [[[ptest]]], u8aConcatStrict);
|
||||
perf('u8aConcatStrict (len)', 10000, [[[ptest], 320]], u8aConcatStrict);
|
||||
});
|
||||
@@ -0,0 +1,60 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { U8aLike } from '../types.js';
|
||||
|
||||
import { u8aToU8a } from './toU8a.js';
|
||||
|
||||
/**
|
||||
* @name u8aConcat
|
||||
* @summary Creates a concatenated Uint8Array from the inputs.
|
||||
* @description
|
||||
* Concatenates the input arrays into a single `UInt8Array`.
|
||||
* @example
|
||||
* <BR>
|
||||
*
|
||||
* ```javascript
|
||||
* import { { u8aConcat } from '@pezkuwi/util';
|
||||
*
|
||||
* u8aConcat(
|
||||
* new Uint8Array([1, 2, 3]),
|
||||
* new Uint8Array([4, 5, 6])
|
||||
* ); // [1, 2, 3, 4, 5, 6]
|
||||
* ```
|
||||
*/
|
||||
export function u8aConcat (...list: readonly U8aLike[]): Uint8Array {
|
||||
const count = list.length;
|
||||
const u8as = new Array<Uint8Array>(count);
|
||||
let length = 0;
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
u8as[i] = u8aToU8a(list[i]);
|
||||
length += u8as[i].length;
|
||||
}
|
||||
|
||||
return u8aConcatStrict(u8as, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name u8aConcatStrict
|
||||
* @description A strict version of [[u8aConcat]], accepting only Uint8Array inputs
|
||||
*/
|
||||
export function u8aConcatStrict (u8as: readonly Uint8Array[], length = 0): Uint8Array {
|
||||
const count = u8as.length;
|
||||
let offset = 0;
|
||||
|
||||
if (!length) {
|
||||
for (let i = 0; i < count; i++) {
|
||||
length += u8as[i].length;
|
||||
}
|
||||
}
|
||||
|
||||
const result = new Uint8Array(length);
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
result.set(u8as[i], offset);
|
||||
offset += u8as[i].length;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { U8aLike } from '../types.js';
|
||||
|
||||
import { u8aToU8a } from './toU8a.js';
|
||||
|
||||
/**
|
||||
* @name u8aConcat
|
||||
* @summary Creates a concatenated Uint8Array from the inputs.
|
||||
* @description
|
||||
* Concatenates the input arrays into a single `UInt8Array`.
|
||||
* @example
|
||||
* <BR>
|
||||
*
|
||||
* ```javascript
|
||||
* import { { u8aConcat } from '@pezkuwi/util';
|
||||
*
|
||||
* u8aConcat(
|
||||
* new Uint8Array([1, 2, 3]),
|
||||
* new Uint8Array([4, 5, 6])
|
||||
* ); // [1, 2, 3, 4, 5, 6]
|
||||
* ```
|
||||
*/
|
||||
export function u8aConcat (...list: readonly U8aLike[]): Uint8Array {
|
||||
const count = list.length;
|
||||
const u8as = new Array<Uint8Array>(count);
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
u8as[i] = u8aToU8a(list[i]);
|
||||
}
|
||||
|
||||
return Uint8Array.from(Buffer.concat(u8as));
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/// <reference types="@polkadot/dev-test/globals.d.ts" />
|
||||
|
||||
import { perf } from '../test/index.js';
|
||||
import { u8aEmpty } from './index.js';
|
||||
|
||||
describe('u8aEmpty', (): void => {
|
||||
it('returns true on zero length', (): void => {
|
||||
expect(
|
||||
u8aEmpty(new Uint8Array())
|
||||
).toEqual(true);
|
||||
});
|
||||
|
||||
it('returns true on all zero values', (): void => {
|
||||
expect(
|
||||
u8aEmpty(new Uint8Array([0, 0, 0, 0, 0, 0]))
|
||||
).toEqual(true);
|
||||
});
|
||||
|
||||
it('returns false when value is found', (): void => {
|
||||
expect(
|
||||
u8aEmpty(new Uint8Array([0, 0, 0, 0, 0, 1]))
|
||||
).toEqual(false);
|
||||
});
|
||||
|
||||
it('returns false when value is found (256)', (): void => {
|
||||
const test = new Uint8Array(256);
|
||||
|
||||
expect(
|
||||
u8aEmpty(test)
|
||||
).toEqual(true);
|
||||
|
||||
test[128] = 1;
|
||||
|
||||
expect(
|
||||
u8aEmpty(test)
|
||||
).toEqual(false);
|
||||
});
|
||||
|
||||
perf('u8aEmpty (32 cmp)', 1_000_000, [[new Uint8Array(32)]], u8aEmpty);
|
||||
perf('u8aEmpty (64 cmp)', 500_000, [[new Uint8Array(64)]], u8aEmpty);
|
||||
perf('u8aEmpty (128 cmp)', 250_000, [[new Uint8Array(128)]], u8aEmpty);
|
||||
perf('u8aEmpty (256 cmp)', 125_000, [[new Uint8Array(256)]], u8aEmpty);
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/**
|
||||
* @name u8aEmpty
|
||||
* @summary Tests for a `Uint8Array` for emptyness
|
||||
* @description
|
||||
* Checks to see if the input `Uint8Array` has zero length or contains all 0 values.
|
||||
*/
|
||||
export function u8aEmpty (value: Uint8Array): boolean {
|
||||
const len = value.length | 0;
|
||||
|
||||
// on smaller sizes, the byte-by-byte compare is faster than allocating
|
||||
// another object for DataView (on very large arrays the DataView is faster)
|
||||
for (let i = 0; i < len; i++) {
|
||||
if (value[i] | 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/// <reference types="@polkadot/dev-test/globals.d.ts" />
|
||||
|
||||
import { perf } from '../test/index.js';
|
||||
import { u8aEq } from './index.js';
|
||||
|
||||
const ltest = new Uint8Array(32768);
|
||||
const stest = new Uint8Array(256);
|
||||
const ztest = new Uint8Array(64);
|
||||
|
||||
for (let i = 0, count = ltest.length; i < count; i++) {
|
||||
if (i < ztest.length) {
|
||||
ztest[i] = i % 256;
|
||||
}
|
||||
|
||||
if (i < stest.length) {
|
||||
stest[i] = i % 256;
|
||||
}
|
||||
|
||||
ltest[i] = i % 256;
|
||||
}
|
||||
|
||||
describe('u8aEq', (): void => {
|
||||
it('returns false when the lengths do not match', (): void => {
|
||||
expect(
|
||||
u8aEq(
|
||||
new Uint8Array([1, 2, 3]),
|
||||
new Uint8Array([1, 2])
|
||||
)
|
||||
).toEqual(false);
|
||||
});
|
||||
|
||||
it('returns false when the contents do not match', (): void => {
|
||||
expect(
|
||||
u8aEq(
|
||||
new Uint8Array([1, 2, 3]),
|
||||
new Uint8Array([1, 2, 4])
|
||||
)
|
||||
).toEqual(false);
|
||||
});
|
||||
|
||||
it('returns true when the contents do match', (): void => {
|
||||
expect(
|
||||
u8aEq(
|
||||
new Uint8Array([1, 2, 3]),
|
||||
new Uint8Array([1, 2, 3])
|
||||
)
|
||||
).toEqual(true);
|
||||
});
|
||||
|
||||
it('returns false when the contents do not match (with u32 start)', (): void => {
|
||||
expect(
|
||||
u8aEq(
|
||||
new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3]),
|
||||
new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 4])
|
||||
)
|
||||
).toEqual(false);
|
||||
});
|
||||
|
||||
it('returns true when the contents do match (with u32 start)', (): void => {
|
||||
expect(
|
||||
u8aEq(
|
||||
new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3]),
|
||||
new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3])
|
||||
)
|
||||
).toEqual(true);
|
||||
});
|
||||
|
||||
it('returns false when the contents do not match (u32 only)', (): void => {
|
||||
expect(
|
||||
u8aEq(
|
||||
new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]),
|
||||
new Uint8Array([1, 2, 3, 4, 5, 6, 7, 9])
|
||||
)
|
||||
).toEqual(false);
|
||||
});
|
||||
|
||||
it('returns true when the contents do match (u32 only)', (): void => {
|
||||
expect(
|
||||
u8aEq(
|
||||
new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]),
|
||||
new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8])
|
||||
)
|
||||
).toEqual(true);
|
||||
});
|
||||
|
||||
it('returns true with equalvalent hex & Uint8array', (): void => {
|
||||
expect(
|
||||
u8aEq(
|
||||
'0x010203',
|
||||
new Uint8Array([1, 2, 3])
|
||||
)
|
||||
).toEqual(true);
|
||||
});
|
||||
|
||||
it('works on aubarray values', (): void => {
|
||||
const a = new Uint8Array(16);
|
||||
|
||||
for (let i = 0, count = a.length; i < count; i++) {
|
||||
a[i] = i;
|
||||
}
|
||||
|
||||
expect(
|
||||
u8aEq(a.subarray(0, 5), a.subarray(0, 5))
|
||||
).toEqual(true);
|
||||
});
|
||||
|
||||
perf('u8aEq (64 cmp)', 200_000, [[ztest, ztest]], u8aEq);
|
||||
perf('u8aEq (256 cmp)', 200_000, [[stest, stest]], u8aEq);
|
||||
perf('u8aEq (32k cmp)', 10_000, [[ltest, ltest]], u8aEq);
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { u8aToU8a } from './toU8a.js';
|
||||
|
||||
/**
|
||||
* @name u8aEq
|
||||
* @summary Compares two Uint8Arrays for equality.
|
||||
* @description
|
||||
* For `UInt8Array` (or hex string) input values true if there is a match.
|
||||
* @example
|
||||
* <BR>
|
||||
*
|
||||
* ```javascript
|
||||
* import { u8aEq } from '@pezkuwi/util';
|
||||
*
|
||||
* u8aEq(new Uint8Array([0x68, 0x65]), new Uint8Array([0x68, 0x65])); // true
|
||||
* ```
|
||||
*/
|
||||
export function u8aEq (a: string | Uint8Array, b: string | Uint8Array): boolean {
|
||||
const u8aa = u8aToU8a(a);
|
||||
const u8ab = u8aToU8a(b);
|
||||
|
||||
if (u8aa.length === u8ab.length) {
|
||||
const dvA = new DataView(u8aa.buffer, u8aa.byteOffset);
|
||||
const dvB = new DataView(u8ab.buffer, u8ab.byteOffset);
|
||||
const mod = (u8aa.length % 4) | 0;
|
||||
const length = (u8aa.length - mod) | 0;
|
||||
|
||||
for (let i = 0; i < length; i += 4) {
|
||||
if (dvA.getUint32(i) !== dvB.getUint32(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = length, count = u8aa.length; i < count; i++) {
|
||||
if (u8aa[i] !== u8ab[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/// <reference types="@polkadot/dev-test/globals.d.ts" />
|
||||
|
||||
import { u8aFixLength } from './index.js';
|
||||
|
||||
describe('u8aFixLength', (): void => {
|
||||
it('returns bitLength === -1 as-is', (): void => {
|
||||
expect(
|
||||
u8aFixLength(
|
||||
new Uint8Array([0x12, 0x34, 0x56, 0x78])
|
||||
)
|
||||
).toEqual(new Uint8Array([0x12, 0x34, 0x56, 0x78]));
|
||||
});
|
||||
|
||||
it('does not change when bitlength === length', (): void => {
|
||||
expect(
|
||||
u8aFixLength(new Uint8Array([0x12, 0x34, 0x56, 0x78]), 32)
|
||||
).toEqual(new Uint8Array([0x12, 0x34, 0x56, 0x78]));
|
||||
});
|
||||
|
||||
it('trims values when bitLength > length', (): void => {
|
||||
expect(
|
||||
u8aFixLength(new Uint8Array([0x12, 0x34, 0x56, 0x78]), 16)
|
||||
).toEqual(new Uint8Array([0x12, 0x34]));
|
||||
});
|
||||
|
||||
it('adds zeros when bitLength < length (withPadded)', (): void => {
|
||||
expect(
|
||||
u8aFixLength(new Uint8Array([0x12, 0x34]), 32)
|
||||
).toEqual(new Uint8Array([0, 0, 0x12, 0x34]));
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/**
|
||||
* @name u8aFixLength
|
||||
* @summary Shifts a Uint8Array to a specific bitLength
|
||||
* @description
|
||||
* Returns a uint8Array with the specified number of bits contained in the return value. (If bitLength is -1, length checking is not done). Values with more bits are trimmed to the specified length.
|
||||
* @example
|
||||
* <BR>
|
||||
*
|
||||
* ```javascript
|
||||
* import { u8aFixLength } from '@pezkuwi/util';
|
||||
*
|
||||
* u8aFixLength('0x12') // => 0x12
|
||||
* u8aFixLength('0x12', 16) // => 0x0012
|
||||
* u8aFixLength('0x1234', 8) // => 0x12
|
||||
* ```
|
||||
*/
|
||||
export function u8aFixLength (value: Uint8Array, bitLength = -1, atStart = false): Uint8Array {
|
||||
const byteLength = Math.ceil(bitLength / 8);
|
||||
|
||||
if (bitLength === -1 || value.length === byteLength) {
|
||||
return value;
|
||||
} else if (value.length > byteLength) {
|
||||
return value.subarray(0, byteLength);
|
||||
}
|
||||
|
||||
const result = new Uint8Array(byteLength);
|
||||
|
||||
result.set(value, atStart ? 0 : (byteLength - value.length));
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/**
|
||||
* @summary Utility methods to convert to and from `Uint8Array` objects
|
||||
*/
|
||||
|
||||
export { u8aCmp } from './cmp.js';
|
||||
export { u8aConcat, u8aConcatStrict } from './concat.js';
|
||||
export { u8aEmpty } from './empty.js';
|
||||
export { u8aEq } from './eq.js';
|
||||
export { u8aFixLength } from './fixLength.js';
|
||||
export { u8aSorted } from './sorted.js';
|
||||
export { u8aToBigInt } from './toBigInt.js';
|
||||
export { u8aToBn } from './toBn.js';
|
||||
export { u8aToBuffer } from './toBuffer.js';
|
||||
export { u8aToFloat } from './toFloat.js';
|
||||
export { u8aToHex } from './toHex.js';
|
||||
export { u8aToNumber } from './toNumber.js';
|
||||
export { u8aToString } from './toString.js';
|
||||
export { u8aToU8a } from './toU8a.js';
|
||||
export { U8A_WRAP_ETHEREUM, U8A_WRAP_POSTFIX, U8A_WRAP_PREFIX, u8aIsWrapped, u8aUnwrapBytes, u8aWrapBytes } from './wrap.js';
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/// <reference types="@polkadot/dev-test/globals.d.ts" />
|
||||
|
||||
import { u8aSorted } from './index.js';
|
||||
|
||||
describe('u8aSorted', (): void => {
|
||||
it('sorts a simple set of u8a', (): void => {
|
||||
expect(
|
||||
u8aSorted([new Uint8Array([1, 2, 3]), new Uint8Array([4, 5, 6]), new Uint8Array([2, 3, 4])])
|
||||
).toEqual([new Uint8Array([1, 2, 3]), new Uint8Array([2, 3, 4]), new Uint8Array([4, 5, 6])]);
|
||||
});
|
||||
|
||||
it('sorts a simple set of u8a (not the same lengths)', (): void => {
|
||||
expect(
|
||||
u8aSorted([new Uint8Array([1, 2, 3, 4]), new Uint8Array([4, 5, 6]), new Uint8Array([1, 2, 3, 5])])
|
||||
).toEqual([new Uint8Array([1, 2, 3, 4]), new Uint8Array([1, 2, 3, 5]), new Uint8Array([4, 5, 6])]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { u8aCmp } from './cmp.js';
|
||||
|
||||
/**
|
||||
* @name u8aSorted
|
||||
* @summary Sorts an array of Uint8Arrays
|
||||
* @description
|
||||
* For input `UInt8Array[]` return the sorted result
|
||||
* @example
|
||||
* <BR>
|
||||
*
|
||||
* ```javascript
|
||||
* import { u8aSorted} from '@pezkuwi/util';
|
||||
*
|
||||
* u8aSorted([new Uint8Array([0x69]), new Uint8Array([0x68])]); // [0x68, 0x69]
|
||||
* ```
|
||||
*/
|
||||
export function u8aSorted (u8as: Uint8Array[]): Uint8Array[] {
|
||||
return u8as.sort(u8aCmp);
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/// <reference types="@polkadot/dev-test/globals.d.ts" />
|
||||
|
||||
import { TESTS } from '../bi/toU8a.spec.js';
|
||||
import { perf } from '../test/index.js';
|
||||
import { u8aToBigInt } from './index.js';
|
||||
|
||||
// test-cases are the same as in u8aToBn
|
||||
describe('u8aToBigInt', (): void => {
|
||||
it('converts little-endian by default', (): void => {
|
||||
expect(
|
||||
u8aToBigInt(
|
||||
new Uint8Array([0x12, 0x34])
|
||||
).toString(16)
|
||||
).toBe('3412');
|
||||
});
|
||||
|
||||
describe('empty creation', (): void => {
|
||||
it('handles unsigned (le)', (): void => {
|
||||
expect(
|
||||
u8aToBigInt(
|
||||
new Uint8Array(),
|
||||
{ isLe: true }
|
||||
).toString(16)
|
||||
).toBe('0');
|
||||
});
|
||||
|
||||
it('handles signed (le)', (): void => {
|
||||
expect(
|
||||
u8aToBigInt(
|
||||
new Uint8Array(),
|
||||
{ isLe: true, isNegative: true }
|
||||
).toString(16)
|
||||
).toBe('0');
|
||||
});
|
||||
|
||||
it('handles unsigned (be)', (): void => {
|
||||
expect(
|
||||
u8aToBigInt(
|
||||
new Uint8Array(),
|
||||
{ isLe: false }
|
||||
).toString(16)
|
||||
).toBe('0');
|
||||
});
|
||||
|
||||
it('handles signed (be)', (): void => {
|
||||
expect(
|
||||
u8aToBigInt(
|
||||
new Uint8Array(),
|
||||
{ isLe: false, isNegative: true }
|
||||
).toString(16)
|
||||
).toBe('0');
|
||||
});
|
||||
});
|
||||
|
||||
it('handles overflows correctly (little-endian)', (): void => {
|
||||
expect(
|
||||
u8aToBigInt(
|
||||
new Uint8Array([0, 1, 0, 0, 0, 0, 0, 0]),
|
||||
{ isLe: true }
|
||||
)
|
||||
).toBe(256n);
|
||||
});
|
||||
|
||||
describe('length tests', (): void => {
|
||||
[true, false].forEach((isLe) => {
|
||||
for (let i = 1; i < 32; i++) {
|
||||
const tu8a = [0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78];
|
||||
const tstr = tu8a.map((n) => n.toString(16));
|
||||
|
||||
it(`converts values with bitLength=${i * 8}, isLe=${isLe}`, (): void => {
|
||||
expect(
|
||||
u8aToBigInt(
|
||||
new Uint8Array(tu8a.slice(0, i)),
|
||||
{ isLe }
|
||||
).toString(16)
|
||||
).toBe(
|
||||
isLe
|
||||
? tstr.slice(0, i).reverse().join('')
|
||||
: tstr.slice(0, i).join('')
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('conversion tests', (): void => {
|
||||
TESTS.forEach(([isLe, isNegative, numarr, strval], i): void => {
|
||||
it(`#${i}: creates ${strval} (bitLength=${numarr.length * 8}, isLe=${isLe}, isNegative=${isNegative})`, (): void => {
|
||||
expect(
|
||||
u8aToBigInt(
|
||||
new Uint8Array(numarr),
|
||||
{ isLe, isNegative }
|
||||
).toString()
|
||||
).toBe(strval);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
perf('u8aToBigInt (i32)', 750_000, [[new Uint8Array([0x9c, 0x9c, 0x9c, 0x9c])]], (v: Uint8Array) => u8aToBigInt(v, { isNegative: true }));
|
||||
perf('u8aToBigInt (u32)', 750_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c])]], u8aToBigInt);
|
||||
perf('u8aToBigInt (u64)', 750_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x68, 0x65, 0x6c, 0x6c])]], u8aToBigInt);
|
||||
perf('u8aToBigInt (u128)', 750_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x68, 0x65, 0x6c, 0x6c, 0x68, 0x65, 0x6c, 0x6c, 0x68, 0x65, 0x6c, 0x6c])]], u8aToBigInt);
|
||||
});
|
||||
@@ -0,0 +1,100 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { ToBnOptions } from '../types.js';
|
||||
|
||||
import { BigInt } from '@pezkuwi/x-bigint';
|
||||
|
||||
import { _1n } from '../bi/consts.js';
|
||||
|
||||
const U8_MAX = BigInt(256);
|
||||
const U16_MAX = BigInt(256 * 256);
|
||||
const U64_MAX = BigInt('0x10000000000000000');
|
||||
|
||||
/**
|
||||
* @name u8aToBigInt
|
||||
* @summary Creates a BigInt from a Uint8Array object.
|
||||
*/
|
||||
export function u8aToBigInt (value: Uint8Array, { isLe = true, isNegative = false }: ToBnOptions = {}): bigint {
|
||||
// slice + reverse is expensive, however SCALE is LE by default so this is the path
|
||||
// we are most interested in (the BE is added for the sake of being comprehensive)
|
||||
if (!isLe) {
|
||||
value = value.slice().reverse();
|
||||
}
|
||||
|
||||
const count = value.length;
|
||||
|
||||
if (isNegative && count && (value[count - 1] & 0x80)) {
|
||||
switch (count) {
|
||||
case 0:
|
||||
return BigInt(0);
|
||||
|
||||
case 1:
|
||||
return BigInt(((value[0] ^ 0x0000_00ff) * -1) - 1);
|
||||
|
||||
case 2:
|
||||
return BigInt((((value[0] + (value[1] << 8)) ^ 0x0000_ffff) * -1) - 1);
|
||||
|
||||
case 4:
|
||||
return BigInt((((value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff) * -1) - 1);
|
||||
}
|
||||
|
||||
const dvI = new DataView(value.buffer, value.byteOffset);
|
||||
|
||||
if (count === 8) {
|
||||
return dvI.getBigInt64(0, true);
|
||||
}
|
||||
|
||||
let result = BigInt(0);
|
||||
const mod = count % 2;
|
||||
|
||||
for (let i = count - 2; i >= mod; i -= 2) {
|
||||
result = (result * U16_MAX) + BigInt(dvI.getUint16(i, true) ^ 0xffff);
|
||||
}
|
||||
|
||||
if (mod) {
|
||||
result = (result * U8_MAX) + BigInt(value[0] ^ 0xff);
|
||||
}
|
||||
|
||||
return (result * -_1n) - _1n;
|
||||
}
|
||||
|
||||
switch (count) {
|
||||
case 0:
|
||||
return BigInt(0);
|
||||
|
||||
case 1:
|
||||
return BigInt(value[0]);
|
||||
|
||||
case 2:
|
||||
return BigInt(value[0] + (value[1] << 8));
|
||||
|
||||
case 4:
|
||||
return BigInt(value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00));
|
||||
}
|
||||
|
||||
const dvI = new DataView(value.buffer, value.byteOffset);
|
||||
|
||||
switch (count) {
|
||||
case 8:
|
||||
return dvI.getBigUint64(0, true);
|
||||
|
||||
case 16:
|
||||
return (dvI.getBigUint64(8, true) * U64_MAX) + dvI.getBigUint64(0, true);
|
||||
|
||||
default: {
|
||||
let result = BigInt(0);
|
||||
const mod = count % 2;
|
||||
|
||||
for (let i = count - 2; i >= mod; i -= 2) {
|
||||
result = (result * U16_MAX) + BigInt(dvI.getUint16(i, true));
|
||||
}
|
||||
|
||||
if (mod) {
|
||||
result = (result * U8_MAX) + BigInt(value[0]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/// <reference types="@polkadot/dev-test/globals.d.ts" />
|
||||
|
||||
import { TESTS } from '../bi/toU8a.spec.js';
|
||||
import { perf } from '../test/index.js';
|
||||
import { u8aToBn } from './index.js';
|
||||
|
||||
// test-cases are the same as in u8aToBigInt
|
||||
describe('u8aToBn', (): void => {
|
||||
it('converts little-endian by default', (): void => {
|
||||
expect(
|
||||
u8aToBn(
|
||||
new Uint8Array([0x12, 0x34])
|
||||
).toString(16)
|
||||
).toBe('3412');
|
||||
});
|
||||
|
||||
describe('empty creation', (): void => {
|
||||
it('handles unsigned (le)', (): void => {
|
||||
expect(
|
||||
u8aToBn(
|
||||
new Uint8Array(),
|
||||
{ isLe: true }
|
||||
).toString(16)
|
||||
).toBe('0');
|
||||
});
|
||||
|
||||
it('handles signed (le)', (): void => {
|
||||
expect(
|
||||
u8aToBn(
|
||||
new Uint8Array(),
|
||||
{ isLe: true, isNegative: true }
|
||||
).toString(16)
|
||||
).toBe('0');
|
||||
});
|
||||
|
||||
it('handles unsigned (be)', (): void => {
|
||||
expect(
|
||||
u8aToBn(
|
||||
new Uint8Array(),
|
||||
{ isLe: false }
|
||||
).toString(16)
|
||||
).toBe('0');
|
||||
});
|
||||
|
||||
it('handles signed (be)', (): void => {
|
||||
expect(
|
||||
u8aToBn(
|
||||
new Uint8Array(),
|
||||
{ isLe: false, isNegative: true }
|
||||
).toString(16)
|
||||
).toBe('0');
|
||||
});
|
||||
});
|
||||
|
||||
it('handles overflows correctly (little-endian)', (): void => {
|
||||
expect(
|
||||
u8aToBn(
|
||||
new Uint8Array([0, 1, 0, 0, 0, 0, 0, 0]),
|
||||
{ isLe: true }
|
||||
).toNumber()
|
||||
).toBe(256);
|
||||
});
|
||||
|
||||
describe('length tests', (): void => {
|
||||
[true, false].forEach((isLe) => {
|
||||
for (let i = 1; i < 32; i++) {
|
||||
const tu8a = [0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78];
|
||||
const tstr = tu8a.map((n) => n.toString(16));
|
||||
|
||||
it(`converts values with bitLength=${i * 8}, isLe=${isLe}`, (): void => {
|
||||
expect(
|
||||
u8aToBn(
|
||||
new Uint8Array(tu8a.slice(0, i)),
|
||||
{ isLe }
|
||||
).toString(16)
|
||||
).toBe(
|
||||
isLe
|
||||
? tstr.slice(0, i).reverse().join('')
|
||||
: tstr.slice(0, i).join('')
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('conversion tests', (): void => {
|
||||
TESTS.forEach(([isLe, isNegative, numarr, strval], i): void => {
|
||||
it(`#${i}: creates ${strval} (bitLength=${numarr.length * 8}, isLe=${isLe}, isNegative=${isNegative})`, (): void => {
|
||||
expect(
|
||||
u8aToBn(
|
||||
new Uint8Array(numarr),
|
||||
{ isLe, isNegative }
|
||||
).toString()
|
||||
).toBe(strval);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
perf('u8aToBn (i32)', 750_000, [[new Uint8Array([0x9c, 0x9c, 0x9c, 0x9c])]], (v: Uint8Array) => u8aToBn(v, { isNegative: true }));
|
||||
perf('u8aToBn (u32)', 750_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c])]], u8aToBn);
|
||||
perf('u8aToBn (u64)', 750_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x68, 0x65, 0x6c, 0x6c])]], u8aToBn);
|
||||
perf('u8aToBn (u128)', 750_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x68, 0x65, 0x6c, 0x6c, 0x68, 0x65, 0x6c, 0x6c, 0x68, 0x65, 0x6c, 0x6c])]], u8aToBn);
|
||||
});
|
||||
@@ -0,0 +1,101 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { ToBnOptions } from '../types.js';
|
||||
|
||||
import { BN } from '../bn/bn.js';
|
||||
|
||||
/**
|
||||
* @name u8aToBn
|
||||
* @summary Creates a BN from a Uint8Array object.
|
||||
* @description
|
||||
* `UInt8Array` input values return the actual BN. `null` or `undefined` values returns an `0x0` value.
|
||||
* @param value The value to convert
|
||||
* @param options Options to pass while converting
|
||||
* @param options.isLe Convert using Little Endian (default)
|
||||
* @param options.isNegative Convert using two's complement
|
||||
* @example
|
||||
* <BR>
|
||||
*
|
||||
* ```javascript
|
||||
* import { u8aToBn } from '@pezkuwi/util';
|
||||
*
|
||||
* u8aToHex(new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0xf])); // 0x68656c0f
|
||||
* ```
|
||||
*/
|
||||
export function u8aToBn (value: Uint8Array, { isLe = true, isNegative = false }: ToBnOptions = {}): BN {
|
||||
// slice + reverse is expensive, however SCALE is LE by default so this is the path
|
||||
// we are most interested in (the BE is added for the sake of being comprehensive)
|
||||
if (!isLe) {
|
||||
value = value.slice().reverse();
|
||||
}
|
||||
|
||||
const count = value.length;
|
||||
|
||||
// shortcut for <= u48 values - in this case the manual conversion
|
||||
// here seems to be more efficient than passing the full array
|
||||
if (isNegative && count && (value[count - 1] & 0x80)) {
|
||||
// Most common case i{8, 16, 32} default LE SCALE-encoded
|
||||
// For <= 32, we also optimize the xor to a single op
|
||||
switch (count) {
|
||||
case 0:
|
||||
return new BN(0);
|
||||
|
||||
case 1:
|
||||
return new BN(((value[0] ^ 0x0000_00ff) * -1) - 1);
|
||||
|
||||
case 2:
|
||||
return new BN((((value[0] + (value[1] << 8)) ^ 0x0000_ffff) * -1) - 1);
|
||||
|
||||
case 3:
|
||||
return new BN((((value[0] + (value[1] << 8) + (value[2] << 16)) ^ 0x00ff_ffff) * -1) - 1);
|
||||
|
||||
case 4:
|
||||
// for the 3rd byte, we don't << 24 - since JS converts all bitwise operators to
|
||||
// 32-bit, in the case where the top-most bit is set this yields a negative value
|
||||
return new BN((((value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff) * -1) - 1);
|
||||
|
||||
case 5:
|
||||
return new BN(((((value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff) + ((value[4] ^ 0xff) * 0x1_00_00_00_00)) * -1) - 1);
|
||||
|
||||
case 6:
|
||||
return new BN(((((value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff) + (((value[4] + (value[5] << 8)) ^ 0x0000_ffff) * 0x1_00_00_00_00)) * -1) - 1);
|
||||
|
||||
default:
|
||||
return new BN(value, 'le').fromTwos(count * 8);
|
||||
}
|
||||
}
|
||||
|
||||
// Most common case - u{8, 16, 32} default LE SCALE-encoded
|
||||
//
|
||||
// There are some slight benefits in unrolling this specific loop,
|
||||
// however it comes with diminishing returns since here the actual
|
||||
// `new BN` does seem to take up the bulk of the time
|
||||
switch (count) {
|
||||
case 0:
|
||||
return new BN(0);
|
||||
|
||||
case 1:
|
||||
return new BN(value[0]);
|
||||
|
||||
case 2:
|
||||
return new BN(value[0] + (value[1] << 8));
|
||||
|
||||
case 3:
|
||||
return new BN(value[0] + (value[1] << 8) + (value[2] << 16));
|
||||
|
||||
case 4:
|
||||
// for the 3rd byte, we don't << 24 - since JS converts all bitwise operators to
|
||||
// 32-bit, in the case where the top-most bit is set this yields a negative value
|
||||
return new BN(value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00));
|
||||
|
||||
case 5:
|
||||
return new BN(value[0] + (value[1] << 8) + (value[2] << 16) + ((value[3] + (value[4] << 8)) * 0x1_00_00_00));
|
||||
|
||||
case 6:
|
||||
return new BN(value[0] + (value[1] << 8) + (value[2] << 16) + ((value[3] + (value[4] << 8) + (value[5] << 16)) * 0x1_00_00_00));
|
||||
|
||||
default:
|
||||
return new BN(value, 'le');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/// <reference types="@polkadot/dev-test/globals.d.ts" />
|
||||
|
||||
import { u8aToBuffer } from './index.js';
|
||||
|
||||
describe('u8aToBuffer', (): void => {
|
||||
it('returns [] when the buffer is null', (): void => {
|
||||
expect(
|
||||
u8aToBuffer(null)
|
||||
).toEqual(Buffer.from([]));
|
||||
});
|
||||
|
||||
it('returns the Buffer value for the Uint8Array', (): void => {
|
||||
expect(
|
||||
u8aToBuffer(new Uint8Array([128, 0, 10]))
|
||||
).toEqual(Buffer.from([128, 0, 10]));
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { BufferClass, BufferObject } from '../types.js';
|
||||
|
||||
import { xglobal } from '@pezkuwi/x-global';
|
||||
|
||||
import { hasBuffer } from '../has.js';
|
||||
|
||||
/**
|
||||
* @name u8aToBuffer
|
||||
* @summary Creates a Buffer object from a hex string.
|
||||
* @description
|
||||
* `null` inputs returns an empty `Buffer` result. `UInt8Array` input values return the actual bytes value converted to a `Buffer`. Anything that is not a `UInt8Array` throws an error.
|
||||
* @example
|
||||
* <BR>
|
||||
*
|
||||
* ```javascript
|
||||
* import { u8aToBuffer } from '@pezkuwi/util';
|
||||
*
|
||||
* console.log('Buffer', u8aToBuffer(new Uint8Array([1, 2, 3])));
|
||||
* ```
|
||||
*/
|
||||
export function u8aToBuffer <T = BufferObject> (value?: Uint8Array | null): T {
|
||||
return hasBuffer
|
||||
? (xglobal.Buffer as unknown as BufferClass).from(value || [])
|
||||
: new Uint8Array(value || []) as T;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/// <reference types="@polkadot/dev-test/globals.d.ts" />
|
||||
|
||||
import { hexToU8a } from '../hex/index.js';
|
||||
import { u8aToFloat } from './index.js';
|
||||
|
||||
describe('u8aToFloat', (): void => {
|
||||
it('throws on invalid bitLength', (): void => {
|
||||
expect(
|
||||
() => u8aToFloat(hexToU8a('0x00000000'), { bitLength: 48 as 32 })
|
||||
).toThrow();
|
||||
});
|
||||
|
||||
it('throws on invalid input length', (): void => {
|
||||
expect(
|
||||
() => u8aToFloat(new Uint8Array())
|
||||
).toThrow();
|
||||
});
|
||||
|
||||
describe('32-bit', (): void => {
|
||||
it('correctly decodes +0.0', (): void => {
|
||||
expect(
|
||||
u8aToFloat(hexToU8a('0x00000000'))
|
||||
).toEqual(+0.0);
|
||||
});
|
||||
|
||||
it('correctly decodes -0.0', (): void => {
|
||||
expect(
|
||||
u8aToFloat(hexToU8a('0x00000080'))
|
||||
).toEqual(-0.0);
|
||||
});
|
||||
|
||||
it('correctly decodes -0.0 (BE)', (): void => {
|
||||
expect(
|
||||
u8aToFloat(hexToU8a('0x80000000'), { isLe: false })
|
||||
).toEqual(-0.0);
|
||||
});
|
||||
|
||||
it('decoded NaN', (): void => {
|
||||
expect(
|
||||
u8aToFloat(hexToU8a('0x0000c07f'))
|
||||
).toEqual(Number.NaN);
|
||||
});
|
||||
|
||||
// https://www.h-schmidt.net/FloatConverter/IEEE754.html
|
||||
it('decodes a known number', (): void => {
|
||||
expect(
|
||||
u8aToFloat(hexToU8a('0x79e9f642')).toFixed(3)
|
||||
).toEqual('123.456');
|
||||
});
|
||||
|
||||
it('decodes a known number (BE)', (): void => {
|
||||
expect(
|
||||
u8aToFloat(hexToU8a('0x42f6e979'), { isLe: false }).toFixed(3)
|
||||
).toEqual('123.456');
|
||||
});
|
||||
});
|
||||
|
||||
describe('64-bit', (): void => {
|
||||
it('correctly decodes +0.0', (): void => {
|
||||
expect(
|
||||
u8aToFloat(hexToU8a('0x0000000000000000'), { bitLength: 64 })
|
||||
).toEqual(+0.0);
|
||||
});
|
||||
|
||||
it('correctly decodes -0.0', (): void => {
|
||||
expect(
|
||||
u8aToFloat(hexToU8a('0x0000000000000080'), { bitLength: 64 })
|
||||
).toEqual(-0.0);
|
||||
});
|
||||
|
||||
it('correctly decodes -0.0 (BE)', (): void => {
|
||||
expect(
|
||||
u8aToFloat(hexToU8a('0x8000000000000000'), { bitLength: 64, isLe: false })
|
||||
).toEqual(-0.0);
|
||||
});
|
||||
|
||||
it('correctly decodes NaN', (): void => {
|
||||
expect(
|
||||
u8aToFloat(hexToU8a('0x000000000000f87f'), { bitLength: 64 })
|
||||
).toEqual(Number.NaN);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
interface Options {
|
||||
bitLength?: 32 | 64;
|
||||
isLe?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name u8aToFloat
|
||||
* @description Converts a Uint8Array value into the float (either 32 or 64-bit)
|
||||
* representation.
|
||||
*/
|
||||
export function u8aToFloat (value: Uint8Array, { bitLength = 32, isLe = true }: Options = {}): number {
|
||||
if (bitLength !== 32 && bitLength !== 64) {
|
||||
throw new Error('Invalid bitLength provided, expected 32 or 64');
|
||||
} else if (value.length < (bitLength / 8)) {
|
||||
throw new Error(`Invalid input buffer provided, expected at least ${bitLength / 8} bytes, found ${value.length}`);
|
||||
}
|
||||
|
||||
const dv = new DataView(value.buffer, value.byteOffset);
|
||||
|
||||
return bitLength === 32
|
||||
? dv.getFloat32(0, isLe)
|
||||
: dv.getFloat64(0, isLe);
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/// <reference types="@polkadot/dev-test/globals.d.ts" />
|
||||
|
||||
import { perfCmp } from '../test/index.js';
|
||||
import { u8aToHex } from './index.js';
|
||||
import { u8aToHex as u8aToHexBuffer } from './toHexBuffer.js';
|
||||
|
||||
const ptest32k = new Uint8Array(32768);
|
||||
const ptest256 = new Uint8Array(256);
|
||||
|
||||
for (let i = 0, count = ptest32k.length; i < count; i++) {
|
||||
if (i < ptest256.length) {
|
||||
ptest256[1] = i % 256;
|
||||
}
|
||||
|
||||
ptest32k[i] = i % 256;
|
||||
}
|
||||
|
||||
describe('u8aToHex', (): void => {
|
||||
it('returns empty as 0x', (): void => {
|
||||
expect(
|
||||
u8aToHex()
|
||||
).toEqual('0x');
|
||||
});
|
||||
|
||||
it('returns empty as "" (unprefixed)', (): void => {
|
||||
expect(
|
||||
u8aToHex(null, -1, false)
|
||||
).toEqual('');
|
||||
});
|
||||
|
||||
it('returns the hex value for the array', (): void => {
|
||||
expect(
|
||||
u8aToHex(
|
||||
new Uint8Array([128, 0, 10])
|
||||
)
|
||||
).toEqual('0x80000a');
|
||||
});
|
||||
|
||||
it('returns the hex value for the array (unprefixed)', (): void => {
|
||||
expect(
|
||||
u8aToHex(
|
||||
new Uint8Array([128, 0, 10]),
|
||||
-1,
|
||||
false
|
||||
)
|
||||
).toEqual('80000a');
|
||||
});
|
||||
|
||||
it('handles starting zeros correctly', (): void => {
|
||||
expect(
|
||||
u8aToHex(
|
||||
new Uint8Array([0, 1, 0, 0, 0, 0, 0, 0])
|
||||
)
|
||||
).toEqual('0x0001000000000000');
|
||||
});
|
||||
|
||||
it('returns the hex value where allowed < max', (): void => {
|
||||
expect(
|
||||
u8aToHex(
|
||||
new Uint8Array(Uint8Array.from([128, 0, 10, 11]), 64)
|
||||
)
|
||||
).toEqual('0x80000a0b');
|
||||
});
|
||||
|
||||
it('returns the trimmed hex value where allowed >= max', (): void => {
|
||||
expect(
|
||||
u8aToHex(
|
||||
new Uint8Array([128, 0, 10, 11, 12, 13]),
|
||||
32
|
||||
)
|
||||
).toEqual('0x8000…0c0d');
|
||||
});
|
||||
|
||||
it('converts known bytes to their correct values', (): void => {
|
||||
expect(
|
||||
// hello world
|
||||
u8aToHex(new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64]))
|
||||
).toEqual('0x68656c6c6f20776f726c64');
|
||||
});
|
||||
|
||||
perfCmp('u8aToHex (32k)', ['u8aToHexBuffer', 'u8aToHex'], 1000, [[ptest32k]], (s: Uint8Array, isSecond) =>
|
||||
isSecond
|
||||
? u8aToHex(s)
|
||||
: u8aToHexBuffer(s)
|
||||
);
|
||||
perfCmp('u8aToHex (128)', ['u8aToHexBuffer', 'u8aToHex'], 200_000, [[ptest256]], (s: Uint8Array, isSecond) =>
|
||||
isSecond
|
||||
? u8aToHex(s)
|
||||
: u8aToHexBuffer(s)
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { HexString } from '../types.js';
|
||||
|
||||
const U8 = new Array<string>(256);
|
||||
const U16 = new Array<string>(256 * 256);
|
||||
|
||||
for (let n = 0; n < 256; n++) {
|
||||
U8[n] = n.toString(16).padStart(2, '0');
|
||||
}
|
||||
|
||||
for (let i = 0; i < 256; i++) {
|
||||
const s = i << 8;
|
||||
|
||||
for (let j = 0; j < 256; j++) {
|
||||
U16[s | j] = U8[i] + U8[j];
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function hex (value: Uint8Array, result: HexString): HexString {
|
||||
const mod = (value.length % 2) | 0;
|
||||
const length = (value.length - mod) | 0;
|
||||
|
||||
for (let i = 0; i < length; i += 2) {
|
||||
result += U16[(value[i] << 8) | value[i + 1]];
|
||||
}
|
||||
|
||||
if (mod) {
|
||||
result += U8[value[length] | 0];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name u8aToHex
|
||||
* @summary Creates a hex string from a Uint8Array object.
|
||||
* @description
|
||||
* `UInt8Array` input values return the actual hex string. `null` or `undefined` values returns an `0x` string.
|
||||
* @example
|
||||
* <BR>
|
||||
*
|
||||
* ```javascript
|
||||
* import { u8aToHex } from '@pezkuwi/util';
|
||||
*
|
||||
* u8aToHex(new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0xf])); // 0x68656c0f
|
||||
* ```
|
||||
*/
|
||||
export function u8aToHex (value?: Uint8Array | null, bitLength = -1, isPrefixed = true): HexString {
|
||||
// this is not 100% correct sinmce we support isPrefixed = false....
|
||||
const empty = isPrefixed
|
||||
? '0x'
|
||||
: '' as HexString;
|
||||
|
||||
if (!value?.length) {
|
||||
return empty;
|
||||
} else if (bitLength > 0) {
|
||||
const length = Math.ceil(bitLength / 8);
|
||||
|
||||
if (value.length > length) {
|
||||
return `${hex(value.subarray(0, length / 2), empty)}…${hex(value.subarray(value.length - length / 2), '' as HexString)}`;
|
||||
}
|
||||
}
|
||||
|
||||
return hex(value, empty);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/// <reference types="@polkadot/dev-test/globals.d.ts" />
|
||||
|
||||
import { u8aToHex } from './toHexBuffer.js';
|
||||
|
||||
describe('u8aToHex', (): void => {
|
||||
it('returns empty as 0x', (): void => {
|
||||
expect(
|
||||
u8aToHex()
|
||||
).toEqual('0x');
|
||||
});
|
||||
|
||||
it('returns empty as "" (unprefixed)', (): void => {
|
||||
expect(
|
||||
u8aToHex(null, -1, false)
|
||||
).toEqual('');
|
||||
});
|
||||
|
||||
it('returns the hex value for the array', (): void => {
|
||||
expect(
|
||||
u8aToHex(
|
||||
new Uint8Array([128, 0, 10])
|
||||
)
|
||||
).toEqual('0x80000a');
|
||||
});
|
||||
|
||||
it('returns the hex value for the array (unprefixed)', (): void => {
|
||||
expect(
|
||||
u8aToHex(
|
||||
new Uint8Array([128, 0, 10]),
|
||||
-1,
|
||||
false
|
||||
)
|
||||
).toEqual('80000a');
|
||||
});
|
||||
|
||||
it('handles starting zeros correctly', (): void => {
|
||||
expect(
|
||||
u8aToHex(
|
||||
new Uint8Array([0, 1, 0, 0, 0, 0, 0, 0])
|
||||
)
|
||||
).toEqual('0x0001000000000000');
|
||||
});
|
||||
|
||||
it('returns the hex value where allowed < max', (): void => {
|
||||
expect(
|
||||
u8aToHex(
|
||||
new Uint8Array(Uint8Array.from([128, 0, 10, 11]), 64)
|
||||
)
|
||||
).toEqual('0x80000a0b');
|
||||
});
|
||||
|
||||
it('returns the trimmed hex value where allowed >= max', (): void => {
|
||||
expect(
|
||||
u8aToHex(
|
||||
new Uint8Array([128, 0, 10, 11, 12, 13]),
|
||||
32
|
||||
)
|
||||
).toEqual('0x8000…0c0d');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { HexString } from '../types.js';
|
||||
|
||||
/**
|
||||
* @name u8aToHex
|
||||
* @summary Creates a hex string from a Uint8Array object.
|
||||
* @description
|
||||
* `UInt8Array` input values return the actual hex string. `null` or `undefined` values returns an `0x` string.
|
||||
* @example
|
||||
* <BR>
|
||||
*
|
||||
* ```javascript
|
||||
* import { u8aToHex } from '@pezkuwi/util';
|
||||
*
|
||||
* u8aToHex(new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0xf])); // 0x68656c0f
|
||||
* ```
|
||||
*/
|
||||
export function u8aToHex (value?: Uint8Array | null, bitLength = -1, isPrefixed = true): HexString {
|
||||
const length = Math.ceil(bitLength / 8);
|
||||
|
||||
return `${isPrefixed ? '0x' : ''}${
|
||||
!value?.length
|
||||
? ''
|
||||
: (bitLength > 0 && value.length > length)
|
||||
? `${Buffer.from(value.subarray(0, length / 2)).toString('hex')}…${Buffer.from(value.subarray(value.length - length / 2)).toString('hex')}`
|
||||
: Buffer.from(value).toString('hex')
|
||||
}` as HexString;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/// <reference types="@polkadot/dev-test/globals.d.ts" />
|
||||
|
||||
import { TESTS } from '../bi/toU8a.spec.js';
|
||||
import { perf } from '../test/index.js';
|
||||
import { u8aToNumber } from './index.js';
|
||||
|
||||
const TESTS_NUM = TESTS.filter(([,, numarr]) => numarr.length <= 6);
|
||||
|
||||
describe('u8aToNumber', (): void => {
|
||||
describe('empty creation', (): void => {
|
||||
it('handles unsigned (le)', (): void => {
|
||||
expect(
|
||||
u8aToNumber(
|
||||
new Uint8Array()
|
||||
)
|
||||
).toBe(0);
|
||||
});
|
||||
|
||||
it('handles signed (le)', (): void => {
|
||||
expect(
|
||||
u8aToNumber(
|
||||
new Uint8Array(),
|
||||
{ isNegative: true }
|
||||
)
|
||||
).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('conversion tests', (): void => {
|
||||
TESTS_NUM.forEach(([isLe, isNegative, numarr, strval], i): void => {
|
||||
it(`#${i}: creates ${strval} (bitLength=${numarr.length * 8}, isLe=${isLe}, isNegative=${isNegative})`, (): void => {
|
||||
expect(
|
||||
u8aToNumber(
|
||||
new Uint8Array(numarr),
|
||||
{ isLe, isNegative }
|
||||
).toString()
|
||||
).toBe(strval);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
perf('u8aToNumber (i32)', 750_000, [[new Uint8Array([0x9c, 0x9c, 0x9c, 0x9c])]], (v: Uint8Array) => u8aToNumber(v, { isNegative: true }));
|
||||
perf('u8aToNumber (u32)', 750_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c])]], u8aToNumber);
|
||||
});
|
||||
@@ -0,0 +1,80 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { ToBnOptions } from '../types.js';
|
||||
|
||||
/**
|
||||
* @name u8aToNumber
|
||||
* @summary Creates a number from a Uint8Array object.
|
||||
*/
|
||||
export function u8aToNumber (value: Uint8Array, { isLe = true, isNegative = false }: ToBnOptions = {}): number {
|
||||
// slice + reverse is expensive, however SCALE is LE by default so this is the path
|
||||
// we are most interested in (the BE is added for the sake of being comprehensive)
|
||||
if (!isLe) {
|
||||
value = value.slice().reverse();
|
||||
}
|
||||
|
||||
const count = value.length;
|
||||
|
||||
// When the value is a i{8, 16, 24, 32, 40, 40} values and the top-most bit
|
||||
// indicates a signed value, we use a two's complement conversion. If one of these
|
||||
// flags are not set, we just do a normal unsigned conversion (the same shortcut
|
||||
// applies in both the u8aTo{BigInt, Bn} conversions as well)
|
||||
if (isNegative && count && (value[count - 1] & 0x80)) {
|
||||
switch (count) {
|
||||
case 0:
|
||||
return 0;
|
||||
|
||||
case 1:
|
||||
return (((value[0] ^ 0x0000_00ff) * -1) - 1);
|
||||
|
||||
case 2:
|
||||
return ((((value[0] + (value[1] << 8)) ^ 0x0000_ffff) * -1) - 1);
|
||||
|
||||
case 3:
|
||||
return ((((value[0] + (value[1] << 8) + (value[2] << 16)) ^ 0x00ff_ffff) * -1) - 1);
|
||||
|
||||
case 4:
|
||||
// for the 3rd byte, we don't << 24 - since JS converts all bitwise operators to
|
||||
// 32-bit, in the case where the top-most bit is set this yields a negative value
|
||||
return ((((value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff) * -1) - 1);
|
||||
|
||||
case 5:
|
||||
return (((((value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff) + ((value[4] ^ 0xff) * 0x1_00_00_00_00)) * -1) - 1);
|
||||
|
||||
case 6:
|
||||
return (((((value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff) + (((value[4] + (value[5] << 8)) ^ 0x0000_ffff) * 0x1_00_00_00_00)) * -1) - 1);
|
||||
|
||||
default:
|
||||
throw new Error('Value more than 48-bits cannot be reliably converted');
|
||||
}
|
||||
}
|
||||
|
||||
switch (count) {
|
||||
case 0:
|
||||
return 0;
|
||||
|
||||
case 1:
|
||||
return value[0];
|
||||
|
||||
case 2:
|
||||
return value[0] + (value[1] << 8);
|
||||
|
||||
case 3:
|
||||
return value[0] + (value[1] << 8) + (value[2] << 16);
|
||||
|
||||
case 4:
|
||||
// for the 3rd byte, we don't << 24 - since JS converts all bitwise operators to
|
||||
// 32-bit, in the case where the top-most bit is set this yields a negative value
|
||||
return value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00);
|
||||
|
||||
case 5:
|
||||
return value[0] + (value[1] << 8) + (value[2] << 16) + ((value[3] + (value[4] << 8)) * 0x1_00_00_00);
|
||||
|
||||
case 6:
|
||||
return value[0] + (value[1] << 8) + (value[2] << 16) + ((value[3] + (value[4] << 8) + (value[5] << 16)) * 0x1_00_00_00);
|
||||
|
||||
default:
|
||||
throw new Error('Value more than 48-bits cannot be reliably converted');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/// <reference types="@polkadot/dev-test/globals.d.ts" />
|
||||
|
||||
import { u8aToString } from './index.js';
|
||||
|
||||
describe('u8aToString', (): void => {
|
||||
it('decodes to an empty string for undefined', (): void => {
|
||||
expect(
|
||||
u8aToString()
|
||||
).toEqual('');
|
||||
});
|
||||
|
||||
it('decodes to an empty string for empty buffer', (): void => {
|
||||
expect(
|
||||
u8aToString(new Uint8Array())
|
||||
).toEqual('');
|
||||
});
|
||||
|
||||
it('decodes the Uint8Array correctly (ru)', (): void => {
|
||||
expect(
|
||||
u8aToString(
|
||||
new Uint8Array([208, 159, 209, 128, 208, 184, 208, 178, 208, 181, 209, 130, 44, 32, 208, 188, 208, 184, 209, 128, 33])
|
||||
)
|
||||
).toEqual('Привет, мир!');
|
||||
});
|
||||
|
||||
it('decodes the Uint8Array correctly (en)', (): void => {
|
||||
expect(
|
||||
u8aToString(
|
||||
new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64])
|
||||
)
|
||||
).toEqual('hello world');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { TextDecoder } from '@pezkuwi/x-textdecoder';
|
||||
|
||||
const decoder = new TextDecoder('utf-8');
|
||||
|
||||
/**
|
||||
* @name u8aToString
|
||||
* @summary Creates a utf-8 string from a Uint8Array object.
|
||||
* @description
|
||||
* `UInt8Array` input values return the actual decoded utf-8 string. `null` or `undefined` values returns an empty string.
|
||||
* @example
|
||||
* <BR>
|
||||
*
|
||||
* ```javascript
|
||||
* import { u8aToString } from '@pezkuwi/util';
|
||||
*
|
||||
* u8aToString(new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x6f])); // hello
|
||||
* ```
|
||||
*/
|
||||
export function u8aToString (value?: Uint8Array | null): string {
|
||||
return value
|
||||
? decoder.decode(value)
|
||||
: '';
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/// <reference types="@polkadot/dev-test/globals.d.ts" />
|
||||
|
||||
import type { U8aLike } from '../types.js';
|
||||
|
||||
import { perf } from '../test/index.js';
|
||||
import { u8aToU8a } from './index.js';
|
||||
|
||||
const TESTS: [input: U8aLike | null | undefined, output: Uint8Array][] = [
|
||||
['0x80000a', new Uint8Array([128, 0, 10])],
|
||||
['abcde fghij', new Uint8Array([97, 98, 99, 100, 101, 32, 102, 103, 104, 105, 106])],
|
||||
[[128, 0, 10, 11, 12], new Uint8Array([128, 0, 10, 11, 12])],
|
||||
[Buffer.from([1, 2, 3, 128, 0, 10, 11, 12]), new Uint8Array([1, 2, 3, 128, 0, 10, 11, 12])],
|
||||
[Buffer.from('80000a', 'hex'), new Uint8Array([128, 0, 10])],
|
||||
// this is where completely invalid data is being passed
|
||||
[123 as unknown as Uint8Array, new Uint8Array([49, 50, 51])]
|
||||
];
|
||||
|
||||
describe('u8aToU8a', (): void => {
|
||||
it('returns an empty Uint8Array when null/undefined/"" provided', (): void => {
|
||||
expect(u8aToU8a(null)).toHaveLength(0);
|
||||
expect(
|
||||
u8aToU8a()
|
||||
).toHaveLength(0);
|
||||
expect(
|
||||
u8aToU8a('')
|
||||
).toHaveLength(0);
|
||||
expect(
|
||||
u8aToU8a('')
|
||||
).toEqual(new Uint8Array());
|
||||
});
|
||||
|
||||
it('Throw error on null/undefined values on strict checking', () => {
|
||||
expect(() => u8aToU8a(undefined, true)).toThrow('u8aToU8a: Expected non-null, non-undefined value');
|
||||
expect(() => u8aToU8a(null, true)).toThrow('u8aToU8a: Expected non-null, non-undefined value');
|
||||
});
|
||||
|
||||
it('returns a Uint8Array as-is (u8a input)', (): void => {
|
||||
const input = new Uint8Array([128, 0, 10]);
|
||||
|
||||
expect(
|
||||
u8aToU8a(input)
|
||||
).toEqual(input);
|
||||
});
|
||||
|
||||
describe('conversion tests', (): void => {
|
||||
TESTS.forEach(([input, output], i): void => {
|
||||
it(`#${i}: converts ${input as string} (typeof=${typeof input})`, (): void => {
|
||||
expect(
|
||||
u8aToU8a(input)
|
||||
).toEqual(
|
||||
output
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
perf('u8aToU8a (hex)', 250_000, [['0x1234']], u8aToU8a);
|
||||
perf('u8aToU8a (str)', 250_000, [['test']], u8aToU8a);
|
||||
perf('u8aToU8a (u8a)', 1_000_000, [[new Uint8Array()]], u8aToU8a);
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { U8aLike } from '../types.js';
|
||||
|
||||
import { hexToU8a } from '../hex/toU8a.js';
|
||||
import { isBuffer } from '../is/buffer.js';
|
||||
import { isHex } from '../is/hex.js';
|
||||
import { isU8a } from '../is/u8a.js';
|
||||
import { stringToU8a } from '../string/toU8a.js';
|
||||
|
||||
/**
|
||||
* @name u8aToU8a
|
||||
* @summary Creates a Uint8Array value from a Uint8Array, Buffer, string or hex input.
|
||||
* @description
|
||||
* `null` or `undefined` inputs returns a `[]` result, Uint8Array values returns the value, hex strings returns a Uint8Array representation.
|
||||
* If `strict` is true, `null` or `undefined` will throw an error instead of returning an empty array.
|
||||
* Supports input types: Uint8Array, Buffer, hex string, string, or number array.
|
||||
* @example
|
||||
* <BR>
|
||||
*
|
||||
* ```javascript
|
||||
* import { u8aToU8a } from '@pezkuwi/util';
|
||||
*
|
||||
* u8aToU8a(new Uint8Array([0x12, 0x34]); // => Uint8Array([0x12, 0x34])
|
||||
* u8aToU8a(0x1234); // => Uint8Array([0x12, 0x34])
|
||||
* ```
|
||||
*/
|
||||
export function u8aToU8a (value?: U8aLike | null, strict = false): Uint8Array {
|
||||
if (strict && (value === null || value === undefined)) {
|
||||
throw new Error('u8aToU8a: Expected non-null, non-undefined value');
|
||||
}
|
||||
|
||||
return isU8a(value)
|
||||
// NOTE isBuffer needs to go here since it actually extends
|
||||
// Uint8Array on Node.js environments, so all Buffer are Uint8Array,
|
||||
// but Uint8Array is not Buffer
|
||||
? isBuffer(value)
|
||||
? new Uint8Array(value)
|
||||
: value
|
||||
: isHex(value)
|
||||
? hexToU8a(value)
|
||||
: Array.isArray(value)
|
||||
? new Uint8Array(value)
|
||||
: stringToU8a(value);
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/// <reference types="@polkadot/dev-test/globals.d.ts" />
|
||||
|
||||
// Originally from https://github.com/polkadot-js/extension/pull/743
|
||||
|
||||
import { u8aConcat, u8aEq, u8aToString } from '@pezkuwi/util';
|
||||
|
||||
import { U8A_WRAP_ETHEREUM, U8A_WRAP_POSTFIX, U8A_WRAP_PREFIX, u8aUnwrapBytes, u8aWrapBytes } from './wrap.js';
|
||||
|
||||
const TEST_DATA = 'this is just some random message that we expect to be wrapped along the way';
|
||||
const TEST_ETH = u8aConcat(U8A_WRAP_ETHEREUM, TEST_DATA);
|
||||
const TEST_WRAP_EMPTY = `${u8aToString(U8A_WRAP_PREFIX)}${u8aToString(U8A_WRAP_POSTFIX)}`;
|
||||
const TEST_WRAP_FULL = `${u8aToString(U8A_WRAP_PREFIX)}${TEST_DATA}${u8aToString(U8A_WRAP_POSTFIX)}`;
|
||||
const TEST_WARP_HALF_PRE = `${u8aToString(U8A_WRAP_PREFIX)}${TEST_DATA}`;
|
||||
const TEST_WRAP_HALF_POST = `${TEST_DATA}${u8aToString(U8A_WRAP_POSTFIX)}`;
|
||||
|
||||
describe('u8aWrapBytes', (): void => {
|
||||
it('wraps empty bytes', (): void => {
|
||||
expect(
|
||||
u8aEq(
|
||||
u8aWrapBytes(new Uint8Array()),
|
||||
u8aConcat(U8A_WRAP_PREFIX, U8A_WRAP_POSTFIX)
|
||||
)
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('wraps when no wrapping is detected', (): void => {
|
||||
expect(
|
||||
u8aToString(
|
||||
u8aWrapBytes(TEST_DATA)
|
||||
)
|
||||
).toEqual(TEST_WRAP_FULL);
|
||||
});
|
||||
|
||||
it('wraps when only start wrap is detected', (): void => {
|
||||
expect(
|
||||
u8aToString(
|
||||
u8aWrapBytes(TEST_WARP_HALF_PRE)
|
||||
)
|
||||
).toEqual(`${u8aToString(U8A_WRAP_PREFIX)}${TEST_WARP_HALF_PRE}${u8aToString(U8A_WRAP_POSTFIX)}`);
|
||||
});
|
||||
|
||||
it('wraps when only end wrap is detected', (): void => {
|
||||
expect(
|
||||
u8aToString(
|
||||
u8aWrapBytes(TEST_WRAP_HALF_POST)
|
||||
)
|
||||
).toEqual(`${u8aToString(U8A_WRAP_PREFIX)}${TEST_WRAP_HALF_POST}${u8aToString(U8A_WRAP_POSTFIX)}`);
|
||||
});
|
||||
|
||||
it('does not re-wrap when a wrap is already present', (): void => {
|
||||
expect(
|
||||
u8aToString(
|
||||
u8aWrapBytes(TEST_WRAP_FULL)
|
||||
)
|
||||
).toEqual(TEST_WRAP_FULL);
|
||||
});
|
||||
|
||||
it('does not re-wrap when a wrap (empty data) is already present', (): void => {
|
||||
expect(
|
||||
u8aToString(
|
||||
u8aWrapBytes(TEST_WRAP_EMPTY)
|
||||
)
|
||||
).toEqual(TEST_WRAP_EMPTY);
|
||||
});
|
||||
});
|
||||
|
||||
describe('unwrapBytes', (): void => {
|
||||
it('unwraps empty bytes', (): void => {
|
||||
expect(
|
||||
u8aEq(
|
||||
u8aUnwrapBytes(new Uint8Array()),
|
||||
new Uint8Array()
|
||||
)
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('unwraps when no wrapping is detected', (): void => {
|
||||
expect(
|
||||
u8aToString(
|
||||
u8aUnwrapBytes(TEST_DATA)
|
||||
)
|
||||
).toEqual(TEST_DATA);
|
||||
});
|
||||
|
||||
it('unwraps when no wrapping is detected (only start)', (): void => {
|
||||
expect(
|
||||
u8aToString(
|
||||
u8aUnwrapBytes(TEST_WARP_HALF_PRE)
|
||||
)
|
||||
).toEqual(TEST_WARP_HALF_PRE);
|
||||
});
|
||||
|
||||
it('unwraps when no wrapping is detected (only end)', (): void => {
|
||||
expect(
|
||||
u8aToString(
|
||||
u8aUnwrapBytes(TEST_WRAP_HALF_POST)
|
||||
)
|
||||
).toEqual(TEST_WRAP_HALF_POST);
|
||||
});
|
||||
|
||||
it('unwraps when a wrap is present', (): void => {
|
||||
expect(
|
||||
u8aToString(
|
||||
u8aUnwrapBytes(TEST_WRAP_FULL)
|
||||
)
|
||||
).toEqual(TEST_DATA);
|
||||
});
|
||||
|
||||
it('unwraps when a an empty wrap is present', (): void => {
|
||||
expect(
|
||||
u8aToString(
|
||||
u8aUnwrapBytes(TEST_WRAP_EMPTY)
|
||||
)
|
||||
).toEqual('');
|
||||
});
|
||||
|
||||
describe('Ethereum-style', (): void => {
|
||||
it('does not wrap an Ethereum wrap', (): void => {
|
||||
expect(
|
||||
u8aEq(
|
||||
u8aWrapBytes(TEST_ETH),
|
||||
TEST_ETH
|
||||
)
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('does not unwrap an Ethereum wrap', (): void => {
|
||||
expect(
|
||||
u8aEq(
|
||||
u8aUnwrapBytes(TEST_ETH),
|
||||
TEST_ETH
|
||||
)
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,65 @@
|
||||
// Copyright 2017-2025 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Originally from https://github.com/polkadot-js/extension/pull/743
|
||||
|
||||
import type { U8aLike } from '../types.js';
|
||||
|
||||
import { u8aConcatStrict } from './concat.js';
|
||||
import { u8aEq } from './eq.js';
|
||||
import { u8aToU8a } from './toU8a.js';
|
||||
|
||||
/** @internal */
|
||||
export const U8A_WRAP_ETHEREUM = /*#__PURE__*/ u8aToU8a('\x19Ethereum Signed Message:\n');
|
||||
|
||||
/** @internal */
|
||||
export const U8A_WRAP_PREFIX = /*#__PURE__*/ u8aToU8a('<Bytes>');
|
||||
|
||||
/** @internal */
|
||||
export const U8A_WRAP_POSTFIX = /*#__PURE__*/ u8aToU8a('</Bytes>');
|
||||
|
||||
const WRAP_LEN = U8A_WRAP_PREFIX.length + U8A_WRAP_POSTFIX.length;
|
||||
|
||||
/** @internal */
|
||||
export function u8aIsWrapped (u8a: Uint8Array, withEthereum: boolean): boolean {
|
||||
return (
|
||||
(
|
||||
u8a.length >= WRAP_LEN &&
|
||||
u8aEq(u8a.subarray(0, U8A_WRAP_PREFIX.length), U8A_WRAP_PREFIX) &&
|
||||
u8aEq(u8a.slice(-U8A_WRAP_POSTFIX.length), U8A_WRAP_POSTFIX)
|
||||
) ||
|
||||
(
|
||||
withEthereum &&
|
||||
u8a.length >= U8A_WRAP_ETHEREUM.length &&
|
||||
u8aEq(u8a.subarray(0, U8A_WRAP_ETHEREUM.length), U8A_WRAP_ETHEREUM)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name u8aUnwrapBytes
|
||||
* @description Removes all <Bytes>...</Bytes> wrappers from the supplied value
|
||||
*/
|
||||
export function u8aUnwrapBytes (bytes: U8aLike): Uint8Array {
|
||||
const u8a = u8aToU8a(bytes);
|
||||
|
||||
// we don't want to unwrap Ethereum-style wraps
|
||||
return u8aIsWrapped(u8a, false)
|
||||
? u8a.subarray(U8A_WRAP_PREFIX.length, u8a.length - U8A_WRAP_POSTFIX.length)
|
||||
: u8a;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name u8aWrapBytes
|
||||
* @description
|
||||
* Adds a <Bytes>...</Bytes> wrapper to the supplied value, if
|
||||
* - We don't already have a Bytes wrapper
|
||||
* - The message is not an Ethereum-style message
|
||||
*/
|
||||
export function u8aWrapBytes (bytes: U8aLike): Uint8Array {
|
||||
const u8a = u8aToU8a(bytes);
|
||||
|
||||
return u8aIsWrapped(u8a, true)
|
||||
? u8a
|
||||
: u8aConcatStrict([U8A_WRAP_PREFIX, u8a, U8A_WRAP_POSTFIX]);
|
||||
}
|
||||
Reference in New Issue
Block a user