This repository has been archived by the owner on Sep 14, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 10
/
Id.ts
71 lines (63 loc) · 1.96 KB
/
Id.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
import { encode as hexEncode } from "../crypto/hex.ts"
import * as $ from "../deps/scale.ts"
import { Blake2b } from "../deps/wat_the_crypto.ts"
import { getOrInit, WeakRefMap } from "../util/mod.ts"
export class Id {
private constructor(public hex: string, public u8a: Uint8Array) {}
private static u8aMap = new WeakRefMap<string, Id>()
private static fromU8a(u8a: Uint8Array) {
const hex = hexEncode(u8a)
return getOrInit(this.u8aMap, hex, () => new Id(hex, u8a))
}
static random() {
return this.fromU8a(crypto.getRandomValues(new Uint8Array(64)))
}
private static locMap = new Map<TemplateStringsArray, Id>()
static loc(tag: TemplateStringsArray) {
return getOrInit(this.locMap, tag, () => this.random())
}
private static _hash(u8a: Uint8Array) {
const hasher = new Blake2b()
hasher.update(u8a)
return this.fromU8a(hasher.digest())
}
private static valueMap = new WeakRefMap<unknown, Id>()
static value(value: unknown): Id {
if (value instanceof Id) {
return value
} else if (
typeof value === "object"
&& value
&& "id" in value
&& value["id" as never] as any instanceof Id
) {
return value["id" as never]
}
return getOrInit(this.valueMap, value, () => {
if (typeof value === "number") {
return this._hash(new Uint8Array(new Float64Array([value])))
}
if (typeof value === "string") {
return this._hash(new TextEncoder().encode(value))
}
if (typeof value === "bigint") {
return this._hash($.i256.encode(value))
}
if (typeof value === "boolean") {
return this._hash(new Uint8Array([+value]))
}
return this.random()
})
}
static hash(base: Id, ...rest: unknown[]) {
const hasher = new Blake2b()
hasher.update(base.u8a)
for (const value of rest) {
hasher.update(this.value(value).u8a)
}
return this.fromU8a(hasher.digest())
}
toString() {
return this.hex
}
}