createType allows for [u8; <length>] definitions (#976)

This commit is contained in:
Jaco Greeff
2019-06-07 12:13:53 +02:00
committed by GitHub
parent e295c4d5bf
commit 91ae98c9e6
4 changed files with 64 additions and 21 deletions
@@ -30,4 +30,10 @@ describe('U8aFixed', () => {
new U8aFixed().toHex()
).toEqual('0x0000000000000000000000000000000000000000000000000000000000000000');
});
it('allows construction via with', () => {
expect(
new (U8aFixed.with(64))().bitLength()
).toEqual(64);
});
});
+10 -2
View File
@@ -4,11 +4,11 @@
import { isString, isU8a, u8aToU8a } from '@polkadot/util';
import { AnyU8a } from '../types';
import { AnyU8a, Constructor } from '../types';
import U8a from './U8a';
type BitLength = 8 | 16 | 32 | 64 | 128 | 160 | 256 | 512;
export type BitLength = 8 | 16 | 32 | 64 | 128 | 160 | 256 | 512 | 1024 | 2048;
/**
* @name U8aFixed
@@ -46,6 +46,14 @@ export default class U8aFixed extends U8a {
return value;
}
static with (bitLength: BitLength): Constructor<U8aFixed> {
return class extends U8aFixed {
constructor (value?: any) {
super(value, bitLength);
}
};
}
/**
* @description Returns the number of bits in the value
*/
@@ -233,8 +233,15 @@ describe('createType', () => {
).toEqual({ B: 0 });
});
it('allows creation of a [u8; 8]', () => {
expect(
createType('[u8; 8]', [0x12, 0x00, 0x23, 0x00, 0x45, 0x00, 0x67, 0x00]).toHex()
).toEqual('0x1200230045006700');
});
it('throw error when create base is a StorageData with null value and isPedantic is true' , () => {
const base = createType('StorageData', null);
expect(
() => createType('DoubleMap<Vec<(BlockNumber,EventIndex)>>', base, true)
).toThrow(/Encoding for input doesn't match output, created 0x00 from 0x/);
@@ -242,6 +249,7 @@ describe('createType', () => {
it('throw error when create base is a StorageData with null value and isPedantic is true' , () => {
const base = createType('StorageData', null);
expect(
() => createType('Vec<(BlockNumber,EventIndex)>', base, true)
).toThrow(/Encoding for input doesn't match output, created 0x00 from 0x/);
+40 -19
View File
@@ -13,26 +13,34 @@ import Linkage from './Linkage';
import Option from './Option';
import Struct from './Struct';
import Tuple from './Tuple';
import U8aFixed, { BitLength as U8aFixedBitLength } from './U8aFixed';
import UInt from './UInt';
import Vector from './Vector';
import getRegistry from './typeRegistry';
export enum TypeDefInfo {
Compact,
DoubleMap,
Enum,
Linkage,
Option,
Plain,
Struct,
Tuple,
Vector,
Linkage,
DoubleMap,
VectorFixed,
// anything not full supported (keep this as the last entry)
Null
}
export type TypeDefExtVecFixed = {
length: number,
type: string
};
export type TypeDef = {
info: TypeDefInfo,
ext?: TypeDefExtVecFixed, // add additional here as required
name?: string,
type: string,
sub?: TypeDef | Array<TypeDef>
@@ -40,9 +48,10 @@ export type TypeDef = {
// safely split a string on ', ' while taking care of any nested occurences
export function typeSplit (type: string): Array<string> {
let sDepth = 0;
let tDepth = 0;
let vDepth = 0;
let cDepth = 0; // compact/doublemap/linkedmap/option/vector depth
let fDepth = 0; // vector (fixed) depth
let sDepth = 0; // struct depth
let tDepth = 0; // tuple depth
let start = 0;
const result = [];
@@ -50,36 +59,34 @@ export function typeSplit (type: string): Array<string> {
switch (type[index]) {
case ',':
// we are not nested, add the type
if (sDepth === 0 && tDepth === 0 && vDepth === 0) {
if (cDepth === 0 && fDepth === 0 && sDepth === 0 && tDepth === 0) {
result.push(type.substr(start, index - start).trim());
start = index + 1;
}
break;
// inc struct depth, start found
case '{': sDepth++; break;
// adjust compact/vec (and friends) depth
case '<': cDepth++; break;
case '>': cDepth--; break;
// dec struct depth, end found
// adjust fixed vec depths
case '[': fDepth++; break;
case ']': fDepth--; break;
// adjust struct depth
case '{': sDepth++; break;
case '}': sDepth--; break;
// inc tuple depth, start found
// adjusttuple depth
case '(': tDepth++; break;
// dec tuple depth, end found
case ')': tDepth--; break;
// inc compact/vec depth, start found
case '<': vDepth++; break;
// dec compact/vec depth, end found
case '>': vDepth--; break;
// normal character
default: break;
}
}
assert(!sDepth && !tDepth && !vDepth, `Invalid defintion (missing terminators) found in ${type}`);
assert(!cDepth && !fDepth && !sDepth && !tDepth, `Invalid defintion (missing terminators) found in ${type}`);
// the final leg of the journey
result.push(type.substr(start, type.length - start).trim());
@@ -111,6 +118,16 @@ export function getTypeDef (_type: Text | string, name?: string): TypeDef {
if (startingWith(type, '(', ')')) {
value.info = TypeDefInfo.Tuple;
value.sub = typeSplit(subType).map((inner) => getTypeDef(inner));
} else if (startingWith(type, '[', ']')) {
// this handles e.g. [u8;32]
const [vecType, _vecLen] = type.substr(1, type.length - 2).split(';');
const vecLen = parseInt(_vecLen.trim(), 10);
// as a first round, only u8 via u8aFixed, we can add more support
assert(vecLen <= 256 && ['u8'].includes(vecType), `Only support for [u8; <length>], where length <= 256`);
value.info = TypeDefInfo.VectorFixed;
value.ext = { length: vecLen, type: 'u8a' } as TypeDefExtVecFixed;
} else if (startingWith(type, '{', '}')) {
const parsed = JSON.parse(type);
const keys = Object.keys(parsed);
@@ -208,6 +225,10 @@ export function getTypeClass (value: TypeDef): Constructor {
return Vector.with(
getTypeClass(value.sub as TypeDef)
);
case TypeDefInfo.VectorFixed:
assert(value.ext, 'Expected length & type information for fixed vector');
return U8aFixed.with(((value.ext as TypeDefExtVecFixed).length * 8) as U8aFixedBitLength);
case TypeDefInfo.Linkage:
assert(value.sub && !Array.isArray(value.sub), 'Expected subtype for Linkage');