Files
api/packages/api-codec/src/base/Array.ts
T
Jaco Greeff d9b05cf9f2 Decode runtime metadata (#162)
* WIP

* Some output, still borken...

* Events decoded correctly

* WIP, metadata decoded

* String cleanups

* Expand with generics

* Add getters

* Start docs...

* Additional docs

* Extra whitespace on Compact

* CodecLength FIXME

* Remove FIXME (impl. takes care)

* Swap in LengthCompact encoding

* Extend docs, play with auto-type for struct

* Trim strings, add Type for type-specific String

* More string-type hackery

* Don't allow Type re-encoding

* Remove struct experiment

* Cleanup Option

* Remove extra type defs from CodecStruct usage

* Expand Storage function with map (and type returns)

* Description around BaseCodec

* Cleanup linting, add Metadata test

* Move to api-codec

* Extract uniq types

* Uniq updates

* Unwrap, ungeneric
2018-09-24 13:51:20 +02:00

118 lines
2.9 KiB
TypeScript

// Copyright 2017-2018 @polkadot/api-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import u8aConcat from '@polkadot/util/u8a/concat';
import CodecBase from './Base';
import Length from './LengthCompact';
// This manages codec arrays. Intrernally it keeps track of the length (as decoded) and allows
// construction with the passed `Type` in the constructor. It aims to be an array-like structure,
// i.e. while it wraps an array, it provides a `length` property to get the actual length, `at(index)`
// to retrieve a specific item. Additionally the helper functions `map`, `filter`, `forEach` and
// `reduce` is exposed on the interface.
export default class CodecArray <
T extends CodecBase
> extends CodecBase<Array<T>> {
private _length: Length;
private _Type: { new(value?: any): T };
constructor (Type: { new(value?: any): T }, value: Array<any> = [] as Array<any>) {
super(
value.map((entry) =>
new Type(entry)
)
);
this._length = new Length(value.length);
this._Type = Type;
}
static with <O extends CodecBase> (Type: { new(value?: any): O }): { new(value?: any): CodecArray<O> } {
return class extends CodecArray<O> {
constructor (value?: Array<any>) {
super(Type, value);
}
};
}
byteLength (): number {
return this.raw.reduce((total, raw) => {
return total + raw.byteLength();
}, this._length.byteLength());
}
get length (): number {
return this.raw.length;
}
at (index: number): T {
return this.raw[index];
}
filter (fn: (entry: T, index?: number) => any): Array<T> {
return this.raw.filter(fn);
}
forEach (fn: (entry: T, index?: number) => any): any {
return this.raw.forEach(fn);
}
fromJSON (input: any): CodecArray<T> {
this.raw = input.map((input: any) =>
new this._Type().fromJSON(input)
);
return this;
}
fromU8a (input: Uint8Array): CodecArray<T> {
this._length.fromU8a(input);
const length = this._length.toNumber();
let offset = this._length.byteLength();
this.raw = [];
for (let index = 0; index < length; index++) {
const raw = new this._Type().fromU8a(input.subarray(offset));
this.raw.push(raw as T);
offset += raw.byteLength();
}
return this;
}
map <O> (fn: (entry: T, index?: number) => O): Array<O> {
return this.raw.map(fn);
}
reduce <O> (fn: (result: O, entry: T, index?: number) => O, initial: O): O {
return this.raw.reduce(fn, initial);
}
toJSON (): any {
return this.raw.map((entry) =>
entry.toJSON()
);
}
toU8a (): Uint8Array {
return u8aConcat(
this._length.toU8a(),
...this.raw.map((entry) =>
entry.toU8a()
)
);
}
toString (): string {
const data = this.raw.map((entry) =>
entry.toString()
).join(', ');
return `[${data}]`;
}
}