-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutil.ts
155 lines (144 loc) · 3.17 KB
/
util.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/**
* @module
*
* Utility types and functions.
*/
import type { MemberClassKeys, MemberedClass } from './members.ts';
import type { BufferView } from './native.ts';
import type { Type } from './type.ts';
/**
* If types are equal.
*/
export type TypesEqual<A, B, X = A, Y = never> = (
<T>() => T extends A ? 1 : 2
) extends (
<T>() => T extends B ? 1 : 2
) ? X
: Y;
/**
* Readonly keys.
*/
export type ReadonlyKeyof<T> = {
[K in keyof T]: TypesEqual<
{ [Q in K]: T[K] },
{ -readonly [Q in K]: T[K] },
never,
K
>;
}[keyof T];
/**
* Define constant.
*
* @param o Object.
* @param key Key.
* @param value Value, or undefined for current value.
*/
export function constant<T, K extends ReadonlyKeyof<T>>(
o: T,
key: K,
value: T[K] | undefined = undefined,
): void {
Object.defineProperty(o, key, {
value: value === undefined ? o[key] : value,
configurable: false,
enumerable: false,
writable: false,
});
}
let dataViews: WeakMap<ArrayBufferLike, DataView>;
/**
* Get reusable data view of buffer.
*
* @param buffer Array buffer.
* @returns Data view.
*/
export function dataView(buffer: ArrayBufferLike): DataView {
let r = (dataViews ??= new WeakMap()).get(buffer);
if (!r) {
dataViews.set(buffer, r = new DataView(buffer));
}
return r;
}
/**
* Get byte offset of member.
*
* @param Type Type class.
* @param name Member name.
* @returns Byte offset.
*/
export function getByteOffset<T extends MemberedClass>(
Type: T,
name: MemberClassKeys<T>,
): number {
return Type.MEMBERS[name].byteOffset;
}
/**
* Get byte length of member.
*
* @param Type Type class.
* @param name Member name.
* @returns Byte length.
*/
export function getByteLength<T extends MemberedClass>(
Type: T,
name: MemberClassKeys<T>,
): number {
return Type.MEMBERS[name].byteLength;
}
/**
* Get members of type.
* Array indexes then member keys from highest to lowest inheritance.
*
* @param Type Type class.
* @returns Member list.
*/
export function getMembers<T extends MemberedClass>(
Type: T,
): (keyof T['prototype'])[] {
const props: Set<PropertyKey> | PropertyKey[] = new Set();
for (let m = Type.MEMBERS; m; m = Object.getPrototypeOf(m)) {
const keys = Reflect.ownKeys(m);
for (let i = keys.length; i--;) {
const k = keys[i];
props.delete(k);
props.add(k);
}
}
if ('LENGTH' in Type) {
for (let i = Type.LENGTH; i--;) {
props.delete(`${i}`);
props.add(i);
}
}
return [...props].reverse() as (keyof T['prototype'])[];
}
/**
* Assign ArrayBuffer data from one view to another.
*
* @param dst Destination memory.
* @param src Source memory of equal or greater size.
* @returns Destination memory.
*/
export function assignView<D extends BufferView>(
dst: D,
src: BufferView,
): D {
const { byteLength } = dst;
new Uint8Array(dst.buffer, dst.byteOffset, byteLength).set(
new Uint8Array(src.buffer, src.byteOffset, byteLength),
);
return dst;
}
/**
* Assign ArrayBuffer data from one type to another.
*
* @param dst Destination type.
* @param src Source type, must extend destination type.
* @returns Destination type.
*/
export function assignType<D extends Type, S extends D>(
dst: D,
src: S,
): D {
return assignView(dst, src);
}