-
Notifications
You must be signed in to change notification settings - Fork 6
/
sortValues.ts
70 lines (56 loc) · 2.48 KB
/
sortValues.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
import type { BN } from 'https://deno.land/x/polkadot@0.2.40/util/mod.ts';
import type { Enum } from '../base/Enum.ts';
import type { Codec } from '../types/index.ts';
import { bnToBn, isBigInt, isBn, isCodec, isNumber, stringify } from 'https://deno.land/x/polkadot@0.2.40/util/mod.ts';
type SortArg = Codec | Codec[] | number[] | BN | bigint | number | Uint8Array;
/** @internal **/
function isArrayLike (arg: SortArg): arg is Uint8Array | Codec[] | number[] {
return arg instanceof Uint8Array || Array.isArray(arg);
}
/** @internal **/
function isEnum (arg: SortArg): arg is Enum {
return isCodec<Codec>(arg) && isNumber((arg as Enum).index) && isCodec((arg as Enum).value);
}
/** @internal */
function isNumberLike (arg: SortArg): arg is BN | bigint | number {
return isNumber(arg) || isBn(arg) || isBigInt(arg);
}
/** @internal */
function sortArray (a: Uint8Array | Codec[] | number[], b: Uint8Array | Codec[] | number[]): number {
// Vec, Tuple, Bytes etc.
let sortRes = 0;
const minLen = Math.min(a.length, b.length);
for (let i = 0; i < minLen; ++i) {
sortRes = sortAsc(a[i], b[i]);
if (sortRes !== 0) {
return sortRes;
}
}
return a.length - b.length;
}
/**
* Sort keys/values of BTreeSet/BTreeMap in ascending order for encoding compatibility with Rust's BTreeSet/BTreeMap
* (https://doc.rust-lang.org/stable/std/collections/struct.BTreeSet.html)
* (https://doc.rust-lang.org/stable/std/collections/struct.BTreeMap.html)
*/
export function sortAsc<V extends SortArg = Codec> (a: V, b: V): number {
if (isNumberLike(a) && isNumberLike(b)) {
return bnToBn(a).cmp(bnToBn(b));
} else if (a instanceof Map && b instanceof Map) {
return sortAsc(Array.from(a.values()), Array.from(b.values()));
} else if (isEnum(a) && isEnum(b)) {
return sortAsc(a.index, b.index) || sortAsc(a.value, b.value);
} else if (isArrayLike(a) && isArrayLike(b)) {
return sortArray(a, b);
} else if (isCodec<Codec>(a) && isCodec<Codec>(b)) {
// Text, Bool etc.
return sortAsc(a.toU8a(true), b.toU8a(true));
}
throw new Error(`Attempting to sort unrecognized values: ${stringify(a)} (typeof ${typeof a}) <-> ${stringify(b)} (typeof ${typeof b})`);
}
export function sortSet<V extends Codec = Codec> (set: Set<V>): Set<V> {
return new Set(Array.from(set).sort(sortAsc));
}
export function sortMap<K extends Codec = Codec, V extends Codec = Codec> (map: Map<K, V>): Map<K, V> {
return new Map(Array.from(map.entries()).sort(([keyA], [keyB]) => sortAsc(keyA, keyB)));
}