-
Notifications
You must be signed in to change notification settings - Fork 6
/
Array.ts
211 lines (172 loc) · 5.4 KB
/
Array.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
import type { HexString } from 'https://deno.land/x/polkadot@0.2.40/util/types.ts';
import type { AnyJson, Codec, Inspect, IU8a, IVec, Registry } from '../types/index.ts';
import { compactToU8a, u8aConcatStrict, u8aToHex } from 'https://deno.land/x/polkadot@0.2.40/util/mod.ts';
import { compareArray } from '../utils/compareArray.ts';
/**
* @name AbstractArray
* @description
* This manages codec arrays. It is an extension to Array, providing
* specific encoding/decoding on top of the base type.
* @noInheritDoc
*/
export abstract class AbstractArray<T extends Codec> extends Array<T> implements IVec<T> {
readonly registry: Registry;
public createdAtHash?: IU8a;
public initialU8aLength?: number;
public isStorageFallback?: boolean;
/**
* @description This ensures that operators such as clice, filter, map, etc. return
* new Array instances (without this we need to apply overrides)
*/
static get [Symbol.species] (): typeof Array {
return Array;
}
protected constructor (registry: Registry, length: number) {
super(length);
this.registry = registry;
}
/**
* @description The length of the value when encoded as a Uint8Array
*/
public get encodedLength (): number {
// We need to loop through all entries since they may have a variable length themselves,
// e.g. when a Vec or Compact is contained withing, it has a variable length based on data
const count = this.length;
let total = compactToU8a(count).length;
for (let i = 0; i < count; i++) {
total += this[i].encodedLength;
}
return total;
}
/**
* @description returns a hash of the contents
*/
public get hash (): IU8a {
return this.registry.hash(this.toU8a());
}
/**
* @description Checks if the value is an empty value
*/
public get isEmpty (): boolean {
return this.length === 0;
}
/**
* @description The length of the value
*/
public override get length (): number {
// only included here since we ignore inherited docs
return super.length;
}
/**
* @description Compares the value of the input to see if there is a match
*/
public eq (other?: unknown): boolean {
return compareArray(this, other);
}
/**
* @description Returns a breakdown of the hex encoding for this Codec
*/
public inspect (): Inspect {
return {
inner: this.inspectInner(),
outer: [compactToU8a(this.length)]
};
}
/**
* @internal
* @description Internal per-item inspection of internal values
*/
public inspectInner (): Inspect[] {
const count = this.length;
const inner = new Array<Inspect>(count);
for (let i = 0; i < count; i++) {
inner[i] = this[i].inspect();
}
return inner;
}
/**
* @description Converts the Object to an standard JavaScript Array
*/
public toArray (): T[] {
return Array.from(this);
}
/**
* @description Returns a hex string representation of the value
*/
public toHex (): HexString {
return u8aToHex(this.toU8a());
}
/**
* @description Converts the Object to to a human-friendly JSON, with additional fields, expansion and formatting of information
*/
public toHuman (isExtended?: boolean): AnyJson {
const count = this.length;
const result = new Array<AnyJson>(count);
for (let i = 0; i < count; i++) {
result[i] = this[i] && this[i].toHuman(isExtended);
}
return result;
}
/**
* @description Converts the Object to JSON, typically used for RPC transfers
*/
public toJSON (): AnyJson {
const count = this.length;
const result = new Array<AnyJson>(count);
for (let i = 0; i < count; i++) {
// We actually log inside the U8a decoding and use JSON.stringify(...), which
// means that the Vec may be partially populated (same applies to toHuman, same check)
result[i] = this[i] && this[i].toJSON();
}
return result;
}
/**
* @description Converts the value in a best-fit primitive form
*/
public toPrimitive (): AnyJson {
const count = this.length;
const result = new Array<AnyJson>(count);
for (let i = 0; i < count; i++) {
result[i] = this[i] && this[i].toPrimitive();
}
return result;
}
/**
* @description Returns the base runtime type name for this instance
*/
abstract toRawType (): string;
/**
* @description Returns the string representation of the value
*/
public override toString (): string {
const count = this.length;
const result = new Array<string>(count);
for (let i = 0; i < count; i++) {
result[i] = this[i].toString();
}
return `[${result.join(', ')}]`;
}
/**
* @description Encodes the value as a Uint8Array as per the SCALE specifications
* @param isBare true when the value has none of the type-specific prefixes (internal)
*/
public toU8a (isBare?: boolean): Uint8Array {
const encoded = this.toU8aInner();
return isBare
? u8aConcatStrict(encoded)
: u8aConcatStrict([compactToU8a(this.length), ...encoded]);
}
/**
* @internal
* @description Internal per-item SCALE encoding of contained values
* @param isBare true when the value has none of the type-specific prefixes (internal)
*/
public toU8aInner (isBare?: boolean): Uint8Array[] {
const count = this.length;
const encoded = new Array<Uint8Array>(count);
for (let i = 0; i < count; i++) {
encoded[i] = this[i].toU8a(isBare);
}
return encoded;
}
}