Allow BTreeMap.with('u32', 'Text') (not only classes) (#1483)
This commit is contained in:
@@ -2,28 +2,35 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import Compact from './Compact';
|
||||
import U8a from './U8a';
|
||||
import { compareMap, decodeU8a } from './utils';
|
||||
import { AnyJson, Constructor, Codec, IHash } from '../types';
|
||||
import { AnyJson, Constructor, Codec, IHash, InterfaceTypes } from '../types';
|
||||
|
||||
import { isHex, hexToU8a, isU8a, u8aConcat, u8aToHex, u8aToU8a } from '@polkadot/util';
|
||||
import { blake2AsU8a } from '@polkadot/util-crypto';
|
||||
|
||||
export default class BTreeMap<K extends Codec = Codec, V extends Codec = Codec> extends Map<K, V> implements Codec {
|
||||
protected _key: Constructor<K>
|
||||
protected _val: Constructor<V>
|
||||
import Compact from './Compact';
|
||||
import U8a from './U8a';
|
||||
import { compareMap, decodeU8a, typeToConstructor } from './utils';
|
||||
|
||||
constructor (keyT: Constructor<K>, valueT: Constructor<V>, rawValue: any) {
|
||||
super(BTreeMap.decodeBTreeMap(keyT, valueT, rawValue));
|
||||
this._key = keyT;
|
||||
this._val = valueT;
|
||||
export default class BTreeMap<K extends Codec = Codec, V extends Codec = Codec> extends Map<K, V> implements Codec {
|
||||
protected _KeyClass: Constructor<K>;
|
||||
|
||||
protected _ValClass: Constructor<V>;
|
||||
|
||||
constructor (keyType: Constructor<K> | InterfaceTypes, valType: Constructor<V> | InterfaceTypes, rawValue: any) {
|
||||
const KeyClass = typeToConstructor(keyType);
|
||||
const ValClass = typeToConstructor(valType);
|
||||
|
||||
super(BTreeMap.decodeBTreeMap(KeyClass, ValClass, rawValue));
|
||||
|
||||
this._KeyClass = KeyClass;
|
||||
this._ValClass = ValClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode input to pass into constructor.
|
||||
*
|
||||
* @param keyConstructor - Type of the map key
|
||||
* @param valueConstructor - Type of the map value
|
||||
* @param KeyClass - Type of the map key
|
||||
* @param ValClass - Type of the map value
|
||||
* @param value - Value to decode, one of:
|
||||
* - null
|
||||
* - undefined
|
||||
@@ -33,49 +40,31 @@ export default class BTreeMap<K extends Codec = Codec, V extends Codec = Codec>
|
||||
* constructors or decodeable values for their types.
|
||||
* @param jsonMap
|
||||
*/
|
||||
public static decodeBTreeMap<K extends Codec = Codec, V extends Codec = Codec> (
|
||||
KeyConstructor: Constructor<K>,
|
||||
ValueConstructor: Constructor<V>,
|
||||
value: Uint8Array | string | Map<any, any>): Map<K, V> {
|
||||
private static decodeBTreeMap<K extends Codec = Codec, V extends Codec = Codec> (KeyClass: Constructor<K>, ValClass: Constructor<V>, value: Uint8Array | string | Map<any, any>): Map<K, V> {
|
||||
if (!value) {
|
||||
return new Map<K, V>();
|
||||
}
|
||||
|
||||
// Convert hex values to UA8 and re-run the function
|
||||
if (isHex(value)) {
|
||||
return BTreeMap.decodeBTreeMap(
|
||||
KeyConstructor,
|
||||
ValueConstructor,
|
||||
hexToU8a(value)
|
||||
);
|
||||
}
|
||||
|
||||
// Values already in U8A can be processed
|
||||
if (isU8a(value)) {
|
||||
return BTreeMap.decodeBTreeMapFromU8a<K, V>(KeyConstructor, ValueConstructor, u8aToU8a(value));
|
||||
}
|
||||
|
||||
// Try to handle map types
|
||||
if (value instanceof Map) {
|
||||
return BTreeMap.decodeBTreeMapFromMap<K, V>(KeyConstructor, ValueConstructor, value);
|
||||
} else if (isHex(value)) {
|
||||
return BTreeMap.decodeBTreeMap(KeyClass, ValClass, hexToU8a(value));
|
||||
} else if (isU8a(value)) {
|
||||
return BTreeMap.decodeBTreeMapFromU8a<K, V>(KeyClass, ValClass, u8aToU8a(value));
|
||||
} else if (value instanceof Map) {
|
||||
return BTreeMap.decodeBTreeMapFromMap<K, V>(KeyClass, ValClass, value);
|
||||
}
|
||||
|
||||
throw new Error('BTreeMap: cannot decode type');
|
||||
}
|
||||
|
||||
public static decodeBTreeMapFromU8a<K extends Codec = Codec, V extends Codec = Codec> (
|
||||
KeyConstructor: Constructor<K>,
|
||||
ValueConstructor: Constructor<V>,
|
||||
u8a: Uint8Array): Map<K, V> {
|
||||
private static decodeBTreeMapFromU8a<K extends Codec = Codec, V extends Codec = Codec> (KeyClass: Constructor<K>, ValClass: Constructor<V>, u8a: Uint8Array): Map<K, V> {
|
||||
const output = new Map<K, V>();
|
||||
const [offset, length] = Compact.decodeU8a(u8a);
|
||||
|
||||
const types = [];
|
||||
|
||||
for (let i = 0; i < length.toNumber(); i++) {
|
||||
types.push(KeyConstructor, ValueConstructor);
|
||||
types.push(KeyClass, ValClass);
|
||||
}
|
||||
|
||||
const values = decodeU8a(u8a.subarray(offset), types);
|
||||
|
||||
for (let i = 0; i < values.length; i += 2) {
|
||||
output.set(values[i] as K, values[i + 1] as V);
|
||||
}
|
||||
@@ -83,16 +72,14 @@ export default class BTreeMap<K extends Codec = Codec, V extends Codec = Codec>
|
||||
return output;
|
||||
}
|
||||
|
||||
public static decodeBTreeMapFromMap<K extends Codec = Codec, V extends Codec = Codec> (
|
||||
KeyConstructor: Constructor<K>,
|
||||
ValueConstructor: Constructor<V>,
|
||||
value: Map<any, any>): Map<K, V> {
|
||||
private static decodeBTreeMapFromMap<K extends Codec = Codec, V extends Codec = Codec> (KeyClass: Constructor<K>, ValClass: Constructor<V>, value: Map<any, any>): Map<K, V> {
|
||||
const output = new Map<K, V>();
|
||||
|
||||
value.forEach((v: any, k: any) => {
|
||||
let key, val;
|
||||
try {
|
||||
key = (k instanceof KeyConstructor) ? k : new KeyConstructor(k);
|
||||
val = (v instanceof ValueConstructor) ? v : new ValueConstructor(v);
|
||||
key = (k instanceof KeyClass) ? k : new KeyClass(k);
|
||||
val = (v instanceof ValClass) ? v : new ValClass(v);
|
||||
} catch (error) {
|
||||
console.error('Failed to decode BTreeMap key or value:', error.message);
|
||||
throw error;
|
||||
@@ -100,13 +87,14 @@ export default class BTreeMap<K extends Codec = Codec, V extends Codec = Codec>
|
||||
|
||||
output.set(key, val);
|
||||
});
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
public static with<K extends Codec, V extends Codec> (k: Constructor<K>, v: Constructor<V>): Constructor<BTreeMap<K, V>> {
|
||||
public static with<K extends Codec, V extends Codec> (keyType: Constructor<K> | InterfaceTypes, valType: Constructor<V> | InterfaceTypes): Constructor<BTreeMap<K, V>> {
|
||||
return class extends BTreeMap<K, V> {
|
||||
constructor (value?: any) {
|
||||
super(k, v, value);
|
||||
super(keyType, valType, value);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -116,9 +104,11 @@ export default class BTreeMap<K extends Codec = Codec, V extends Codec = Codec>
|
||||
*/
|
||||
public get encodedLength (): number {
|
||||
let len = Compact.encodeU8a(this.size).length;
|
||||
|
||||
this.forEach((v: V, k: K) => {
|
||||
len += v.encodedLength + k.encodedLength;
|
||||
});
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
@@ -155,9 +145,11 @@ export default class BTreeMap<K extends Codec = Codec, V extends Codec = Codec>
|
||||
*/
|
||||
public toJSON (): AnyJson {
|
||||
const json: any = {};
|
||||
|
||||
this.forEach((v: V, k: K) => {
|
||||
json[k.toString()] = v.toJSON();
|
||||
});
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
@@ -165,7 +157,7 @@ export default class BTreeMap<K extends Codec = Codec, V extends Codec = Codec>
|
||||
* @description Returns the base runtime type name for this instance
|
||||
*/
|
||||
public toRawType (): string {
|
||||
return `BTreeMap<${new this._key().toRawType()},${new this._val().toRawType()}>`;
|
||||
return `BTreeMap<${new this._KeyClass().toRawType()},${new this._ValClass().toRawType()}>`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,7 +19,7 @@ export default class Result<O extends Codec, E extends Codec> extends Enum {
|
||||
super({ Ok, Error }, value);
|
||||
}
|
||||
|
||||
public static with<O extends Codec, E extends Codec> (Types: { Ok: Constructor<O> | InterfaceTypes;Error: Constructor<E> | InterfaceTypes }): Constructor<Result<O, E>> {
|
||||
public static with<O extends Codec, E extends Codec> (Types: { Ok: Constructor<O> | InterfaceTypes; Error: Constructor<E> | InterfaceTypes }): Constructor<Result<O, E>> {
|
||||
return class extends Result<O, E> {
|
||||
public constructor (value?: any) {
|
||||
super(Types.Ok, Types.Error, value);
|
||||
|
||||
@@ -58,10 +58,10 @@ function getTypeClassArray (value: TypeDef): (InterfaceTypes)[] {
|
||||
|
||||
const infoMapping: Record<TypeDefInfo, (value: TypeDef) => Constructor> = {
|
||||
[TypeDefInfo.BTreeMap]: (value: TypeDef): Constructor => {
|
||||
const [keyDef, valueDef] = getSubDefArray(value);
|
||||
const [keyType, valueType] = getTypeClassArray(value);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||
return BTreeMap.with(getTypeClass(keyDef), getTypeClass(valueDef));
|
||||
return BTreeMap.with(keyType, valueType);
|
||||
},
|
||||
|
||||
[TypeDefInfo.Compact]: (value: TypeDef): Constructor => Compact.with(getSubType(value)),
|
||||
@@ -82,10 +82,10 @@ const infoMapping: Record<TypeDefInfo, (value: TypeDef) => Constructor> = {
|
||||
getTypeRegistry().getOrThrow(value.type, `Unable to find plain type for ${JSON.stringify(value)}`),
|
||||
|
||||
[TypeDefInfo.Result]: (value: TypeDef): Constructor => {
|
||||
const [okDef, errorDef] = getSubDefArray(value);
|
||||
const [Ok, Error] = getTypeClassArray(value);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||
return Result.with({ Ok: getTypeClass(okDef), Error: getTypeClass(errorDef) });
|
||||
return Result.with({ Ok, Error });
|
||||
},
|
||||
|
||||
[TypeDefInfo.Set]: (value: TypeDef): Constructor => {
|
||||
|
||||
Reference in New Issue
Block a user