-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmod.ts
130 lines (130 loc) · 3.12 KB
/
mod.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
export type Adler32AcceptDataType = string | BigUint64Array | Uint8Array | Uint16Array | Uint32Array;
/**
* Get the checksum of the data with algorithm Adler32.
*/
export class Adler32 {
get [Symbol.toStringTag](): string {
return "Adler32";
}
#freezed: boolean = false;
#hash: bigint | null = null;
#a: bigint = 1n;
#b: bigint = 0n;
/**
* Initialize.
* @param {Adler32AcceptDataType} [data] Data. Can append later via the method {@linkcode Adler32.update}.
*/
constructor(data?: Adler32AcceptDataType) {
if (typeof data !== "undefined") {
this.update(data);
}
}
/**
* Whether the instance is freezed.
* @returns {boolean}
*/
get freezed(): boolean {
return this.#freezed;
}
/**
* Freeze the instance to prevent any update.
* @returns {this}
*/
freeze(): this {
this.#freezed = true;
return this;
}
/**
* Get the checksum of the data, in original format.
* @returns {bigint}
*/
hash(): bigint {
if (this.#hash === null) {
this.#hash = this.#b * 65536n + this.#a;
}
return this.#hash;
}
/**
* Get the checksum of the data, in Base16.
* @returns {string}
*/
hashBase16(): string {
return this.hashBigInt().toString(16).toUpperCase();
}
/**
* Get the checksum of the data, in Base32Hex ({@link https://datatracker.ietf.org/doc/html/rfc4648#section-7 RFC 4648 §7}).
* @returns {string}
*/
hashBase32Hex(): string {
return this.hashBigInt().toString(32).toUpperCase();
}
/**
* Get the checksum of the data, in Base36.
* @returns {string}
*/
hashBase36(): string {
return this.hashBigInt().toString(36).toUpperCase();
}
/**
* Get the checksum of the data, in big integer.
* @returns {bigint}
*/
hashBigInt(): bigint {
return this.hash();
}
/**
* Get the checksum of the data, in big integer.
* @returns {bigint}
*/
hashBigInteger: () => bigint = this.hashBigInt;
/**
* Get the checksum of the data, in hex/hexadecimal without padding.
* @returns {string}
*/
hashHex(): string {
return this.hashBase16();
}
/**
* Get the checksum of the data, in hex/hexadecimal with padding.
* @returns {string}
*/
hashHexPadding(): string {
return this.hashHex().padStart(8, "0");
}
/**
* Get the checksum of the data, in number.
* @returns {number}
*/
hashNumber(): number {
return Number(this.hash());
}
/**
* Append data.
* @param {Adler32AcceptDataType} data Data.
* @returns {this}
*/
update(data: Adler32AcceptDataType): this {
if (this.#freezed) {
throw new Error(`Instance is freezed!`);
}
this.#hash = null;
for (const byte of ((typeof data === "string") ? new TextEncoder().encode(data) : data)) {
this.#a = (this.#a + BigInt(byte)) % 65521n;
this.#b = (this.#b + this.#a) % 65521n;
}
return this;
}
/**
* Initialize from the readable stream, asynchronously.
* @param {ReadableStream<Adler32AcceptDataType>} stream Readable stream.
* @returns {Promise<Adler32>}
*/
static async fromStream(stream: ReadableStream<Adler32AcceptDataType>): Promise<Adler32> {
const instance: Adler32 = new this();
for await (const chunk of stream) {
instance.update(chunk);
}
return instance;
}
}
export default Adler32;