From c7cd9cdfbfe0233e5a33026e66d9013160b5fba7 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Tue, 2 Oct 2018 13:09:25 +0200 Subject: [PATCH] Create TypeValue structure (#184) * Create TypeValue structure * Cleanup create * More nesting in types * Trim types (just in case) --- packages/types/src/codec/createType.spec.js | 67 +++++++++++---- packages/types/src/codec/createType.ts | 93 +++++++++++++-------- 2 files changed, 110 insertions(+), 50 deletions(-) diff --git a/packages/types/src/codec/createType.spec.js b/packages/types/src/codec/createType.spec.js index 451674e23b..336c0a7d43 100644 --- a/packages/types/src/codec/createType.spec.js +++ b/packages/types/src/codec/createType.spec.js @@ -2,7 +2,7 @@ // This software may be modified and distributed under the terms // of the ISC license. See the LICENSE file for details. -import { typeSplit, getType, getTupleType, getVectorType } from './createType'; +import { TypeValueInfo, typeSplit, getType, getTypeValue } from './createType'; describe('typeSplit', () => { it('splits simple types into an array', () => { @@ -48,31 +48,68 @@ describe('typeSplit', () => { }); }); -describe('getTupleType', () => { +describe('getTypeValue', () => { it('does not allow invalid tuples, end )', () => { expect( - () => getTupleType('(u64, u32') + () => getTypeValue('(u64, u32') ).toThrow(/tuple wrapped/); }); - it('does not allow invalid tuples, start (', () => { - expect( - () => getTupleType('u64, u32)') - ).toThrow(/tuple wrapped/); - }); -}); - -describe('getVectorType', () => { it('does not allow invalid vectors, end >', () => { expect( - () => getVectorType('Vec getTypeValue('Vec { + it('returns a type structure', () => { expect( - () => getVectorType('u64>') - ).toThrow(/Vec wrapped/); + getTypeValue('(u32, Vec, (Text, Vec<(Bool, u128)>))') + ).toEqual({ + info: TypeValueInfo.Tuple, + type: '(u32, Vec, (Text, Vec<(Bool, u128)>))', + sub: [ + { + info: TypeValueInfo.Plain, + type: 'u32' + }, + { + info: TypeValueInfo.Vector, + type: 'Vec', + sub: { + info: TypeValueInfo.Plain, + type: 'u64' + } + }, + { + info: TypeValueInfo.Tuple, + type: '(Text, Vec<(Bool, u128)>)', + sub: [ + { + info: TypeValueInfo.Plain, + type: 'Text' + }, + { + info: TypeValueInfo.Vector, + type: 'Vec<(Bool, u128)>', + sub: { + info: TypeValueInfo.Tuple, + type: '(Bool, u128)', + sub: [ + { + info: TypeValueInfo.Plain, + type: 'Bool' + }, + { + info: TypeValueInfo.Plain, + type: 'u128' + } + ] + } + } + ] + } + ] + }); }); }); diff --git a/packages/types/src/codec/createType.ts b/packages/types/src/codec/createType.ts index b943ca6614..222b22570b 100644 --- a/packages/types/src/codec/createType.ts +++ b/packages/types/src/codec/createType.ts @@ -11,6 +11,18 @@ import Vector from './Vector'; type Constructor = { new (value?: any): Base }; +export enum TypeValueInfo { + Plain, + Tuple, + Vector +} + +export type TypeValue = { + info: TypeValueInfo, + type: string, + sub?: TypeValue | Array +}; + // safely split a string on ', ' while taking care of any nested occurences export function typeSplit (type: string): Array { let tDepth = 0; @@ -62,54 +74,63 @@ export function typeSplit (type: string): Array { return result; } -// Handle Vector types, i.e Vec or Vec<(AccountId, Balance)> -export function getVectorType (type: string): Constructor { - // l.debug(() => ['getVectorType', { type }]); +export function getTypeValue (_type: string): TypeValue { + const type = _type.trim(); + const value: TypeValue = { + info: TypeValueInfo.Plain, + type + }; - assert(type.substr(0, 4) === 'Vec<' && type[type.length - 1] === '>', `Expected Vec wrapped with <>`); + if (type[0] === '(') { + assert(type[type.length - 1] === ')', `Expected tuple wrapped with ()`); - // strip wrapping Vec<> - const subType = type.substr(4, type.length - 5); + // strip wrapping ()'s + const innerTypes = typeSplit(type.substr(1, type.length - 2)); - return Vector.with( - getType(subType) - ); -} + value.info = TypeValueInfo.Tuple; + value.sub = innerTypes.map((inner) => + getTypeValue(inner) + ); + } else if (type.substr(0, 4) === 'Vec<') { + assert(type[type.length - 1] === '>', `Expected Vec wrapped with <>`); -// Handle tuple types, (u32, String, AccountId). It could be nested and wrapped in other -// types, i.e. (u32, Vec<(AccountId, Balance)>) -export function getTupleType (type: string): Constructor { - // l.debug(() => ['getTupleType', { type }]); + // strip wrapping Vec<> + const subType = type.substr(4, type.length - 5); - assert(type[0] === '(' && type[type.length - 1] === ')', `Expected tuple wrapped with ()`); + value.info = TypeValueInfo.Vector; + value.sub = getTypeValue(subType); + } - // strip wrapping ()'s - const innerTypes = typeSplit(type.substr(1, type.length - 2)); - - return Tuple.with( - innerTypes.reduce((result, type, index) => { - result[`entry${index}`] = getType(type); - - return result; - }, {} as { [index: string]: Constructor }) - ); + return value; } // Returns the type Class for construction -export function getType (_type: string): Constructor { - const type = _type.trim(); +export function getType (value: TypeValue): Constructor { + if (value.info === TypeValueInfo.Tuple) { + if (!Array.isArray(value.sub)) { + throw new Error(`Expected nested subtypes for Tuple`); + } - // l.debug(() => ['getType', { type }]); + return Tuple.with( + value.sub.reduce((result, type, index) => { + result[`entry${index}`] = getType(type); - if (type[0] === '(') { - return getTupleType(type); - } else if (type.substr(0, 4) === 'Vec<') { - return getVectorType(type); + return result; + }, {} as { [index: string]: Constructor }) + ); + } else if (value.info === TypeValueInfo.Vector) { + if (!value.sub || Array.isArray(value.sub)) { + throw new Error(`Expected subtype for Vector`); + } + + return Vector.with( + getType(value.sub) + ); } - const Type = (Types as any)[type]; + const Type = (Types as any)[value.type]; - assert(Type, `Unable to determine type from '${type}'`); + assert(Type, `Unable to determine type from '${value.type}'`); return Type; } @@ -117,7 +138,9 @@ export function getType (_type: string): Constructor { export default function createType (type: string, value?: any): Base { // l.debug(() => ['createType', { type, value }]); - const Type = getType(type); + const Type = getType( + getTypeValue(type) + ); return new Type(value); }