Remove some internal Array allocations (#4858)
* Handle Vec assignment inline * mappings * Adjust * Adjust * Cleanup build * Fix BTreeSet build * Adjust * hasNoDupes adjustment * Adjust PortableRegistry extractName
This commit is contained in:
@@ -20,18 +20,10 @@ export abstract class AbstractArray<T extends Codec> extends Array<T> implements
|
||||
|
||||
public createdAtHash?: IU8a;
|
||||
|
||||
readonly initialU8aLength?: number;
|
||||
|
||||
protected constructor (registry: Registry, values: T[], initialU8aLength?: number) {
|
||||
super(values.length);
|
||||
|
||||
// explicitly set the values here - this removes the need for any extra allocations
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
this[i] = values[i];
|
||||
}
|
||||
protected constructor (registry: Registry, length: number) {
|
||||
super(length);
|
||||
|
||||
this.registry = registry;
|
||||
this.initialU8aLength = initialU8aLength;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -66,12 +66,10 @@ function extractDef (registry: Registry, _def: Record<string, string | CodecClas
|
||||
isBasic = true;
|
||||
isIndexed = false;
|
||||
} else if (isRustEnum(_def)) {
|
||||
const entries = Object.entries(mapToTypeMap(registry, _def));
|
||||
const [Types, keys] = mapToTypeMap(registry, _def);
|
||||
|
||||
for (let i = 0; i < entries.length; i++) {
|
||||
const [key, Type] = entries[i];
|
||||
|
||||
def[key] = { Type, index: i };
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
def[keys[i]] = { Type: Types[i], index: i };
|
||||
}
|
||||
|
||||
isBasic = !Object.values(def).some(({ Type }) => Type !== Null);
|
||||
@@ -403,15 +401,14 @@ export class Enum implements IEnum {
|
||||
: this.defKeys;
|
||||
}
|
||||
|
||||
const typeMap = Object
|
||||
.entries(this.#def)
|
||||
.reduce((out: Record<string, CodecClass>, [key, { Type }]) => {
|
||||
out[key] = Type;
|
||||
const entries = Object.entries(this.#def);
|
||||
|
||||
return out;
|
||||
}, {});
|
||||
return typesToMap(this.registry, entries.reduce<[CodecClass[], string[]]>((out, [key, { Type }], i) => {
|
||||
out[0][i] = Type;
|
||||
out[1][i] = key;
|
||||
|
||||
return typesToMap(this.registry, typeMap);
|
||||
return out;
|
||||
}, [new Array<CodecClass>(entries.length), new Array<string>(entries.length)]));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,51 +8,44 @@ import { isFunction, isHex, isString, isU8a, stringify, u8aConcat, u8aToU8a } fr
|
||||
import { AbstractArray } from '../abstract/AbstractArray';
|
||||
import { decodeU8a, mapToTypeMap, typeToConstructor } from '../utils';
|
||||
|
||||
type TupleCodecClass = CodecClass[] | {
|
||||
[index: string]: CodecClass;
|
||||
};
|
||||
|
||||
type TupleType = (CodecClass | string);
|
||||
|
||||
type TupleTypes = TupleType[] | {
|
||||
[index: string]: CodecClass | string;
|
||||
};
|
||||
|
||||
type Definition = [CodecClass[], string[]];
|
||||
|
||||
interface Options {
|
||||
definition?: TupleCodecClass;
|
||||
setDefinition?: (d: TupleCodecClass) => TupleCodecClass;
|
||||
definition?: Definition;
|
||||
setDefinition?: (d: Definition) => Definition;
|
||||
}
|
||||
|
||||
function noopSetDefinition (d: TupleCodecClass): TupleCodecClass {
|
||||
function noopSetDefinition (d: Definition): Definition {
|
||||
return d;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function decodeTuple (registry: Registry, Classes: TupleCodecClass, value?: Exclude<AnyTupleValue, Uint8Array>): [Codec[], number] {
|
||||
function decodeTuple (registry: Registry, result: Codec[], Classes: Definition, value?: Exclude<AnyTupleValue, Uint8Array>): [Codec[], number] {
|
||||
if (isU8a(value) || isHex(value)) {
|
||||
return decodeU8a(registry, u8aToU8a(value), Classes);
|
||||
return decodeU8a(registry, result, u8aToU8a(value), Classes);
|
||||
}
|
||||
|
||||
const Types: CodecClass[] = Array.isArray(Classes)
|
||||
? Classes
|
||||
: Object.values(Classes);
|
||||
const Types = Classes[0];
|
||||
|
||||
return [
|
||||
Types.map((Type, index): Codec => {
|
||||
try {
|
||||
const entry = value?.[index];
|
||||
for (let i = 0; i < Types.length; i++) {
|
||||
try {
|
||||
const entry = value?.[i];
|
||||
|
||||
if (entry instanceof Type) {
|
||||
return entry;
|
||||
}
|
||||
result[i] = entry instanceof Types[i]
|
||||
? entry
|
||||
: new Types[i](registry, entry);
|
||||
} catch (error) {
|
||||
throw new Error(`Tuple: failed on ${i}:: ${(error as Error).message}`);
|
||||
}
|
||||
}
|
||||
|
||||
return new Type(registry, entry);
|
||||
} catch (error) {
|
||||
throw new Error(`Tuple: failed on ${index}:: ${(error as Error).message}`);
|
||||
}
|
||||
}),
|
||||
0
|
||||
];
|
||||
return [result, 0];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,29 +55,34 @@ function decodeTuple (registry: Registry, Classes: TupleCodecClass, value?: Excl
|
||||
* own type. It extends the base JS `Array` object.
|
||||
*/
|
||||
export class Tuple extends AbstractArray<Codec> implements ITuple<Codec[]> {
|
||||
#Types: TupleCodecClass;
|
||||
readonly initialU8aLength?: number;
|
||||
|
||||
#Types: Definition;
|
||||
|
||||
constructor (registry: Registry, Types: TupleTypes | TupleType, value?: AnyTupleValue, { definition, setDefinition = noopSetDefinition }: Options = {}) {
|
||||
const Classes = definition || setDefinition(Array.isArray(Types)
|
||||
? Types.map((t) => typeToConstructor(registry, t))
|
||||
: isFunction(Types) || isString(Types)
|
||||
? [typeToConstructor(registry, Types)]
|
||||
: mapToTypeMap(registry, Types)
|
||||
const Classes = definition || setDefinition(
|
||||
Array.isArray(Types)
|
||||
? [Types.map((t) => typeToConstructor(registry, t)), []]
|
||||
: isFunction(Types) || isString(Types)
|
||||
? [[typeToConstructor(registry, Types)], []]
|
||||
: mapToTypeMap(registry, Types)
|
||||
);
|
||||
const [values, decodedLength] = isU8a(value)
|
||||
? decodeU8a(registry, value, Classes)
|
||||
: decodeTuple(registry, Classes, value);
|
||||
|
||||
super(registry, values, decodedLength);
|
||||
super(registry, Classes[0].length);
|
||||
|
||||
const [, decodedLength] = isU8a(value)
|
||||
? decodeU8a(registry, this, value, Classes, false)
|
||||
: decodeTuple(registry, this, Classes, value);
|
||||
|
||||
this.initialU8aLength = decodedLength;
|
||||
this.#Types = Classes;
|
||||
}
|
||||
|
||||
public static with (Types: TupleTypes | TupleType): CodecClass<Tuple> {
|
||||
let definition: TupleCodecClass | undefined;
|
||||
let definition: Definition | undefined;
|
||||
|
||||
// eslint-disable-next-line no-return-assign
|
||||
const setDefinition = (d: TupleCodecClass) =>
|
||||
const setDefinition = (d: Definition) =>
|
||||
definition = d;
|
||||
|
||||
return class extends Tuple {
|
||||
@@ -111,9 +109,9 @@ export class Tuple extends AbstractArray<Codec> implements ITuple<Codec[]> {
|
||||
* @description The types definition of the tuple
|
||||
*/
|
||||
public get Types (): string[] {
|
||||
return Array.isArray(this.#Types)
|
||||
? this.#Types.map((T) => new T(this.registry).toRawType())
|
||||
: Object.keys(this.#Types);
|
||||
return this.#Types[1].length
|
||||
? this.#Types[1]
|
||||
: this.#Types[0].map((T) => new T(this.registry).toRawType());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -129,11 +127,7 @@ export class Tuple extends AbstractArray<Codec> implements ITuple<Codec[]> {
|
||||
* @description Returns the base runtime type name for this instance
|
||||
*/
|
||||
public toRawType (): string {
|
||||
const types = (
|
||||
Array.isArray(this.#Types)
|
||||
? this.#Types
|
||||
: Object.values(this.#Types)
|
||||
).map((T) =>
|
||||
const types = this.#Types[0].map((T) =>
|
||||
this.registry.getClassName(T) || new T(this.registry).toRawType()
|
||||
);
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import type { HexString } from '@polkadot/util/types';
|
||||
import type { Codec, CodecClass, Registry } from '../types';
|
||||
|
||||
import { assert, compactFromU8a, logger, u8aToU8a } from '@polkadot/util';
|
||||
import { assert, compactFromU8a, isU8a, logger, u8aToU8a } from '@polkadot/util';
|
||||
|
||||
import { AbstractArray } from '../abstract/AbstractArray';
|
||||
import { decodeU8aVec, typeToConstructor } from '../utils';
|
||||
@@ -22,11 +22,24 @@ function noopSetDefinition <T extends Codec> (d: CodecClass<T>): CodecClass<T> {
|
||||
return d;
|
||||
}
|
||||
|
||||
export function decodeVec<T extends Codec> (registry: Registry, Type: CodecClass<T>, value: Uint8Array | HexString | unknown[], length = -1): [T[], number, number] {
|
||||
function decodeVecLength (value: Uint8Array | HexString | unknown[]): [Uint8Array | unknown[], number, number] {
|
||||
if (Array.isArray(value)) {
|
||||
const result = new Array<T>(value.length);
|
||||
return [value, value.length, 0];
|
||||
}
|
||||
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
const u8a = u8aToU8a(value);
|
||||
const [startAt, length] = compactFromU8a(u8a);
|
||||
|
||||
assert(length.lten(MAX_LENGTH), () => `Vec length ${length.toString()} exceeds ${MAX_LENGTH}`);
|
||||
|
||||
return [u8a, length.toNumber(), startAt];
|
||||
}
|
||||
|
||||
export function decodeVec<T extends Codec> (registry: Registry, result: T[], value: Uint8Array | HexString | unknown[], startAt: number, Type: CodecClass<T>): [number, number] {
|
||||
if (Array.isArray(value)) {
|
||||
const count = result.length;
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
const entry = value[i];
|
||||
|
||||
try {
|
||||
@@ -40,22 +53,10 @@ export function decodeVec<T extends Codec> (registry: Registry, Type: CodecClass
|
||||
}
|
||||
}
|
||||
|
||||
return [result, 0, 0];
|
||||
return [0, 0];
|
||||
}
|
||||
|
||||
const u8a = u8aToU8a(value);
|
||||
let offset = 0;
|
||||
|
||||
if (length === -1) {
|
||||
const [_offset, _length] = compactFromU8a(u8a);
|
||||
|
||||
assert(_length.lten(MAX_LENGTH), () => `Vec length ${_length.toString()} exceeds ${MAX_LENGTH}`);
|
||||
|
||||
length = _length.toNumber();
|
||||
offset = _offset;
|
||||
}
|
||||
|
||||
return decodeU8aVec(registry, u8a, offset, Type, length);
|
||||
return decodeU8aVec(registry, result, u8aToU8a(value), startAt, Type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,15 +67,22 @@ export function decodeVec<T extends Codec> (registry: Registry, Type: CodecClass
|
||||
* specific encoding/decoding on top of the base type.
|
||||
*/
|
||||
export class Vec<T extends Codec> extends AbstractArray<T> {
|
||||
readonly initialU8aLength?: number;
|
||||
|
||||
#Type: CodecClass<T>;
|
||||
|
||||
constructor (registry: Registry, Type: CodecClass<T> | string, value: Uint8Array | HexString | unknown[] = [], { definition, setDefinition = noopSetDefinition }: Options<T> = {}) {
|
||||
const Clazz = definition || setDefinition(typeToConstructor<T>(registry, Type));
|
||||
const [values, decodedLength] = decodeVec(registry, Clazz, value);
|
||||
const [decodeFrom, length, startAt] = decodeVecLength(value);
|
||||
|
||||
super(registry, values, decodedLength);
|
||||
super(registry, length);
|
||||
|
||||
this.#Type = Clazz;
|
||||
this.#Type = definition || setDefinition(typeToConstructor<T>(registry, Type));
|
||||
|
||||
const [decodedLength] = isU8a(decodeFrom)
|
||||
? decodeU8aVec(registry, this, decodeFrom, startAt, this.#Type)
|
||||
: decodeVec(registry, this, decodeFrom, startAt, this.#Type);
|
||||
|
||||
this.initialU8aLength = decodedLength;
|
||||
}
|
||||
|
||||
public static with<O extends Codec> (Type: CodecClass<O> | string): CodecClass<Vec<O>> {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import type { HexString } from '@polkadot/util/types';
|
||||
import type { Codec, CodecClass, Inspect, Registry } from '../types';
|
||||
|
||||
import { assert, isU8a, u8aConcat } from '@polkadot/util';
|
||||
import { isU8a, u8aConcat } from '@polkadot/util';
|
||||
|
||||
import { AbstractArray } from '../abstract/AbstractArray';
|
||||
import { decodeU8aVec, typeToConstructor } from '../utils';
|
||||
@@ -19,36 +19,26 @@ function noopSetDefinition <T extends Codec> (d: CodecClass<T>): CodecClass<T> {
|
||||
return d;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function decodeVecFixed<T extends Codec> (registry: Registry, value: HexString | unknown[], Type: CodecClass<T>, length: number): [T[], number, number] {
|
||||
const [values, decodedLength, decodedLengthNoOffset] = decodeVec(registry, Type, value, length);
|
||||
|
||||
while (values.length < length) {
|
||||
values.push(new Type(registry));
|
||||
}
|
||||
|
||||
assert(values.length === length, () => `Expected a length of exactly ${length} entries`);
|
||||
|
||||
return [values, decodedLength, decodedLengthNoOffset];
|
||||
}
|
||||
|
||||
/**
|
||||
* @name VecFixed
|
||||
* @description
|
||||
* This manages codec arrays of a fixed length
|
||||
*/
|
||||
export class VecFixed<T extends Codec> extends AbstractArray<T> {
|
||||
readonly initialU8aLength?: number;
|
||||
|
||||
#Type: CodecClass<T>;
|
||||
|
||||
constructor (registry: Registry, Type: CodecClass<T> | string, length: number, value: Uint8Array | HexString | unknown[] = [] as unknown[], { definition, setDefinition = noopSetDefinition }: Options<T> = {}) {
|
||||
const Clazz = definition || setDefinition(typeToConstructor<T>(registry, Type));
|
||||
const [values,, decodedLengthNoOffset] = isU8a(value)
|
||||
? decodeU8aVec(registry, value, 0, Clazz, length)
|
||||
: decodeVecFixed(registry, value, Clazz, length);
|
||||
super(registry, length);
|
||||
|
||||
super(registry, values, decodedLengthNoOffset);
|
||||
this.#Type = definition || setDefinition(typeToConstructor<T>(registry, Type));
|
||||
|
||||
this.#Type = Clazz;
|
||||
const [, decodedLengthNoOffset] = isU8a(value)
|
||||
? decodeU8aVec(registry, this, value, 0, this.#Type)
|
||||
: decodeVec(registry, this, value, 0, this.#Type);
|
||||
|
||||
this.initialU8aLength = decodedLengthNoOffset;
|
||||
}
|
||||
|
||||
public static with<O extends Codec> (Type: CodecClass<O> | string, length: number): CodecClass<VecFixed<O>> {
|
||||
|
||||
@@ -14,10 +14,12 @@ const l = logger('BTreeSet');
|
||||
function decodeSetFromU8a<V extends Codec> (registry: Registry, ValClass: CodecClass<V>, u8a: Uint8Array): [CodecClass<V>, Set<V>, number] {
|
||||
const output = new Set<V>();
|
||||
const [offset, length] = compactFromU8a(u8a);
|
||||
const [values, decodedLength] = decodeU8aVec(registry, u8a, offset, ValClass, length.toNumber());
|
||||
const count = length.toNumber();
|
||||
const result = new Array<V>(count);
|
||||
const [decodedLength] = decodeU8aVec(registry, result, u8a, offset, ValClass);
|
||||
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
output.add(values[i]);
|
||||
for (let i = 0; i < count; i++) {
|
||||
output.add(result[i] as unknown as V);
|
||||
}
|
||||
|
||||
return [ValClass, output, decodedLength];
|
||||
|
||||
@@ -24,7 +24,7 @@ function decodeMapFromU8a<K extends Codec, V extends Codec> (registry: Registry,
|
||||
types.push(KeyClass, ValClass);
|
||||
}
|
||||
|
||||
const [values, decodedLength] = decodeU8a(registry, u8a.subarray(offset), types);
|
||||
const [values, decodedLength] = decodeU8a(registry, new Array(types.length), u8a.subarray(offset), [types, []]);
|
||||
|
||||
for (let i = 0; i < values.length; i += 2) {
|
||||
output.set(values[i] as K, values[i + 1] as V);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { HexString } from '@polkadot/util/types';
|
||||
import type { AnyJson, BareOpts, Codec, CodecClass, CodecClassDef, Inspect, IStruct, IU8a, Registry } from '../types';
|
||||
import type { AnyJson, BareOpts, Codec, CodecClass, Inspect, IStruct, IU8a, Registry } from '../types';
|
||||
|
||||
import { assert, isBoolean, isFunction, isHex, isObject, isU8a, isUndefined, objectProperties, stringCamelCase, stringify, u8aConcat, u8aToHex, u8aToU8a } from '@polkadot/util';
|
||||
|
||||
@@ -10,31 +10,32 @@ import { compareMap, decodeU8a, mapToTypeMap, typesToMap } from '../utils';
|
||||
|
||||
type TypesDef<T = Codec> = Record<string, string | CodecClass<T>>;
|
||||
|
||||
type Definition = [CodecClass[], string[]];
|
||||
|
||||
interface Options {
|
||||
definition?: CodecClassDef;
|
||||
setDefinition?: (d: CodecClassDef) => CodecClassDef;
|
||||
definition?: Definition;
|
||||
setDefinition?: (d: Definition) => Definition;
|
||||
}
|
||||
|
||||
function noopSetDefinition (d: CodecClassDef): CodecClassDef {
|
||||
function noopSetDefinition (d: Definition): Definition {
|
||||
return d;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function decodeStructFromObject (registry: Registry, Types: CodecClassDef, value: any, jsonMap: Map<string, string>): [Iterable<[string, Codec]>, number] {
|
||||
function decodeStructFromObject (registry: Registry, [Types, keys]: Definition, value: any, jsonMap: Map<string, string>): [Iterable<[string, Codec]>, number] {
|
||||
let jsonObj: Record<string, unknown> | undefined;
|
||||
const inputKeys = Object.keys(Types);
|
||||
const typeofArray = Array.isArray(value);
|
||||
const typeofMap = value instanceof Map;
|
||||
|
||||
assert(typeofArray || typeofMap || isObject(value), () => `Struct: Cannot decode value ${stringify(value)} (typeof ${typeof value}), expected an input object, map or array`);
|
||||
assert(!typeofArray || value.length === inputKeys.length, () => `Struct: Unable to map ${stringify(value)} array to object with known keys ${inputKeys.join(', ')}`);
|
||||
assert(!typeofArray || value.length === keys.length, () => `Struct: Unable to map ${stringify(value)} array to object with known keys ${keys.join(', ')}`);
|
||||
|
||||
const raw = new Array<[string, Codec]>(inputKeys.length);
|
||||
const raw = new Array<[string, Codec]>(keys.length);
|
||||
|
||||
for (let i = 0; i < inputKeys.length; i++) {
|
||||
const key = inputKeys[i];
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const key = keys[i];
|
||||
const jsonKey = jsonMap.get(key) || key;
|
||||
const Type = Types[key];
|
||||
const Type = Types[i];
|
||||
let assign: unknown;
|
||||
|
||||
try {
|
||||
@@ -107,17 +108,15 @@ export class Struct<
|
||||
|
||||
readonly #jsonMap: Map<keyof S, string>;
|
||||
|
||||
readonly #Types: CodecClassDef;
|
||||
readonly #Types: Definition;
|
||||
|
||||
constructor (registry: Registry, Types: S, value?: V | Map<unknown, unknown> | unknown[] | HexString | null, jsonMap = new Map<string, string>(), { definition, setDefinition = noopSetDefinition }: Options = {}) {
|
||||
const typeMap = definition || setDefinition(mapToTypeMap(registry, Types));
|
||||
const [decoded, decodedLength] = isU8a(value)
|
||||
? decodeU8a<Codec, [string, Codec]>(registry, value, typeMap, true)
|
||||
: isHex(value)
|
||||
? decodeU8a<Codec, [string, Codec]>(registry, u8aToU8a(value), typeMap, true)
|
||||
: value instanceof Struct
|
||||
? [value as Iterable<[string, Codec]>, 0]
|
||||
: decodeStructFromObject(registry, typeMap, value || {}, jsonMap);
|
||||
const [decoded, decodedLength] = isU8a(value) || isHex(value)
|
||||
? decodeU8a<Codec, [string, Codec]>(registry, new Array(typeMap[0].length), u8aToU8a(value), typeMap, true)
|
||||
: value instanceof Struct
|
||||
? [value as Iterable<[string, Codec]>, 0]
|
||||
: decodeStructFromObject(registry, typeMap, value || {}, jsonMap);
|
||||
|
||||
super(decoded);
|
||||
|
||||
@@ -130,10 +129,10 @@ export class Struct<
|
||||
public static with<S extends TypesDef> (Types: S, jsonMap?: Map<string, string>): CodecClass<Struct<S>> {
|
||||
const keys = Object.keys(Types);
|
||||
|
||||
let definition: CodecClassDef | undefined;
|
||||
let definition: Definition | undefined;
|
||||
|
||||
// eslint-disable-next-line no-return-assign
|
||||
const setDefinition = (d: CodecClassDef) =>
|
||||
const setDefinition = (d: Definition) =>
|
||||
definition = d;
|
||||
|
||||
return class extends Struct<S> {
|
||||
@@ -149,7 +148,7 @@ export class Struct<
|
||||
* @description The available keys for this struct
|
||||
*/
|
||||
public get defKeys (): string[] {
|
||||
return Object.keys(this.#Types);
|
||||
return this.#Types[1];
|
||||
}
|
||||
|
||||
public getT <T> (key: string): T {
|
||||
@@ -174,12 +173,10 @@ export class Struct<
|
||||
*/
|
||||
public get Type (): E {
|
||||
const result: Record<string, string> = {};
|
||||
const defs = Object.entries(this.#Types);
|
||||
const [Types, keys] = this.#Types;
|
||||
|
||||
for (let i = 0; i < defs.length; i++) {
|
||||
const [key, Type] = defs[i];
|
||||
|
||||
result[key] = new Type(this.registry).toRawType();
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
result[keys[i]] = new Types[i](this.registry).toRawType();
|
||||
}
|
||||
|
||||
return result as E;
|
||||
|
||||
@@ -105,8 +105,6 @@ export interface CodecClass<T = Codec> {
|
||||
new(registry: Registry, ...args: any[]): T;
|
||||
}
|
||||
|
||||
export type CodecClassDef<T = Codec> = Record<string, CodecClass<T>>;
|
||||
|
||||
export type CodecTo = 'toHex' | 'toJSON' | 'toString' | 'toU8a';
|
||||
|
||||
export type ArgsDef = Record<string, CodecClass | string>;
|
||||
|
||||
@@ -25,22 +25,18 @@ function getRawType (registry: Registry, Type: CodecClass): string | null {
|
||||
* @param result - The result array (will be returned with values pushed)
|
||||
* @param types - The array of CodecClass to decode the U8a against.
|
||||
*/
|
||||
export function decodeU8a <T extends Codec = Codec, E = T> (registry: Registry, u8a: Uint8Array, types: CodecClass[] | { [index: string]: CodecClass }, withZip?: boolean): [E[], number] {
|
||||
const [Types, keys]: [CodecClass[], string[]] = Array.isArray(types)
|
||||
? [types, []]
|
||||
: [Object.values(types), Object.keys(types)];
|
||||
|
||||
const result = new Array<E>(Types.length);
|
||||
export function decodeU8a <T extends Codec = Codec, E = T> (registry: Registry, result: unknown[], u8a: Uint8Array, [Types, keys]: [CodecClass[], string[]], withZip?: boolean): [E[], number] {
|
||||
const count = result.length;
|
||||
let offset = 0;
|
||||
|
||||
for (let i = 0; i < Types.length; i++) {
|
||||
for (let i = 0; i < count; i++) {
|
||||
try {
|
||||
const value = new Types[i](registry, u8a.subarray(offset));
|
||||
|
||||
offset += value.initialU8aLength || value.encodedLength;
|
||||
result[i] = withZip
|
||||
? [keys[i], value] as unknown as E
|
||||
: value as unknown as E;
|
||||
? [keys[i], value]
|
||||
: value;
|
||||
} catch (error) {
|
||||
throw new Error(formatFailure(
|
||||
error as Error,
|
||||
@@ -51,14 +47,14 @@ export function decodeU8a <T extends Codec = Codec, E = T> (registry: Registry,
|
||||
}
|
||||
}
|
||||
|
||||
return [result, offset];
|
||||
return [result as E[], offset];
|
||||
}
|
||||
|
||||
// Split from decodeU8a since this is specialized to 1 instance ... yes duplication, but
|
||||
// since we have to do less checks (and these are intensive anyway), much faster
|
||||
export function decodeU8aVec <T extends Codec = Codec> (registry: Registry, u8a: Uint8Array, start: number, Type: CodecClass<T>, count: number): [T[], number, number] {
|
||||
const result = new Array<T>(count);
|
||||
let offset = start;
|
||||
export function decodeU8aVec <T extends Codec = Codec> (registry: Registry, result: unknown[], u8a: Uint8Array, startAt: number, Type: CodecClass<T>): [number, number] {
|
||||
const count = result.length;
|
||||
let offset = startAt;
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
try {
|
||||
@@ -75,5 +71,5 @@ export function decodeU8aVec <T extends Codec = Codec> (registry: Registry, u8a:
|
||||
}
|
||||
}
|
||||
|
||||
return [result, offset, offset - start];
|
||||
return [offset, offset - startAt];
|
||||
}
|
||||
|
||||
@@ -8,12 +8,14 @@ import { typeToConstructor } from './typeToConstructor';
|
||||
/**
|
||||
* @description takes an input map of the form `{ [string]: string | CodecClass }` and returns a map of `{ [string]: CodecClass }`
|
||||
*/
|
||||
export function mapToTypeMap (registry: Registry, input: Record<string, string | CodecClass>): Record<string, CodecClass> {
|
||||
export function mapToTypeMap (registry: Registry, input: Record<string, string | CodecClass>): [CodecClass[], string[]] {
|
||||
const entries = Object.entries(input);
|
||||
const output: Record<string, CodecClass> = {};
|
||||
const count = entries.length;
|
||||
const output: [CodecClass[], string[]] = [new Array<CodecClass>(count), new Array<string>(count)];
|
||||
|
||||
for (let i = 0; i < entries.length; i++) {
|
||||
output[entries[i][0]] = typeToConstructor(registry, entries[i][1]);
|
||||
output[1][i] = entries[i][0];
|
||||
output[0][i] = typeToConstructor(registry, entries[i][1]);
|
||||
}
|
||||
|
||||
return output;
|
||||
|
||||
@@ -3,14 +3,11 @@
|
||||
|
||||
import type { CodecClass, Registry } from '../types';
|
||||
|
||||
export function typesToMap (registry: Registry, Types: Record<string, CodecClass>): Record<string, string> {
|
||||
const entries = Object.entries(Types);
|
||||
export function typesToMap (registry: Registry, [Types, keys]: [CodecClass[], string[]]): Record<string, string> {
|
||||
const result: Record<string, string> = {};
|
||||
|
||||
for (let i = 0; i < entries.length; i++) {
|
||||
const [key, Type] = entries[i];
|
||||
|
||||
result[key] = registry.getClassName(Type) || new Type(registry).toRawType();
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
result[keys[i]] = registry.getClassName(Types[i]) || new Types[i](registry).toRawType();
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -117,11 +117,13 @@ function getAliasPath (path: SiPath): string | null {
|
||||
: null;
|
||||
}
|
||||
|
||||
function hasNoDupes (input: [number, string, SiTypeParameter[]][]): boolean {
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
function hasNoDupes (input: [number, string][]): boolean {
|
||||
const count = input.length;
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
const [ai, an] = input[i];
|
||||
|
||||
for (let j = 0; j < input.length; j++) {
|
||||
for (let j = i + 1; j < count; j++) {
|
||||
const [bi, bn] = input[j];
|
||||
|
||||
// if the indexes are not the same and the names match, we have a dupe
|
||||
@@ -177,7 +179,7 @@ function removeDuplicateNames (lookup: PortableRegistry, names: [number, string
|
||||
}
|
||||
|
||||
// see if using the param type helps
|
||||
const adjusted = new Array<[number, string, SiTypeParameter[]]>(allSame.length);
|
||||
const adjusted = new Array<[number, string]>(allSame.length);
|
||||
|
||||
for (let i = 0; i < allSame.length; i++) {
|
||||
const [oIndex, oName, oParams] = allSame[i];
|
||||
@@ -191,8 +193,7 @@ function removeDuplicateNames (lookup: PortableRegistry, names: [number, string
|
||||
oIndex,
|
||||
def.isPrimitive
|
||||
? `${oName}${def.asPrimitive.toString()}`
|
||||
: `${oName}${path[path.length - 1].toString()}`,
|
||||
params
|
||||
: `${oName}${path[path.length - 1].toString()}`
|
||||
];
|
||||
}
|
||||
|
||||
@@ -217,29 +218,36 @@ function removeDuplicateNames (lookup: PortableRegistry, names: [number, string
|
||||
}
|
||||
|
||||
function extractName (types: PortableType[], { id, type: { params, path } }: PortableType): [number, string, SiTypeParameter[]] | null {
|
||||
const last = path.length - 1;
|
||||
|
||||
// if we have no path or determined as a wrapper, we just skip it
|
||||
if (!path.length || WRAPPERS.includes(path[path.length - 1].toString())) {
|
||||
if (last === -1 || WRAPPERS.includes(path[last].toString())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const parts = path
|
||||
.map((p) => stringPascalCase(p))
|
||||
.filter((p, index) => {
|
||||
const lower = p.toLowerCase();
|
||||
const parts: string[] = [];
|
||||
let typeName = '';
|
||||
|
||||
return (
|
||||
for (let i = 0; i <= last; i++) {
|
||||
const p = stringPascalCase(path[i]);
|
||||
const l = p.toLowerCase();
|
||||
|
||||
if (
|
||||
(
|
||||
// Remove ::{generic, misc, pallet, traits, types}::
|
||||
index !== 1 ||
|
||||
!PATH_RM_INDEX_1.includes(lower)
|
||||
i !== 1 ||
|
||||
!PATH_RM_INDEX_1.includes(l)
|
||||
) &&
|
||||
(
|
||||
// sp_runtime::generic::digest::Digest -> sp_runtime::generic::Digest
|
||||
// sp_runtime::multiaddress::MultiAddress -> sp_runtime::MultiAddress
|
||||
index === path.length - 1 ||
|
||||
lower !== path[index + 1].toLowerCase()
|
||||
);
|
||||
});
|
||||
let typeName = parts.join('');
|
||||
i === last ||
|
||||
l !== path[i + 1].toLowerCase()
|
||||
)) {
|
||||
parts.push(p);
|
||||
typeName += p;
|
||||
}
|
||||
}
|
||||
|
||||
// do magic for RawOrigin lookup, e.g. pallet_collective::RawOrigin
|
||||
if (parts.length === 2 && parts[1] === 'RawOrigin' && params.length === 2 && params[1].type.isSome) {
|
||||
|
||||
Reference in New Issue
Block a user