Internal adjustments (part 4) (#4136)

* Internal adjustments (part 3)

* Internal adjustments (part 4)

* Additional

* Additional

* Fix set encoding
This commit is contained in:
Jaco
2021-11-01 11:01:31 +02:00
committed by GitHub
parent 4a893b9feb
commit d24db4fd6a
8 changed files with 164 additions and 103 deletions
+24 -13
View File
@@ -11,33 +11,44 @@ import { compareArray } from './utils';
type SetValues = Record<string, number | BN>;
function encodeSet (setValues: SetValues, value: string[]): BN {
return value.reduce((result, value): BN => {
return result.or(bnToBn(setValues[value] || 0));
}, new BN(0));
function encodeSet (setValues: SetValues, values: string[]): BN {
const encoded = new BN(0);
for (let i = 0; i < values.length; i++) {
encoded.ior(bnToBn(setValues[values[i]] || 0));
}
return encoded;
}
/** @internal */
function decodeSetArray (setValues: SetValues, value: string[]): string[] {
return value.reduce<string[]>((result, key): string[] => {
function decodeSetArray (setValues: SetValues, values: string[]): string[] {
const result = new Array<string>(values.length);
for (let i = 0; i < values.length; i++) {
const key = values[i];
assert(!isUndefined(setValues[key]), () => `Set: Invalid key '${key}' passed to Set, allowed ${Object.keys(setValues).join(', ')}`);
result.push(key);
result[i] = key;
}
return result;
}, []);
return result;
}
/** @internal */
function decodeSetNumber (setValues: SetValues, _value: BN | number): string[] {
const bn = bnToBn(_value);
const result = Object.keys(setValues).reduce<string[]>((result, key): string[] => {
const keys = Object.keys(setValues);
const result: string[] = [];
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
if (bn.and(bnToBn(setValues[key])).eq(bnToBn(setValues[key]))) {
result.push(key);
}
return result;
}, []);
}
const computed = encodeSet(setValues, result);
+38 -20
View File
@@ -21,14 +21,17 @@ function decodeStructFromObject (registry: Registry, Types: ConstructorDef, valu
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(', ')}`);
return inputKeys.reduce<[string, Codec][]>((raw, key, index) => {
const raw = new Array<[string, Codec]>(inputKeys.length);
for (let i = 0; i < inputKeys.length; i++) {
const key = inputKeys[i];
const jsonKey = jsonMap.get(key) || key;
const Type = Types[key];
let assign: unknown;
try {
if (typeofArray) {
assign = value[index] as unknown;
assign = value[i] as unknown;
} else if (typeofMap) {
assign = jsonKey && value.get(jsonKey);
} else {
@@ -36,23 +39,25 @@ function decodeStructFromObject (registry: Registry, Types: ConstructorDef, valu
if (isUndefined(assign)) {
if (isUndefined(jsonObj)) {
jsonObj = Object.entries(value).reduce((all: Record<string, unknown>, [k, v]): Record<string, unknown> => {
all[stringCamelCase(k)] = v;
const entries = Object.entries(value);
return all;
}, {});
jsonObj = {};
for (let e = 0; e < entries.length; e++) {
jsonObj[stringCamelCase(entries[e][0])] = entries[e][1];
}
}
assign = jsonKey && jsonObj[jsonKey];
}
}
raw.push([
raw[i] = [
key,
assign instanceof Type
? assign
: new Type(registry, assign)
]);
];
} catch (error) {
let type = Type.name;
@@ -64,9 +69,9 @@ function decodeStructFromObject (registry: Registry, Types: ConstructorDef, valu
throw new Error(`Struct: failed on ${jsonKey}: ${type}:: ${(error as Error).message}`);
}
}
return raw;
}, []);
return raw;
}
/**
@@ -154,11 +159,16 @@ export class Struct<
}
public static typesToMap (registry: Registry, Types: Record<string, Constructor>): Record<string, string> {
return Object.entries(Types).reduce((result: Record<string, string>, [key, Type]): Record<string, string> => {
result[key] = registry.getClassName(Type) || new Type(registry).toRawType();
const entries = Object.entries(Types);
const result: Record<string, string> = {};
return result;
}, {});
for (let i = 0; i < entries.length; i++) {
const [key, Type] = entries[i];
result[key] = registry.getClassName(Type) || new Type(registry).toRawType();
}
return result;
}
/**
@@ -266,27 +276,35 @@ export class Struct<
* @description Converts the Object to to a human-friendly JSON, with additional fields, expansion and formatting of information
*/
public toHuman (isExtended?: boolean): Record<string, AnyJson> {
return [...this.keys()].reduce((json: Record<string, AnyJson>, key): Record<string, AnyJson> => {
const json: Record<string, AnyJson> = {};
const keys = [...this.keys()];
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const value = this.get(key);
json[key as string] = value && value.toHuman(isExtended);
}
return json;
}, {});
return json;
}
/**
* @description Converts the Object to JSON, typically used for RPC transfers
*/
public toJSON (): Record<string, AnyJson> {
return [...this.keys()].reduce((json: Record<string, AnyJson>, key): Record<string, AnyJson> => {
const json: Record<string, AnyJson> = {};
const keys = [...this.keys()];
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const jsonKey = this.#jsonMap.get(key) || key;
const value = this.get(key);
json[jsonKey as string] = value && value.toJSON();
}
return json;
}, {});
return json;
}
/**
@@ -9,11 +9,12 @@ import { typeToConstructor } from './typeToConstructor';
* @description takes an input map of the form `{ [string]: string | Constructor }` and returns a map of `{ [string]: Constructor }`
*/
export function mapToTypeMap (registry: Registry, input: Record<string, string | Constructor>): Record<string, Constructor> {
return Object
.entries(input)
.reduce((output: Record<string, Constructor>, [key, type]): Record<string, Constructor> => {
output[key] = typeToConstructor(registry, type);
const entries = Object.entries(input);
const output: Record<string, Constructor> = {};
return output;
}, {});
for (let i = 0; i < entries.length; i++) {
output[entries[i][0]] = typeToConstructor(registry, entries[i][1]);
}
return output;
}
+15 -10
View File
@@ -12,6 +12,10 @@ import { Bytes, Null } from '../primitive';
import { getTypeDef } from './getTypeDef';
import { TypeDefInfo } from './types';
function getTypeDefType ({ lookupName, type }: TypeDef): string {
return lookupName || type;
}
function getSubDefArray (value: TypeDef): TypeDef[] {
assert(value.sub && Array.isArray(value.sub), () => `Expected subtype as TypeDef[] in ${stringify(value)}`);
@@ -25,23 +29,24 @@ function getSubDef (value: TypeDef): TypeDef {
}
function getSubType (value: TypeDef): string {
const { lookupName, type } = getSubDef(value);
return lookupName || type;
return getTypeDefType(getSubDef(value));
}
// create a maps of type string constructors from the input
function getTypeClassMap (value: TypeDef): Record<string, string> {
return getSubDefArray(value).reduce<Record<string, string>>((result, { lookupName, name, type }) => {
result[name as string] = lookupName || type;
const subs = getSubDefArray(value);
const map: Record<string, string> = {};
return result;
}, {});
for (let i = 0; i < subs.length; i++) {
map[subs[i].name as string] = getTypeDefType(subs[i]);
}
return map;
}
// create an array of type string constructors from the input
function getTypeClassArray (value: TypeDef): string[] {
return getSubDefArray(value).map(({ lookupName, type }) => lookupName || type);
return getSubDefArray(value).map(getTypeDefType);
}
function createInt ({ displayName, length }: TypeDef, Clazz: typeof Int | typeof UInt): Constructor<Codec> {
@@ -152,7 +157,7 @@ const infoMapping: Record<TypeDefInfo, (registry: Registry, value: TypeDef) => C
return (
sub.type === 'u8'
? Bytes
: Vec.with(sub.lookupName || sub.type)
: Vec.with(getTypeDefType(sub))
);
},
@@ -162,7 +167,7 @@ const infoMapping: Record<TypeDefInfo, (registry: Registry, value: TypeDef) => C
return (
sub.type === 'u8'
? U8aFixed.with((length * 8) as U8aBitLength, displayName)
: VecFixed.with(sub.lookupName || sub.type, length)
: VecFixed.with(getTypeDefType(sub), length)
);
},
+7 -4
View File
@@ -44,10 +44,13 @@ function encodeSubTypes (registry: Registry, sub: TypeDef[], asEnum?: boolean, e
assert(names.every((n) => !!n), () => `Subtypes does not have consistent names, ${names.join(', ')}`);
const inner = sub.reduce< Record<string, string>>((result, type) => ({
...result,
[type.name as string]: encodeTypeDef(registry, type)
}), { ...(extra as Record<string, string>) });
const inner: Record<string, string> = { ...(extra as Record<string, string>) };
for (let i = 0; i < sub.length; i++) {
const def = sub[i];
inner[def.name as string] = encodeTypeDef(registry, def);
}
return stringify(
asEnum
+7 -3
View File
@@ -230,7 +230,11 @@ export function removeWrap (check: string): Mapper {
// eslint-disable-next-line @typescript-eslint/ban-types
export function sanitize (value: String | string, options?: SanitizeOptions): string {
return mappings.reduce<string>((result, fn) =>
fn(result, options), value.toString()
).trim();
let result = value.toString();
for (let i = 0; i < mappings.length; i++) {
result = mappings[i](result, options);
}
return result.trim();
}
@@ -60,6 +60,10 @@ function splitNamespace (values: string[]): string[][] {
return values.map((v) => v.split('::'));
}
function sanitizeDocs (docs: Text[]): string[] {
return docs.map((d) => d.toString());
}
function matchParts (first: string[], second: (string | Text)[]): boolean {
return first.length === second.length && first.every((a, index) => {
const b = second[index].toString();
@@ -220,17 +224,17 @@ function extractNames (lookup: GenericPortableRegistry, types: PortableType[]):
extractName(types, t)
));
const [names, typesNew] = dedup.reduce<[Record<number, string>, Record<string, string>]>(([names, types], [lookupIndex, name]) => {
// We set the name for this specific type
const names: Record<number, string> = {};
const lookups: Record<string, string> = {};
for (let i = 0; i < dedup.length; i++) {
const [lookupIndex, name] = dedup[i];
names[lookupIndex] = name;
lookups[name] = lookup.registry.createLookupType(lookupIndex);
}
// we map to the actual lookupIndex
types[name] = lookup.registry.createLookupType(lookupIndex);
return [names, types];
}, [{}, {}]);
lookup.registry.register(typesNew);
lookup.registry.register(lookups);
return names;
}
@@ -238,11 +242,15 @@ function extractNames (lookup: GenericPortableRegistry, types: PortableType[]):
// types have an id, which means they are to be named by
// the specified id - ensure we have a mapping lookup for these
function extractTypeMap (types: PortableType[]): Record<number, PortableType> {
return types.reduce<Record<number, PortableType>>((types, pt) => {
types[pt.id.toNumber()] = pt;
const result: Record<number, PortableType> = {};
return types;
}, {});
for (let i = 0; i < types.length; i++) {
const p = types[i];
result[p.id.toNumber()] = p;
}
return result;
}
export class GenericPortableRegistry extends Struct {
@@ -396,7 +404,7 @@ export class GenericPortableRegistry extends Struct {
}
return {
docs: type.docs.map((d) => d.toString()),
docs: sanitizeDocs(type.docs),
namespace,
...typeDef
};
@@ -493,11 +501,15 @@ export class GenericPortableRegistry extends Struct {
}
#extractFields (lookupIndex: number, fields: SiField[]): TypeDef {
const [isStruct, isTuple] = fields.reduce(([isAllNamed, isAllUnnamed], { name }) => ([
isAllNamed && name.isSome,
isAllUnnamed && name.isNone
]),
[true, true]);
let isStruct = true;
let isTuple = true;
for (let f = 0; f < fields.length; f++) {
const { name } = fields[f];
isStruct = isStruct && name.isSome;
isTuple = isTuple && name.isNone;
}
assert(isTuple || isStruct, 'Invalid fields type detected, expected either Tuple (all unnamed) or Struct (all named)');
@@ -551,38 +563,41 @@ export class GenericPortableRegistry extends Struct {
#extractFieldsAlias (fields: SiField[]): [TypeDef[], Map<string, string>] {
const alias = new Map<string, string>();
const sub = fields.map(({ docs, name, type, typeName }) => {
const sub = new Array<TypeDef>(fields.length);
for (let i = 0; i < fields.length; i++) {
const { docs, name, type, typeName } = fields[i];
const typeDef = this.#createSiDef(type);
if (name.isNone) {
return typeDef;
sub[i] = typeDef;
} else {
let nameField = stringCamelCase(name.unwrap());
let nameOrig: string | null = null;
if (nameField.includes('#')) {
nameOrig = nameField;
nameField = nameOrig.replace(/#/g, '_');
} else if (RESERVED.includes(nameField)) {
nameOrig = nameField;
nameField = `${nameField}_`;
}
if (nameOrig) {
alias.set(nameField, nameOrig);
}
sub[i] = {
...typeDef,
docs: sanitizeDocs(docs),
name: nameField,
...(typeName.isSome
? { typeName: sanitize(typeName.unwrap()) }
: {}
)
};
}
let nameField = stringCamelCase(name.unwrap());
let nameOrig: string | null = null;
if (nameField.includes('#')) {
nameOrig = nameField;
nameField = nameOrig.replace(/#/g, '_');
} else if (RESERVED.includes(nameField)) {
nameOrig = nameField;
nameField = `${nameField}_`;
}
if (nameOrig) {
alias.set(nameField, nameOrig);
}
return {
...typeDef,
docs: docs.map((d) => d.toString()),
name: nameField,
...(typeName.isSome
? { typeName: sanitize(typeName.unwrap()) }
: {}
)
};
});
}
return [sub, alias];
}
@@ -31,10 +31,14 @@ export class MetadataVersioned extends Struct {
readonly #converted = new Map<MetaVersions, MetaMapped>();
constructor (registry: Registry, value?: unknown) {
// console.time('MetadataVersioned')
super(registry, {
magicNumber: MagicNumber,
metadata: 'MetadataAll'
}, value as Map<unknown, unknown>);
// console.timeEnd('MetadataVersioned')
}
#assertVersion = (version: number): boolean => {