codec/Set extends JS Set (#917)

This commit is contained in:
Jaco Greeff
2019-06-12 16:45:45 +12:00
committed by Ian He
parent 0e5906473b
commit 194077033a
4 changed files with 63 additions and 30 deletions
+8
View File
@@ -1,3 +1,11 @@
# 0.79.1
- Support latest EventRecord metadata (substrate master)
- Introduce RuntimeVeriosion type overrides in api/nodeCompat.ts
- Add `api.queryMulti` and `api.query.<module>.<method>.multi`
- Convert `api.derive.*` to use multi queries
- `types/codec/Set` now extends the base JS `Set` (breaking: `set.values` -> `set.strings`)
# 0.78.1
- Fix linked-maps (not working since 0.77.1)
+13 -1
View File
@@ -20,7 +20,7 @@ const SET_ROLES = {
describe('Set', () => {
it('constructs via an Array<string>', () => {
const set = new Set(SET_ROLES, ['full', 'authority', 'invalid']);
const set = new Set(SET_ROLES, ['full', 'authority']);
expect(set.isEmpty).toEqual(false);
expect(set.toString()).toEqual(
@@ -28,6 +28,18 @@ describe('Set', () => {
);
});
it('throws with invalid values', () => {
expect(
() => new Set(SET_ROLES, ['full', 'authority', 'invalid'])
).toThrow(/Invalid key 'invalid'/);
});
it('throws with add on invalid', () => {
expect(
() => (new Set(SET_ROLES, [])).add('invalid')
).toThrow(/Invalid key 'invalid'/);
});
it('constructs via Uint8Array', () => {
const set = new Set(SET_FIELDS, new Uint8Array([0b00000001 | 0b00000010 | 0b00010000 | 0b10000000]));
+38 -25
View File
@@ -2,9 +2,8 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { isU8a, isNumber, isUndefined, u8aToHex } from '@plugnet/util';
import { assert, isU8a, isNumber, isUndefined, u8aToHex } from '@plugnet/util';
import Base from './Base';
import { Codec } from '../types';
import { compareArray } from './utils';
@@ -19,27 +18,29 @@ type SetValues = {
* a bitwise representation of the values.
*/
// FIXME This is a prime candidate to extend the JavaScript built-in Set
export default class Set extends Base<Array<string>> implements Codec {
export default class CodecSet extends Set<string> implements Codec {
private _setValues: SetValues;
constructor (setValues: SetValues, value?: Array<string> | Uint8Array | number) {
constructor (setValues: SetValues, value?: Array<string> | Set<string> | Uint8Array | number) {
super(
Set.decodeSet(setValues, value)
CodecSet.decodeSet(setValues, value)
);
this._setValues = setValues;
}
static decodeSet (setValues: SetValues, value: Array<string> | Uint8Array | number = 0): Array<string> {
static decodeSet (setValues: SetValues, value: Array<string> | Set<string> | Uint8Array | number = 0): Array<string> {
if (isU8a(value)) {
return Set.decodeSet(setValues, value[0]);
return value.length === 0
? []
: CodecSet.decodeSet(setValues, value[0]);
} else if (value instanceof Set) {
return CodecSet.decodeSet(setValues, [...value.values()]);
} 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 value.reduce((result, key) => {
assert(!isUndefined(setValues[key]), `Set: Invalid key '${key}' passed to Set, allowed ${Object.keys(setValues).join(', ')}`);
result.push(key);
return result;
}, [] as Array<string>);
@@ -52,11 +53,10 @@ export default class Set extends Base<Array<string>> implements Codec {
return result;
}, [] as Array<string>);
const computed = Set.encodeSet(setValues, result);
if (value !== computed) {
console.error(`Mismatch decoding '${value}', computed as '${computed}' with ${result}`);
}
const computed = CodecSet.encodeSet(setValues, result);
assert(value !== computed, `Set: Mismatch decoding '${value}', computed as '${computed}' with ${result}`);
return result;
}
@@ -78,21 +78,34 @@ export default class Set extends Base<Array<string>> implements Codec {
* @description true is the Set contains no values
*/
get isEmpty (): boolean {
return this.values.length === 0;
return this.size === 0;
}
/**
* @description The actual set values as a Array<string>
*/
get values (): Array<string> {
return this.raw;
get strings (): Array<string> {
return [...super.values()];
}
/**
* @description The encoded value for the set members
*/
get valueEncoded (): number {
return Set.encodeSet(this._setValues, this.raw);
return CodecSet.encodeSet(this._setValues, this.strings);
}
/**
* @description adds a value to the Set (extended to allow for validity checking)
*/
add (key: string): this {
// we have the isUndefined(this._setValues) in here as well, add is used internally
// in the Set constructor (so it is undefined at this point, and should allow)
assert(isUndefined(this._setValues) || !isUndefined(this._setValues[key]), `Set: Invalid key '${key}' on add`);
super.add(key);
return this;
}
/**
@@ -101,9 +114,9 @@ export default class Set extends Base<Array<string>> implements Codec {
eq (other?: any): boolean {
if (Array.isArray(other)) {
// we don't actually care about the order, sort the values
return compareArray(this.values.sort(), other.sort());
return compareArray(this.strings.sort(), other.sort());
} else if (other instanceof Set) {
return this.eq(other.values);
return this.eq([...other.values()]);
} else if (isNumber(other)) {
return this.valueEncoded === other;
}
@@ -122,14 +135,14 @@ export default class Set extends Base<Array<string>> implements Codec {
* @description Converts the Object to JSON, typically used for RPC transfers
*/
toJSON (): any {
return this.values;
return this.strings;
}
/**
* @description Returns the string representation of the value
*/
toString (): string {
return `[${this.values.join(', ')}]`;
return `[${this.strings.join(', ')}]`;
}
/**
+4 -4
View File
@@ -23,27 +23,27 @@ export default class WithdrawReasons extends Set {
* @description In order to reserve some funds for a later return or repatriation
*/
get isReserve (): boolean {
return this.values.includes('Reserve');
return this.strings.includes('Reserve');
}
/**
* @description In order to pay for (system) transaction costs
*/
get isTransactionPayment (): boolean {
return this.values.includes('TransactionPayment');
return this.strings.includes('TransactionPayment');
}
/**
* @description In order to transfer ownership
*/
get isTransfer (): boolean {
return this.values.includes('Transfer');
return this.strings.includes('Transfer');
}
/**
* @description /// In order to pay some other (higher-level) fees.
*/
get isFee (): boolean {
return this.values.includes('Fee');
return this.strings.includes('Fee');
}
}