Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract short type aliases for Portable types #4488

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 75 additions & 22 deletions packages/types/src/metadata/PortableRegistry/PortableRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { assert, isNumber, isString, objectSpread, stringCamelCase, stringify, s

import { assertUnreachable } from './util';

type Named = [number, string, SiTypeParameter[], string[]];

// Just a placeholder for a type.unrwapOr()
const TYPE_UNWRAP = { toNumber: () => -1 };

Expand Down Expand Up @@ -116,7 +118,7 @@ function getAliasPath (path: SiPath): string | null {
: null;
}

function hasNoDupes (input: [number, string, SiTypeParameter[]][]): boolean {
function hasNoDupes (input: Named[]): boolean {
for (let i = 0; i < input.length; i++) {
const [ai, an] = input[i];

Expand All @@ -133,17 +135,17 @@ function hasNoDupes (input: [number, string, SiTypeParameter[]][]): boolean {
return true;
}

function removeDuplicateNames (lookup: PortableRegistry, names: [number, string | null, SiTypeParameter[]][]): [number, string, SiTypeParameter[]][] {
function removeDuplicateNames (lookup: PortableRegistry, names: [number, string | null, SiTypeParameter[], string[]][]): Named[] {
const rewrite: Record<number, string> = {};

return names
.map(([lookupIndex, name, params]): [number, string, SiTypeParameter[]] | null => {
.map(([lookupIndex, name, params, aliases]): Named | null => {
if (!name) {
return null;
}

// those where the name is matching (since name is filtered, these all do have names)
const allSame = names.filter(([, oName]) => name === oName) as [number, string, SiTypeParameter[]][];
const allSame = names.filter(([, oName]) => name === oName) as Named[];

// are there among matching names
const anyDiff = allSame.some(([oIndex,, oParams]) =>
Expand All @@ -158,7 +160,7 @@ function removeDuplicateNames (lookup: PortableRegistry, names: [number, string

// everything matches, we can combine these
if (!anyDiff || !allSame[0][2].length) {
return [lookupIndex, name, params];
return [lookupIndex, name, params, aliases];
}

// find the first parameter that yields differences
Expand All @@ -172,14 +174,14 @@ function removeDuplicateNames (lookup: PortableRegistry, names: [number, string

// No param found that is different
if (paramIdx === -1) {
return [lookupIndex, name, params];
return [lookupIndex, name, params, aliases];
}

// see if using the param type helps
const adjusted = new Array<[number, string, SiTypeParameter[]]>(allSame.length);
const adjusted = new Array<Named>(allSame.length);

for (let i = 0; i < allSame.length; i++) {
const [oIndex, oName, oParams] = allSame[i];
const [oIndex, oName, oParams, oAlias] = allSame[i];
const { def, path } = lookup.getSiType(oParams[paramIdx].type.unwrap());

if (!def.isPrimitive && !path.length) {
Expand All @@ -191,7 +193,8 @@ function removeDuplicateNames (lookup: PortableRegistry, names: [number, string
def.isPrimitive
? `${oName}${def.asPrimitive.toString()}`
: `${oName}${path[path.length - 1].toString()}`,
params
params,
oAlias
];
}

Expand All @@ -202,25 +205,56 @@ function removeDuplicateNames (lookup: PortableRegistry, names: [number, string
rewrite[index] = name;
}

return [lookupIndex, name, params];
return [lookupIndex, name, params, aliases];
}

return null;
})
.filter((n): n is [number, string, SiTypeParameter[]] => !!n)
.map(([lookupIndex, name, params]) => [
.filter((n): n is Named => !!n)
.map(([lookupIndex, name, params, aliases]) => [
lookupIndex,
rewrite[lookupIndex] || name,
params
params,
aliases
]);
}

function extractName (types: PortableType[], { id, type: { params, path } }: PortableType): [number, string, SiTypeParameter[]] | null {
function removeDuplicateAliases (list: Named[]): Named[] {
const dupes: string[] = [];

for (let i = 0; i < list.length; i++) {
const [,,, aliases] = list[i];

for (let j = 0; j < list.length; j++) {
if (i !== j) {
const [,,, others] = list[j];

for (let a = 1; a < aliases.length; a++) {
const alias = aliases[a];

if (!dupes.includes(alias) && others.includes(alias)) {
dupes.push(alias);
}
}
}
Comment on lines +228 to +239

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

x2 faster:

Suggested change
for (let j = 0; j < list.length; j++) {
if (i !== j) {
const [,,, others] = list[j];
for (let a = 1; a < aliases.length; a++) {
const alias = aliases[a];
if (!dupes.includes(alias) && others.includes(alias)) {
dupes.push(alias);
}
}
}
for (let j = i + 1; j < list.length; j++) {
const [,,, others] = list[j];
for (let a = 1; a < aliases.length; a++) {
const alias = aliases[a];
if (!dupes.includes(alias) && others.includes(alias)) {
dupes.push(alias);
}
}

}
}

return list.map(([lookupIndex, name, params, aliases]) => [
lookupIndex,
name,
params,
aliases.slice(1).filter((a) => !dupes.includes(a))
]);
Comment on lines +243 to +248

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Less memory consuming by mutate array items:

Suggested change
return list.map(([lookupIndex, name, params, aliases]) => [
lookupIndex,
name,
params,
aliases.slice(1).filter((a) => !dupes.includes(a))
]);
return list.map((item) => {
item[3] = item[3].slice(1).filter((a) => !dupes.includes(a))
return item
});

}

function extractName (types: PortableType[], { id, type: { params, path } }: PortableType): Named | null {
// if we have no path or determined as a wrapper, we just skip it
if (!path.length || WRAPPERS.includes(path[path.length - 1].toString())) {
return null;
}

const aliases = [];
const parts = path
.map((p) => stringPascalCase(p))
.filter((p, index) => {
Expand All @@ -238,7 +272,15 @@ function extractName (types: PortableType[], { id, type: { params, path } }: Por
lower !== path[index + 1].toLowerCase()
);
});
let typeName = parts.join('');

// based on the input, combine various parts to create type aliases, e.g
// [sp_runtime::generic::Digest, generic::Digest, Digest]
for (let i = 0; i < parts.length; i++) {
aliases.push(parts.slice(i).join(''));
}

// the first alias contains all info, this is the canonical typeName
let typeName = aliases[0];

// do magic for RawOrigin lookup, e.g. pallet_collective::RawOrigin
if (parts.length === 2 && parts[1] === 'RawOrigin' && params.length === 2 && params[1].type.isSome) {
Expand All @@ -249,7 +291,7 @@ function extractName (types: PortableType[], { id, type: { params, path } }: Por
}
}

return [id.toNumber(), typeName, params];
return [id.toNumber(), typeName, params, aliases];
}

function registerTypes (lookup: PortableRegistry, lookups: Record<string, string>, names: Record<number, string>, params: Record<string, SiTypeParameter[]>): void {
Expand Down Expand Up @@ -290,8 +332,8 @@ function registerTypes (lookup: PortableRegistry, lookups: Record<string, string
}
}

function extractTypeInfo (lookup: PortableRegistry, portable: PortableType[]): [Record<number, PortableType>, Record<string, string>, Record<number, string>, Record<string, SiTypeParameter[]>] {
const nameInfo: [number, string, SiTypeParameter[]][] = [];
function extractTypeInfo (lookup: PortableRegistry, portable: PortableType[]): [Record<number, PortableType>, Record<string, string>, Record<number, string>, Record<string, SiTypeParameter[]>, Record<number, string[]>] {
const nameInfo: Named[] = [];
const types: Record<number, PortableType> = {};

for (let i = 0; i < portable.length; i++) {
Expand All @@ -305,23 +347,26 @@ function extractTypeInfo (lookup: PortableRegistry, portable: PortableType[]): [
types[type.id.toNumber()] = type;
}

const dedup = removeDuplicateNames(lookup, nameInfo);
const dedup = removeDuplicateAliases(removeDuplicateNames(lookup, nameInfo));
const lookups: Record<string, string> = {};
const names: Record<number, string> = {};
const params: Record<string, SiTypeParameter[]> = {};
const aliases: Record<number, string[]> = {};

for (let i = 0; i < dedup.length; i++) {
const [lookupIndex, name, p] = dedup[i];
const [lookupIndex, name, p, a] = dedup[i];

aliases[lookupIndex] = a;
names[lookupIndex] = name;
lookups[name] = lookup.registry.createLookupType(lookupIndex);
params[name] = p;
}

return [types, lookups, names, params];
return [types, lookups, names, params, aliases];
}

export class PortableRegistry extends Struct implements ILookup {
#aliases: Record<number, string[]>;
#names: Record<number, string>;
#typeDefs: Record<number, TypeDef> = {};
#types: Record<number, PortableType>;
Expand All @@ -333,8 +378,9 @@ export class PortableRegistry extends Struct implements ILookup {
types: 'Vec<PortableType>'
}, value);

const [types, lookups, names, params] = extractTypeInfo(this, this.types);
const [types, lookups, names, params, aliases] = extractTypeInfo(this, this.types);

this.#aliases = aliases;
this.#names = names;
this.#types = types;

Expand All @@ -354,6 +400,13 @@ export class PortableRegistry extends Struct implements ILookup {
return this.getT('types');
}

/**
* @description Returns the aliases for this specific type
*/
public getAliases (lookupId: SiLookupTypeId | string | number): string[] {
return this.#aliases[this.#getLookupId(lookupId)] || [];
}

/**
* @description Returns the name for a specific lookup
*/
Expand Down