-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathstate-serialization.ts
More file actions
103 lines (96 loc) · 3.24 KB
/
Copy pathstate-serialization.ts
File metadata and controls
103 lines (96 loc) · 3.24 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
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
const TYPED_ARRAY_CTORS: Record<string, { from(values: Iterable<unknown>): ArrayBufferView }> = {
Int8Array,
Uint8Array,
Uint8ClampedArray,
Int16Array,
Uint16Array,
Int32Array,
Uint32Array,
Float32Array,
Float64Array,
BigInt64Array,
BigUint64Array,
};
type EncodedSpecial =
| { __ae_type: 'TypedArray'; name: string; values: unknown[] }
| { __ae_type: 'DataView'; bytes: number[] }
| { __ae_type: 'ArrayBuffer'; bytes: number[] }
| { __ae_type: 'SharedArrayBuffer'; bytes: number[] };
export function encodeSpecialValue(value: unknown): unknown {
if (value && typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) {
return value;
}
if (value && ArrayBuffer.isView(value)) {
if (value instanceof DataView) {
const bytes = Array.from(new Uint8Array(value.buffer, value.byteOffset, value.byteLength));
return { __ae_type: 'DataView', bytes } satisfies EncodedSpecial;
}
const name = value.constructor?.name;
if (name && TYPED_ARRAY_CTORS[name]) {
const values = Array.from(value as unknown as Iterable<unknown>);
return { __ae_type: 'TypedArray', name, values } satisfies EncodedSpecial;
}
}
if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {
return {
__ae_type: 'ArrayBuffer',
bytes: Array.from(new Uint8Array(value)),
} satisfies EncodedSpecial;
}
if (typeof SharedArrayBuffer !== 'undefined' && value instanceof SharedArrayBuffer) {
return {
__ae_type: 'SharedArrayBuffer',
bytes: Array.from(new Uint8Array(value)),
} satisfies EncodedSpecial;
}
return value;
}
export function reviveSpecialValue(value: unknown, seen = new WeakSet<object>()): unknown {
if (!value || typeof value !== 'object') {
return value;
}
const marker = (value as { __ae_type?: string }).__ae_type;
if (marker === 'TypedArray') {
const { name, values } = value as EncodedSpecial & { name: string; values: unknown[] };
const ctor = TYPED_ARRAY_CTORS[name];
if (ctor) {
return ctor.from(values);
}
return values;
}
if (marker === 'DataView') {
const bytes = (value as EncodedSpecial & { bytes: number[] }).bytes ?? [];
const buffer = new ArrayBuffer(bytes.length);
new Uint8Array(buffer).set(bytes);
return new DataView(buffer);
}
if (marker === 'ArrayBuffer') {
const bytes = (value as EncodedSpecial & { bytes: number[] }).bytes ?? [];
const buffer = new ArrayBuffer(bytes.length);
new Uint8Array(buffer).set(bytes);
return buffer;
}
if (marker === 'SharedArrayBuffer') {
const bytes = (value as EncodedSpecial & { bytes: number[] }).bytes ?? [];
if (typeof SharedArrayBuffer !== 'undefined') {
const shared = new SharedArrayBuffer(bytes.length);
new Uint8Array(shared).set(bytes);
return shared;
}
const buffer = new ArrayBuffer(bytes.length);
new Uint8Array(buffer).set(bytes);
return buffer;
}
if (seen.has(value as object)) {
return value;
}
seen.add(value as object);
if (Array.isArray(value)) {
return value.map((item) => reviveSpecialValue(item, seen));
}
const result: Record<string, unknown> = {};
for (const [key, val] of Object.entries(value)) {
result[key] = reviveSpecialValue(val, seen);
}
return result;
}