utilium 2.0.0-pre.2 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/struct.js DELETED
@@ -1,204 +0,0 @@
1
- import { BufferViewArray } from './buffer.js';
2
- import { _debugLog } from './debugging.js';
3
- import * as primitive from './internal/primitives.js';
4
- import { checkStruct, initMetadata, isInstance, isStatic, isStruct } from './internal/struct.js';
5
- import { _throw } from './misc.js';
6
- import { getAllPrototypes } from './objects.js';
7
- export * as Struct from './internal/struct.js';
8
- /**
9
- * Gets the size in bytes of a type
10
- */
11
- export function sizeof(type) {
12
- if (type === undefined || type === null)
13
- return 0;
14
- if (Array.isArray(type)) {
15
- let size = 0;
16
- for (let i = 0; i < type.length; i++) {
17
- size += sizeof(type[i]);
18
- }
19
- return size;
20
- }
21
- // primitive or character
22
- if (typeof type == 'string') {
23
- primitive.checkValid(type);
24
- return primitive.types[primitive.normalize(type)].size;
25
- }
26
- if (primitive.isType(type))
27
- return type.size;
28
- checkStruct(type);
29
- const constructor = isStatic(type) ? type : type.constructor;
30
- const { struct, structInit } = constructor[Symbol.metadata];
31
- if (isStatic(type) || !struct.isDynamic)
32
- return struct.staticSize;
33
- const last = structInit.members.at(-1);
34
- const length = type[last.length];
35
- let dynamicSize = 0;
36
- if (primitive.isType(last.type)) {
37
- dynamicSize = last.type.size * length;
38
- }
39
- else {
40
- const value = type[last.name];
41
- for (let i = 0; i < length; i++) {
42
- dynamicSize += sizeof(isStruct(value[i]) ? value[i] : last.type);
43
- }
44
- }
45
- return (struct.isUnion ? Math.max(struct.staticSize, dynamicSize) : struct.staticSize + dynamicSize);
46
- }
47
- /**
48
- * Returns the offset (in bytes) of a member in a struct.
49
- */
50
- export function offsetof(type, memberName) {
51
- checkStruct(type);
52
- const constructor = isStatic(type) ? type : type.constructor;
53
- const member = constructor[Symbol.metadata].struct.members.get(memberName);
54
- if (!member)
55
- throw new Error('Struct does not have member: ' + memberName);
56
- return member.offset;
57
- }
58
- /** Aligns a number */
59
- export function align(value, alignment) {
60
- return Math.ceil(value / alignment) * alignment;
61
- }
62
- /**
63
- * Decorates a class as a struct
64
- */
65
- export function struct(options = {}) {
66
- return function _decorateStruct(target, context) {
67
- const init = initMetadata(context);
68
- const members = new Map();
69
- for (const member of init.members) {
70
- if (options.isUnion)
71
- member.offset = 0;
72
- _debugLog('define', target.name + '.' + member.name);
73
- members.set(member.name, member);
74
- }
75
- context.metadata.struct = {
76
- options,
77
- members,
78
- staticSize: init.size,
79
- isDynamic: init.isDynamic,
80
- isUnion: options.isUnion ?? false,
81
- };
82
- };
83
- }
84
- /**
85
- * Decorates a class member to be serialized
86
- */
87
- export function member(type, opt = {}) {
88
- return function __decorateMember(value, context) {
89
- if (context.kind != 'accessor')
90
- throw new Error('Member must be an accessor');
91
- const init = initMetadata(context);
92
- if (init.isDynamic)
93
- throw new Error('Dynamic members must be declared at the end of the struct');
94
- let name = context.name;
95
- if (typeof name == 'symbol') {
96
- console.warn('Symbol used for struct member name will be coerced to string: ' + name.toString());
97
- name = name.toString();
98
- }
99
- if (!name)
100
- throw new ReferenceError('Invalid name for struct member');
101
- if (!primitive.isType(type) && !isStatic(type))
102
- throw new TypeError('Not a valid type: ' + type.name);
103
- if (typeof opt.length == 'string') {
104
- const countedBy = init.members.find(m => m.name == opt.countedBy);
105
- if (!countedBy)
106
- throw new Error(`"${opt.countedBy}" is not declared and cannot be used to count "${name}"`);
107
- if (!primitive.isType(countedBy.type))
108
- throw new Error(`"${opt.countedBy}" is not a number and cannot be used to count "${name}"`);
109
- init.isDynamic = true;
110
- }
111
- const size = align(sizeof(type) * (typeof opt.length == 'string' ? 0 : (opt.length ?? 1)), opt.align ?? sizeof(type));
112
- const member = {
113
- name,
114
- offset: init.size,
115
- type,
116
- length: opt.length,
117
- countedBy: opt.countedBy,
118
- size,
119
- decl: `${opt.typeName ?? type.name} ${name}${opt.length !== undefined ? `[${JSON.stringify(opt.length)}]` : ''}`,
120
- littleEndian: !opt.bigEndian,
121
- };
122
- init.members.push(member);
123
- // Apply after setting `offset`
124
- init.size += size;
125
- return {
126
- get() {
127
- return _get(this, member);
128
- },
129
- set(value) {
130
- _set(this, member, value);
131
- },
132
- };
133
- };
134
- }
135
- /** Gets the length of a member */
136
- function _memberLength(instance, length, countedBy) {
137
- if (length === undefined)
138
- return -1;
139
- if (typeof countedBy == 'string')
140
- length = Math.min(length, instance[countedBy]);
141
- return Number.isSafeInteger(length) && length >= 0
142
- ? length
143
- : _throw(new Error('Array lengths must be natural numbers'));
144
- }
145
- function _set(instance, member, value, index) {
146
- const { name, type, length: maxLength, countedBy } = member;
147
- const length = _memberLength(instance, maxLength, countedBy);
148
- if (!primitive.isType(type)) {
149
- if (!isInstance(value))
150
- return _debugLog(`Tried to set "${name}" to a non-instance value`);
151
- if (length > 0 && typeof index != 'number') {
152
- for (let i = 0; i < length; i++)
153
- _set(instance, member, value[i], i);
154
- return;
155
- }
156
- if (!Array.from(getAllPrototypes(value.constructor)).some(c => c === type))
157
- throw new Error(`${value.constructor.name} is not a subtype of ${type.name}`);
158
- const offset = instance.byteOffset + member.offset + (index ?? 0) * sizeof(type);
159
- // It's already the same value
160
- if (value.buffer === instance.buffer && value.byteOffset === offset)
161
- return;
162
- const current = new Uint8Array(instance.buffer, offset, sizeof(value));
163
- current.set(new Uint8Array(value.buffer, value.byteOffset, sizeof(value)));
164
- return;
165
- }
166
- const view = new DataView(instance.buffer, instance.byteOffset, instance.byteLength);
167
- if (length > 0 && typeof index != 'number') {
168
- for (let i = 0; i < length; i++) {
169
- const offset = member.offset + i * type.size;
170
- type.set(view, offset, member.littleEndian, value[i]);
171
- }
172
- return;
173
- }
174
- if (typeof value == 'string')
175
- value = value.charCodeAt(0);
176
- type.set(view, member.offset + (index ?? 0) * type.size, member.littleEndian, value);
177
- }
178
- function _get(instance, member, index) {
179
- const { type, length: maxLength, countedBy } = member;
180
- const length = _memberLength(instance, maxLength, countedBy);
181
- if (length > 0 && typeof index != 'number') {
182
- return new (primitive.isType(type) ? type.array : BufferViewArray(type, sizeof(type)))(instance.buffer, instance.byteOffset + member.offset, length * sizeof(type));
183
- }
184
- const offset = member.offset + (index ?? 0) * sizeof(type);
185
- if (isStatic(type))
186
- return new type(instance.buffer, offset, sizeof(type));
187
- const view = new DataView(instance.buffer, instance.byteOffset, instance.byteLength);
188
- return type.get(view, offset, member.littleEndian);
189
- }
190
- function _member(typeName) {
191
- const type = primitive.types[primitive.normalize(typeName)];
192
- function _structMemberDecorator(valueOrLength, context) {
193
- return typeof valueOrLength == 'number'
194
- ? member(type, { typeName, length: valueOrLength, ...context })
195
- : member(type, { typeName })(valueOrLength, context && 'name' in context ? context : _throw('Invalid decorator context object'));
196
- }
197
- return _structMemberDecorator;
198
- }
199
- /**
200
- * Shortcut types
201
- *
202
- * Instead of writing `@member(type)` you can write `@types.type`, or `@types.type(length)` for arrays
203
- */
204
- export const types = Object.fromEntries(primitive.validNames.map(t => [t, _member(t)]));
package/src/buffer.ts DELETED
@@ -1,419 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-unused-expressions */
2
-
3
- import { _throw } from './misc.js';
4
- import type { Mutable } from './objects.js';
5
-
6
- /**
7
- * A generic constructor for an `ArrayBufferView`
8
- */
9
- export interface ArrayBufferViewConstructor {
10
- readonly prototype: ArrayBufferView<ArrayBufferLike>;
11
- new (length: number): ArrayBufferView<ArrayBuffer>;
12
- new (array: ArrayLike<number>): ArrayBufferView<ArrayBuffer>;
13
- new <TArrayBuffer extends ArrayBufferLike = ArrayBuffer>(
14
- buffer: TArrayBuffer,
15
- byteOffset?: number,
16
- length?: number
17
- ): ArrayBufferView<TArrayBuffer>;
18
- new (array: ArrayLike<number> | ArrayBuffer): ArrayBufferView<ArrayBuffer>;
19
- }
20
-
21
- /**
22
- * A generic typed array.
23
- */
24
- export interface TypedArray<TArrayBuffer extends ArrayBufferLike = ArrayBuffer, TValue = number | bigint>
25
- extends ArrayBufferView<TArrayBuffer> {
26
- /**
27
- * The size in bytes of each element in the array.
28
- */
29
- readonly BYTES_PER_ELEMENT: number;
30
-
31
- /**
32
- * Returns the this object after copying a section of the array identified by start and end
33
- * to the same array starting at position target
34
- * @param target If target is negative, it is treated as length+target where length is the
35
- * length of the array.
36
- * @param start If start is negative, it is treated as length+start. If end is negative, it
37
- * is treated as length+end.
38
- * @param end If not specified, length of the this object is used as its default value.
39
- */
40
- copyWithin(target: number, start: number, end?: number): this;
41
-
42
- /**
43
- * Determines whether all the members of an array satisfy the specified test.
44
- * @param predicate A function that accepts up to three arguments. The every method calls
45
- * the predicate function for each element in the array until the predicate returns a value
46
- * which is coercible to the Boolean value false, or until the end of the array.
47
- * @param thisArg An object to which the this keyword can refer in the predicate function.
48
- * If thisArg is omitted, undefined is used as the this value.
49
- */
50
- every(predicate: (value: TValue, index: number, array: this) => unknown, thisArg?: any): boolean;
51
-
52
- /**
53
- * Changes all array elements from `start` to `end` index to a static `value` and returns the modified array
54
- * @param value value to fill array section with
55
- * @param start index to start filling the array at. If start is negative, it is treated as
56
- * length+start where length is the length of the array.
57
- * @param end index to stop filling the array at. If end is negative, it is treated as
58
- * length+end.
59
- */
60
- fill(value: TValue, start?: number, end?: number): this;
61
-
62
- /**
63
- * Returns the elements of an array that meet the condition specified in a callback function.
64
- * @param predicate A function that accepts up to three arguments. The filter method calls
65
- * the predicate function one time for each element in the array.
66
- * @param thisArg An object to which the this keyword can refer in the predicate function.
67
- * If thisArg is omitted, undefined is used as the this value.
68
- */
69
- filter(
70
- predicate: (value: TValue, index: number, array: this) => any,
71
- thisArg?: any
72
- ): TypedArray<TArrayBuffer, TValue>;
73
-
74
- /**
75
- * Returns the value of the first element in the array where predicate is true, and undefined
76
- * otherwise.
77
- * @param predicate find calls predicate once for each element of the array, in ascending
78
- * order, until it finds one where predicate returns true. If such an element is found, find
79
- * immediately returns that element value. Otherwise, find returns undefined.
80
- * @param thisArg If provided, it will be used as the this value for each invocation of
81
- * predicate. If it is not provided, undefined is used instead.
82
- */
83
- find(predicate: (value: TValue, index: number, obj: this) => boolean, thisArg?: any): TValue | undefined;
84
-
85
- /**
86
- * Returns the index of the first element in the array where predicate is true, and -1
87
- * otherwise.
88
- * @param predicate find calls predicate once for each element of the array, in ascending
89
- * order, until it finds one where predicate returns true. If such an element is found,
90
- * findIndex immediately returns that element index. Otherwise, findIndex returns -1.
91
- * @param thisArg If provided, it will be used as the this value for each invocation of
92
- * predicate. If it is not provided, undefined is used instead.
93
- */
94
- findIndex(predicate: (value: TValue, index: number, obj: this) => boolean, thisArg?: any): number;
95
-
96
- /**
97
- * Performs the specified action for each element in an array.
98
- * @param callbackfn A function that accepts up to three arguments. forEach calls the
99
- * callbackfn function one time for each element in the array.
100
- * @param thisArg An object to which the this keyword can refer in the callbackfn function.
101
- * If thisArg is omitted, undefined is used as the this value.
102
- */
103
- forEach(callbackfn: (value: TValue, index: number, array: this) => void, thisArg?: any): void;
104
-
105
- /**
106
- * Returns the index of the first occurrence of a value in an array.
107
- * @param searchElement The value to locate in the array.
108
- * @param fromIndex The array index at which to begin the search. If fromIndex is omitted, the
109
- * search starts at index 0.
110
- */
111
- indexOf(searchElement: TValue, fromIndex?: number): number;
112
-
113
- /**
114
- * Adds all the elements of an array separated by the specified separator string.
115
- * @param separator A string used to separate one element of an array from the next in the
116
- * resulting String. If omitted, the array elements are separated with a comma.
117
- */
118
- join(separator?: string): string;
119
-
120
- /**
121
- * Returns the index of the last occurrence of a value in an array.
122
- * @param searchElement The value to locate in the array.
123
- * @param fromIndex The array index at which to begin the search. If fromIndex is omitted, the
124
- * search starts at index 0.
125
- */
126
- lastIndexOf(searchElement: TValue, fromIndex?: number): number;
127
-
128
- /**
129
- * The length of the array.
130
- */
131
- readonly length: number;
132
-
133
- /**
134
- * Calls a defined callback function on each element of an array, and returns an array that
135
- * contains the results.
136
- * @param callbackfn A function that accepts up to three arguments. The map method calls the
137
- * callbackfn function one time for each element in the array.
138
- * @param thisArg An object to which the this keyword can refer in the callbackfn function.
139
- * If thisArg is omitted, undefined is used as the this value.
140
- */
141
- map(
142
- callbackfn: (value: TValue, index: number, array: this) => TValue,
143
- thisArg?: any
144
- ): TypedArray<TArrayBuffer, TValue>;
145
-
146
- /**
147
- * Calls the specified callback function for all the elements in an array. The return value of
148
- * the callback function is the accumulated result, and is provided as an argument in the next
149
- * call to the callback function.
150
- * @param callbackfn A function that accepts up to four arguments. The reduce method calls the
151
- * callbackfn function one time for each element in the array.
152
- * @param initialValue If initialValue is specified, it is used as the initial value to start
153
- * the accumulation. The first call to the callbackfn function provides this value as an argument
154
- * instead of an array value.
155
- */
156
- reduce(
157
- callbackfn: (previousValue: TValue, currentValue: TValue, currentIndex: number, array: this) => number
158
- ): number;
159
- reduce(
160
- callbackfn: (previousValue: TValue, currentValue: TValue, currentIndex: number, array: this) => number,
161
- initialValue: number
162
- ): number;
163
-
164
- /**
165
- * Calls the specified callback function for all the elements in an array. The return value of
166
- * the callback function is the accumulated result, and is provided as an argument in the next
167
- * call to the callback function.
168
- * @param callbackfn A function that accepts up to four arguments. The reduce method calls the
169
- * callbackfn function one time for each element in the array.
170
- * @param initialValue If initialValue is specified, it is used as the initial value to start
171
- * the accumulation. The first call to the callbackfn function provides this value as an argument
172
- * instead of an array value.
173
- */
174
- reduce<U>(
175
- callbackfn: (previousValue: U, currentValue: TValue, currentIndex: number, array: this) => U,
176
- initialValue: U
177
- ): U;
178
-
179
- /**
180
- * Calls the specified callback function for all the elements in an array, in descending order.
181
- * The return value of the callback function is the accumulated result, and is provided as an
182
- * argument in the next call to the callback function.
183
- * @param callbackfn A function that accepts up to four arguments. The reduceRight method calls
184
- * the callbackfn function one time for each element in the array.
185
- * @param initialValue If initialValue is specified, it is used as the initial value to start
186
- * the accumulation. The first call to the callbackfn function provides this value as an
187
- * argument instead of an array value.
188
- */
189
- reduceRight(
190
- callbackfn: (previousValue: TValue, currentValue: TValue, currentIndex: number, array: this) => number
191
- ): number;
192
- reduceRight(
193
- callbackfn: (previousValue: TValue, currentValue: TValue, currentIndex: number, array: this) => number,
194
- initialValue: number
195
- ): number;
196
-
197
- /**
198
- * Calls the specified callback function for all the elements in an array, in descending order.
199
- * The return value of the callback function is the accumulated result, and is provided as an
200
- * argument in the next call to the callback function.
201
- * @param callbackfn A function that accepts up to four arguments. The reduceRight method calls
202
- * the callbackfn function one time for each element in the array.
203
- * @param initialValue If initialValue is specified, it is used as the initial value to start
204
- * the accumulation. The first call to the callbackfn function provides this value as an argument
205
- * instead of an array value.
206
- */
207
- reduceRight<U>(
208
- callbackfn: (previousValue: U, currentValue: TValue, currentIndex: TValue, array: this) => U,
209
- initialValue: U
210
- ): U;
211
-
212
- /**
213
- * Reverses the elements in an Array.
214
- */
215
- reverse(): this;
216
-
217
- /**
218
- * Sets a value or an array of values.
219
- * @param array A typed or untyped array of values to set.
220
- * @param offset The index in the current array at which the values are to be written.
221
- */
222
- set(array: ArrayLike<TValue>, offset?: number): void;
223
-
224
- /**
225
- * Returns a section of an array.
226
- * @param start The beginning of the specified portion of the array.
227
- * @param end The end of the specified portion of the array. This is exclusive of the element at the index 'end'.
228
- */
229
- slice(start?: number, end?: number): TypedArray<TArrayBuffer, TValue>;
230
-
231
- /**
232
- * Determines whether the specified callback function returns true for any element of an array.
233
- * @param predicate A function that accepts up to three arguments. The some method calls
234
- * the predicate function for each element in the array until the predicate returns a value
235
- * which is coercible to the Boolean value true, or until the end of the array.
236
- * @param thisArg An object to which the this keyword can refer in the predicate function.
237
- * If thisArg is omitted, undefined is used as the this value.
238
- */
239
- some(predicate: (value: TValue, index: number, array: this) => unknown, thisArg?: any): boolean;
240
-
241
- /**
242
- * Sorts an array.
243
- * @param compareFn Function used to determine the order of the elements. It is expected to return
244
- * a negative value if first argument is less than second argument, zero if they're equal and a positive
245
- * value otherwise. If omitted, the elements are sorted in ascending order.
246
- * ```ts
247
- * [11,2,22,1].sort((a, b) => a - b)
248
- * ```
249
- */
250
- sort(compareFn?: (a: TValue, b: TValue) => number): this;
251
-
252
- /**
253
- * Gets a new Int8Array view of the ArrayBuffer store for this array, referencing the elements
254
- * at begin, inclusive, up to end, exclusive.
255
- * @param begin The index of the beginning of the array.
256
- * @param end The index of the end of the array.
257
- */
258
- subarray(begin?: number, end?: number): TypedArray<TArrayBuffer, TValue>;
259
-
260
- /**
261
- * Converts a number to a string by using the current locale.
262
- */
263
- toLocaleString(): string;
264
-
265
- /**
266
- * Returns a string representation of an array.
267
- */
268
- toString(): string;
269
-
270
- /** Returns the primitive value of the specified object. */
271
- valueOf(): this;
272
-
273
- [index: number]: TValue;
274
- }
275
-
276
- export interface TypedArrayConstructor {
277
- readonly prototype: TypedArray<ArrayBufferLike>;
278
- new (length: number): TypedArray<ArrayBuffer>;
279
- new (array: ArrayLike<number>): TypedArray<ArrayBuffer>;
280
- new <TArrayBuffer extends ArrayBufferLike = ArrayBuffer>(
281
- buffer: TArrayBuffer,
282
- byteOffset?: number,
283
- length?: number
284
- ): TypedArray<TArrayBuffer>;
285
- new (array: ArrayLike<number> | ArrayBuffer): TypedArray<ArrayBuffer>;
286
- readonly BYTES_PER_ELEMENT: number;
287
- }
288
-
289
- /**
290
- * Grows a buffer if it isn't large enough
291
- * @returns The original buffer if resized successfully, or a newly created buffer
292
- */
293
- export function extendBuffer<T extends ArrayBufferLike | ArrayBufferView>(buffer: T, newByteLength: number): T {
294
- if (buffer.byteLength >= newByteLength) return buffer;
295
-
296
- if (ArrayBuffer.isView(buffer)) {
297
- const newBuffer = extendBuffer(buffer.buffer, newByteLength);
298
- return new (buffer.constructor as ArrayBufferViewConstructor)(newBuffer, buffer.byteOffset, newByteLength) as T;
299
- }
300
-
301
- const isShared = typeof SharedArrayBuffer !== 'undefined' && buffer instanceof SharedArrayBuffer;
302
-
303
- // Note: If true, the buffer must be resizable/growable because of the first check.
304
- if (buffer.maxByteLength > newByteLength) {
305
- isShared ? buffer.grow(newByteLength) : (buffer as ArrayBuffer).resize(newByteLength);
306
- return buffer;
307
- }
308
-
309
- if (isShared) {
310
- const newBuffer = new SharedArrayBuffer(newByteLength) as T & SharedArrayBuffer;
311
- new Uint8Array(newBuffer).set(new Uint8Array(buffer));
312
- return newBuffer;
313
- }
314
-
315
- try {
316
- return (buffer as ArrayBuffer).transfer(newByteLength) as T;
317
- } catch {
318
- const newBuffer = new ArrayBuffer(newByteLength) as T & ArrayBuffer;
319
- new Uint8Array(newBuffer).set(new Uint8Array(buffer));
320
- return newBuffer;
321
- }
322
- }
323
-
324
- export function toUint8Array(buffer: ArrayBufferLike | ArrayBufferView): Uint8Array {
325
- if (buffer instanceof Uint8Array) return buffer;
326
- if (!ArrayBuffer.isView(buffer)) return new Uint8Array(buffer);
327
- return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
328
- }
329
-
330
- export function initView<T extends ArrayBufferLike = ArrayBuffer>(
331
- view: Mutable<ArrayBufferView<T> & { BYTES_PER_ELEMENT?: number }>,
332
- buffer?: T | ArrayBufferView<T> | ArrayLike<number> | number,
333
- byteOffset?: number,
334
- byteLength?: number
335
- ) {
336
- if (typeof buffer == 'number') {
337
- const per = view.BYTES_PER_ELEMENT ?? _throw('BYTES_PER_ELEMENT is not set');
338
- view.buffer = new ArrayBuffer(buffer * per) as T;
339
- view.byteOffset = 0;
340
- view.byteLength = buffer * per;
341
- return;
342
- }
343
-
344
- if (
345
- !buffer
346
- || buffer instanceof ArrayBuffer
347
- || (globalThis.SharedArrayBuffer && buffer instanceof globalThis.SharedArrayBuffer)
348
- ) {
349
- const { staticSize = 0 } = (view.constructor as any)?.[Symbol.metadata]?.struct ?? {};
350
- view.buffer = buffer ?? (new ArrayBuffer(staticSize) as T);
351
- view.byteOffset = byteOffset ?? 0;
352
- view.byteLength = byteLength ?? staticSize;
353
- return;
354
- }
355
-
356
- if (ArrayBuffer.isView(buffer)) {
357
- view.buffer = buffer.buffer;
358
- view.byteOffset = buffer.byteOffset;
359
- view.byteLength = buffer.byteLength;
360
- return;
361
- }
362
-
363
- const array = buffer as ArrayLike<number>;
364
-
365
- view.buffer = new ArrayBuffer(array.length) as T;
366
- view.byteOffset = 0;
367
- view.byteLength = array.length;
368
-
369
- const data = new Uint8Array(view.buffer);
370
- for (let i = 0; i < array.length; i++) {
371
- data[i] = array[i];
372
- }
373
- }
374
-
375
- /** Creates a view of an array buffer */
376
- export class BufferView<T extends ArrayBufferLike = ArrayBufferLike> implements ArrayBufferView<T> {
377
- declare public readonly buffer: T;
378
- declare public readonly byteOffset: number;
379
- declare public readonly byteLength: number;
380
-
381
- public constructor(buffer?: T | ArrayBufferView<T> | ArrayLike<number>, byteOffset?: number, byteLength?: number) {
382
- initView<T>(this, buffer, byteOffset, byteLength);
383
- }
384
- }
385
-
386
- BufferView satisfies ArrayBufferViewConstructor;
387
-
388
- /** Creates an array of a buffer view type */
389
- export function BufferViewArray<T extends ArrayBufferViewConstructor>(element: T, size: number) {
390
- return class BufferViewArray<TArrayBuffer extends ArrayBufferLike = ArrayBuffer> extends Array {
391
- public readonly BYTES_PER_ELEMENT: number = size;
392
-
393
- declare public readonly buffer: TArrayBuffer;
394
- declare public readonly byteOffset: number;
395
- declare public readonly byteLength: number;
396
-
397
- public constructor(
398
- buffer?: TArrayBuffer | ArrayBufferView<TArrayBuffer> | ArrayLike<number>,
399
- byteOffset?: number,
400
- byteLength?: number
401
- ) {
402
- const t_size = size;
403
-
404
- const length = (byteLength ?? t_size) / t_size;
405
-
406
- if (!Number.isSafeInteger(length)) throw new Error('Invalid array length: ' + length);
407
-
408
- super(length);
409
-
410
- initView(this, buffer, byteOffset, byteLength);
411
-
412
- for (let i = 0; i < length; i++) {
413
- this[i] = new element(this.buffer, this.byteOffset + i * t_size, t_size);
414
- }
415
- }
416
- };
417
- }
418
-
419
- BufferView satisfies ArrayBufferViewConstructor;