From 686ea05167a65cd8349ded3b16ba91859bb0bd89 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Tue, 30 Oct 2018 17:23:20 +0100 Subject: [PATCH] Add Set basetype (#365) * Add Set basetype * Test and log invalid init values * Set.value -> Set.values * isEmpty used this.values in Set * Cleanup erronenous export * Export Option for codec --- packages/types/src/codec/EnumType.ts | 5 ++ packages/types/src/codec/Set.spec.ts | 36 +++++++++++ packages/types/src/codec/Set.ts | 92 ++++++++++++++++++++++++++++ packages/types/src/codec/index.ts | 5 ++ packages/types/src/index.ts | 3 +- 5 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 packages/types/src/codec/Set.spec.ts create mode 100644 packages/types/src/codec/Set.ts diff --git a/packages/types/src/codec/EnumType.ts b/packages/types/src/codec/EnumType.ts index b11764c387..7a36265a22 100644 --- a/packages/types/src/codec/EnumType.ts +++ b/packages/types/src/codec/EnumType.ts @@ -5,6 +5,7 @@ import { isNumber, isObject, isU8a, isUndefined, u8aConcat } from '@polkadot/util'; import Base from './Base'; +import Null from '../Null'; import { Constructor } from '../types'; type TypesArray = Array>; @@ -79,6 +80,10 @@ export default class EnumType extends Base> { return { index: 0, value: new (Object.values(def)[0])() }; } + get isNull (): boolean { + return this.raw instanceof Null; + } + get type (): string { return this._Types[this._index].name; } diff --git a/packages/types/src/codec/Set.spec.ts b/packages/types/src/codec/Set.spec.ts new file mode 100644 index 0000000000..79cece484b --- /dev/null +++ b/packages/types/src/codec/Set.spec.ts @@ -0,0 +1,36 @@ +// Copyright 2017-2018 @polkadot/types authors & contributors +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +import Set from './Set'; + +describe('Set', () => { + it('constructs via an Array', () => { + const set = new Set({ + none: 0b00000000, + full: 0b00000001, + light: 0b00000010, + authority: 0b00000100 + }, ['full', 'authority', 'invalid']); + + expect(set.isEmpty).toEqual(false); + expect(set.toString()).toEqual( + '[full, authority]' + ); + }); + + it('constructs via Uint8Array', () => { + const set = new Set({ + header: 0b00000001, + body: 0b00000010, + receipt: 0b00000100, + messageQueue: 0b00001000, + justification: 0b00010000 + }, new Uint8Array([0b00000001 | 0b00000010 | 0b00010000 | 0b10000000])); + + expect(set.encodedLength).toEqual(1); + expect(set.toJSON()).toEqual([ + 'header', 'body', 'justification' + ]); + }); +}); diff --git a/packages/types/src/codec/Set.ts b/packages/types/src/codec/Set.ts new file mode 100644 index 0000000000..bc56361bca --- /dev/null +++ b/packages/types/src/codec/Set.ts @@ -0,0 +1,92 @@ +// Copyright 2017-2018 @polkadot/types authors & contributors +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +import { isU8a, isUndefined } from '@polkadot/util'; + +import Base from './Base'; + +type SetValues = { + [index: string]: number +}; + +// An Set is an array of string values, represented an an encoded type by +// a bitwise representation of the values. +// +// FIXME This is a prime candidate to potentially extend Set +export default class Set extends Base> { + private _setValues: SetValues; + + constructor (setValues: SetValues, value?: Array | Uint8Array | number) { + super( + Set.decodeSet(setValues, value) + ); + + this._setValues = setValues; + } + + static decodeSet (setValues: SetValues, value: Array | Uint8Array | number = 0): Array { + if (isU8a(value)) { + return Set.decodeSet(setValues, value[0]); + } else if (Array.isArray(value)) { + return value.reduce((result, value) => { + if (isUndefined(setValues[value])) { + console.error(`Ignoring invalid '${value}' passed to Set`); + } else { + result.push(value); + } + + return result; + }, [] as Array); + } + + const result = Object.keys(setValues).reduce((result, key) => { + if ((value & setValues[key]) === setValues[key]) { + result.push(key); + } + + return result; + }, [] as Array); + const computed = Set.encodeSet(setValues, result); + + if (value !== computed) { + console.error(`Mismatch decoding '${value}', computed as '${computed}' with ${result}`); + } + + return result; + } + + static encodeSet (setValues: SetValues, value: Array): number { + return value.reduce((result, value) => { + return result | (setValues[value] || 0); + }, 0); + } + + get encodedLength (): number { + return 1; + } + + get isEmpty (): boolean { + return this.values.length === 0; + } + + get values (): Array { + return this.raw; + } + + get valueEncoded (): number { + return Set.encodeSet(this._setValues, this.raw); + } + + toJSON (): any { + return this.values; + } + + toU8a (isBare?: boolean): Uint8Array { + return new Uint8Array(this.valueEncoded); + } + + toString (): string { + return `[${this.values.map((value) => value).join(', ')}]`; + } +} diff --git a/packages/types/src/codec/index.ts b/packages/types/src/codec/index.ts index 8cab36169d..b8a03c6949 100644 --- a/packages/types/src/codec/index.ts +++ b/packages/types/src/codec/index.ts @@ -9,6 +9,11 @@ // These are the base codec types, generally used for construction export { default as Base } from './Base'; +export { default as Compact } from './Compact'; +export { default as Enum } from './Enum'; +export { default as EnumType } from './EnumType'; +export { default as Option } from './Option'; +export { default as Set } from './Set'; export { default as Struct } from './Struct'; export { default as Tuple } from './Tuple'; export { default as Vector } from './Vector'; diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 84aca8b14d..82d8b3e525 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -43,8 +43,7 @@ export { default as Method } from './Method'; export { default as MisbehaviorReport } from './MisbehaviorReport'; export { default as Moment } from './Moment'; export { default as NewAccountOutcome } from './NewAccountOutcome'; -// NOTE only used internally atm -// export { default as Null } from './Null'; +export { default as Null } from './Null'; // NOTE Nonce is renamed to Index export { default as Index } from './Nonce'; export { default as Origin } from './Origin';