This repository was archived by the owner on Aug 7, 2026. It is now read-only.
Repository navigation
Expand file tree
/
Copy pathlz4.ts
More file actions
73 lines (62 loc) · 2.44 KB
/
Copy pathlz4.ts
File metadata and controls
73 lines (62 loc) · 2.44 KB
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
import type { Codec, CodecConstructor } from "./types.js";
type WasmModule = typeof import("../pkg/rumcodecs-wasm-node/rumcodecs_wasm.js");
const DEFAULT_ACCELERATION = 1;
const MAX_BUFFER_SIZE = 0x7e000000;
let wasmModule: Promise<WasmModule> | null = null;
async function getModule(): Promise<WasmModule> {
if (!wasmModule) {
wasmModule = import("../pkg/rumcodecs-wasm-node/rumcodecs_wasm.js");
}
return wasmModule;
}
interface LZ4Config {
acceleration?: number;
}
const LZ4: CodecConstructor<LZ4Config> = class LZ4 implements Codec {
public static codecId = "lz4";
public static DEFAULT_ACCELERATION = DEFAULT_ACCELERATION;
public static max_buffer_size = MAX_BUFFER_SIZE;
public max_buffer_size = MAX_BUFFER_SIZE;
public acceleration: number;
constructor(acceleration = DEFAULT_ACCELERATION) {
if (!Number.isInteger(acceleration)) {
throw Error(`Invalid acceleration "${acceleration}". Must be a positive integer.`);
}
this.acceleration = acceleration <= 0 ? DEFAULT_ACCELERATION : acceleration;
}
static fromConfig({ acceleration }: LZ4Config): LZ4 {
return new LZ4(acceleration);
}
async encode(data: Uint8Array): Promise<Uint8Array> {
if (data.length > MAX_BUFFER_SIZE) {
throw Error(`Codec does not support buffers of > ${MAX_BUFFER_SIZE} bytes.`);
}
const m = await getModule();
return m.lz4_compress(data, this.acceleration);
}
async decode(data: Uint8Array, out?: Uint8Array): Promise<Uint8Array> {
if (data.length > MAX_BUFFER_SIZE) {
throw Error(`Codec does not support buffers of > ${MAX_BUFFER_SIZE} bytes.`);
}
// The header is the numcodecs framing: a 4-byte LE original size. It gives
// us the exact length a successful decode has to produce, which is what
// separates a genuine empty payload from the empty Vec the WASM side
// returns on failure. Without this check a corrupt chunk decodes to a
// zero-filled `out` and reaches the caller as data.
if (data.length < 4) {
throw new Error("LZ4 decompression failed: input is shorter than the size header");
}
const declared = new DataView(data.buffer, data.byteOffset, 4).getUint32(0, true);
const m = await getModule();
const result = m.lz4_decompress(data);
if (result.length !== declared) {
throw new Error("LZ4 decompression failed");
}
if (out !== undefined) {
out.set(result);
return out;
}
return result;
}
};
export default LZ4;