utilium 1.7.11 → 1.7.13

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.
@@ -27,4 +27,16 @@ type LoggableDecoratorContext = Exclude<DecoratorContext, ClassFieldDecoratorCon
27
27
  * Create a function that can be used to decorate classes and non-field members.
28
28
  */
29
29
  export declare function createLogDecorator(options: CreateLoggerOptions): <T extends (...args: any[]) => any>(value: T, context: LoggableDecoratorContext) => T;
30
+ /**
31
+ * @internal @hidden
32
+ */
33
+ export declare let U_DEBUG: boolean;
34
+ /**
35
+ * @internal @hidden
36
+ */
37
+ export declare function _setDebug(value: boolean): void;
38
+ /**
39
+ * @internal @hidden
40
+ */
41
+ export declare function _debugLog(...text: any[]): void;
30
42
  export {};
package/dist/debugging.js CHANGED
@@ -53,3 +53,20 @@ export function createLogDecorator(options) {
53
53
  };
54
54
  };
55
55
  }
56
+ /**
57
+ * @internal @hidden
58
+ */
59
+ export let U_DEBUG = 'process' in globalThis && 'env' in globalThis.process && globalThis.process.env.U_DEBUG == 'true';
60
+ /**
61
+ * @internal @hidden
62
+ */
63
+ export function _setDebug(value) {
64
+ U_DEBUG = value;
65
+ }
66
+ /**
67
+ * @internal @hidden
68
+ */
69
+ export function _debugLog(...text) {
70
+ if (U_DEBUG)
71
+ console.debug('[U]', ...text);
72
+ }
@@ -10,7 +10,7 @@ declare global {
10
10
  readonly deserialize: unique symbol;
11
11
  }
12
12
  }
13
- export type TypeLike = Custom | Like | primitive.Valid;
13
+ export type TypeLike = Custom | Like | primitive.Valid | undefined | null;
14
14
  export type Type = Custom | Static | primitive.Typename;
15
15
  /**
16
16
  * Member initialization data
@@ -30,22 +30,31 @@ export interface Options {
30
30
  isUnion: boolean;
31
31
  }
32
32
  export interface Member {
33
+ name: string;
33
34
  type: Type;
34
- offset: number;
35
+ staticOffset: number;
35
36
  length?: number | string;
37
+ /** A C-style type/name declaration string, used for diagnostics */
38
+ decl: string;
36
39
  }
37
40
  export interface Metadata {
38
41
  options: Partial<Options>;
39
42
  members: Map<string, Member>;
40
- init?: MemberInit[];
41
43
  staticSize: number;
44
+ isDynamic: boolean;
42
45
  }
43
46
  type _DecoratorMetadata<T extends Metadata = Metadata> = DecoratorMetadata & {
44
- struct?: Partial<T>;
47
+ struct?: T;
48
+ structInit?: MemberInit[];
45
49
  };
46
50
  export interface DecoratorContext<T extends Metadata = Metadata> {
47
51
  metadata: _DecoratorMetadata<T>;
48
52
  }
53
+ /**
54
+ * Initializes the struct metadata for a class
55
+ * This also handles copying metadata from parent classes
56
+ */
57
+ export declare function initMetadata(context: DecoratorContext): MemberInit[];
49
58
  export type MemberContext = ClassMemberDecoratorContext & DecoratorContext;
50
59
  export interface Static<T extends Metadata = Metadata> {
51
60
  [Symbol.metadata]: {
@@ -63,12 +72,9 @@ export declare function isValidMetadata<T extends Metadata = Metadata>(arg: unkn
63
72
  /**
64
73
  * Polyfill context.metadata
65
74
  * @see https://github.com/microsoft/TypeScript/issues/53461
75
+ * @internal @hidden
66
76
  */
67
- export declare function _polyfill_contextMetadata(target: object): void;
68
- /**
69
- * Gets a reference to Symbol.metadata, even on platforms that do not expose it globally (like Node)
70
- */
71
- export declare function symbol_metadata(arg: ClassLike): typeof Symbol.metadata;
77
+ export declare function _polyfill_metadata(target: object): void;
72
78
  export declare function isStatic<T extends Metadata = Metadata>(arg: unknown): arg is Static<T>;
73
79
  export interface Instance<T extends Metadata = Metadata> {
74
80
  constructor: Static<T>;
@@ -90,7 +96,7 @@ export interface Custom {
90
96
  }
91
97
  export declare function isCustom(arg: unknown): arg is Custom;
92
98
  export type Like<T extends Metadata = Metadata> = InstanceLike<T> | StaticLike<T>;
93
- export type Size<T extends TypeLike> = T extends {
94
- readonly [Symbol.size]: infer S;
99
+ export type Size<T extends TypeLike> = T extends undefined | null ? 0 : T extends {
100
+ readonly [Symbol.size]: infer S extends number;
95
101
  } ? S : T extends primitive.Valid ? primitive.Size<T> : number;
96
102
  export {};
@@ -1,22 +1,32 @@
1
+ /**
2
+ * Polyfill Symbol.metadata
3
+ * @see https://github.com/microsoft/TypeScript/issues/53461
4
+ */
5
+ Symbol.metadata ??= Symbol.for('Symbol.metadata');
1
6
  Object.assign(Symbol, {
2
7
  size: Symbol('uSize'),
3
8
  serialize: Symbol('uSerialize'),
4
9
  deserialize: Symbol('uDeserialize'),
5
10
  });
11
+ /**
12
+ * Initializes the struct metadata for a class
13
+ * This also handles copying metadata from parent classes
14
+ */
15
+ export function initMetadata(context) {
16
+ context.metadata ??= {};
17
+ context.metadata.structInit = [...(context.metadata.structInit ?? [])];
18
+ return context.metadata.structInit;
19
+ }
6
20
  export function isValidMetadata(arg) {
7
21
  return arg != null && typeof arg == 'object' && 'struct' in arg;
8
22
  }
9
- /**
10
- * Polyfill Symbol.metadata
11
- * @see https://github.com/microsoft/TypeScript/issues/53461
12
- */
13
- Symbol.metadata ??= Symbol.for('Symbol.metadata');
14
23
  /**
15
24
  * Polyfill context.metadata
16
25
  * @see https://github.com/microsoft/TypeScript/issues/53461
26
+ * @internal @hidden
17
27
  */
18
- export function _polyfill_contextMetadata(target) {
19
- if (!Symbol?.metadata || Symbol.metadata in target)
28
+ export function _polyfill_metadata(target) {
29
+ if (Symbol.metadata in target)
20
30
  return;
21
31
  Object.defineProperty(target, Symbol.metadata, {
22
32
  enumerable: true,
@@ -25,21 +35,8 @@ export function _polyfill_contextMetadata(target) {
25
35
  value: Object.create(null),
26
36
  });
27
37
  }
28
- /**
29
- * Gets a reference to Symbol.metadata, even on platforms that do not expose it globally (like Node)
30
- */
31
- export function symbol_metadata(arg) {
32
- const symbol_metadata = Symbol.metadata || Object.getOwnPropertySymbols(arg).find(s => s.description == 'Symbol.metadata');
33
- _polyfill_contextMetadata(arg);
34
- if (!symbol_metadata) {
35
- throw new ReferenceError('Could not get a reference to Symbol.metadata');
36
- }
37
- return symbol_metadata;
38
- }
39
38
  export function isStatic(arg) {
40
- return (typeof arg == 'function'
41
- && symbol_metadata(arg) in arg
42
- && isValidMetadata(arg[symbol_metadata(arg)]));
39
+ return typeof arg == 'function' && Symbol.metadata in arg && isValidMetadata(arg[Symbol.metadata]);
43
40
  }
44
41
  export function isInstance(arg) {
45
42
  return arg != null && typeof arg == 'object' && isStatic(arg.constructor);
package/dist/struct.d.ts CHANGED
@@ -5,7 +5,7 @@ export * as Struct from './internal/struct.js';
5
5
  /**
6
6
  * Gets the size in bytes of a type
7
7
  */
8
- export declare function sizeof<T extends TypeLike>(type: T): Size<T>;
8
+ export declare function sizeof<T extends TypeLike>(type: T | T[]): Size<T>;
9
9
  /**
10
10
  * Returns the offset (in bytes) of a member in a struct.
11
11
  */
package/dist/struct.js CHANGED
@@ -1,50 +1,46 @@
1
1
  import { toUint8Array } from './buffer.js';
2
+ import { _debugLog } from './debugging.js';
2
3
  import * as primitive from './internal/primitives.js';
3
- import { checkInstance, checkStruct, isCustom, isStatic, symbol_metadata } from './internal/struct.js';
4
+ import { _polyfill_metadata, checkInstance, checkStruct, initMetadata, isCustom, isInstance, isStatic, } from './internal/struct.js';
4
5
  import { _throw } from './misc.js';
5
6
  import { capitalize } from './string.js';
6
7
  export * as Struct from './internal/struct.js';
7
- /**
8
- * Gets the length of an array in a struct
9
- * @param length The numeric length or the name of the field which has the array length (like __counted_by)
10
- * @param name The name of the array field— only used for errors
11
- */
12
- function _memberLength(struct, length, name) {
13
- if (length === undefined)
14
- return -1;
15
- if (typeof length != 'string')
16
- return Number.isSafeInteger(length) && length >= 0
17
- ? length
18
- : _throw(new Error('Array lengths must be natural numbers'));
19
- if (!(length in struct))
20
- throw new Error(`Can not use non-existent member to count ${name}: ` + length);
21
- const n = struct[length];
22
- if (typeof n != 'number')
23
- throw new Error(`Can not use "${name}" to count ${length}`);
24
- return n;
25
- }
26
8
  /**
27
9
  * Gets the size in bytes of a type
28
10
  */
29
11
  export function sizeof(type) {
30
- // primitive
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
31
22
  if (typeof type == 'string') {
23
+ // Single character inside string, since sizeof(string) -> sizeof(string[0]) -> here
24
+ if (type.length == 1)
25
+ return 1;
32
26
  primitive.checkValid(type);
33
27
  return (+primitive.normalize(type).match(primitive.regex)[2] / 8);
34
28
  }
35
29
  if (isCustom(type))
36
30
  return type[Symbol.size];
37
31
  checkStruct(type);
38
- const { struct } = isStatic(type)
39
- ? type[symbol_metadata(type)]
40
- : type.constructor[symbol_metadata(type.constructor)];
32
+ const constructor = isStatic(type) ? type : type.constructor;
33
+ _polyfill_metadata(constructor);
34
+ const { struct } = constructor[Symbol.metadata];
41
35
  if (isStatic(type))
42
36
  return struct.staticSize;
43
37
  let size = struct.staticSize;
44
- for (const [name, { type: memberType, length: key }] of struct.members) {
45
- if (typeof key != 'string')
38
+ for (const member of struct.members.values()) {
39
+ if (typeof member.length != 'string')
46
40
  continue;
47
- size += sizeof(memberType) * _memberLength(type, key, name);
41
+ for (let i = 0; i < type[member.length]; i++) {
42
+ size += sizeof(type[member.name][i]);
43
+ }
48
44
  }
49
45
  return size;
50
46
  }
@@ -53,12 +49,20 @@ export function sizeof(type) {
53
49
  */
54
50
  export function offsetof(type, memberName) {
55
51
  checkStruct(type);
56
- const struct = isStatic(type) ? type : type.constructor;
57
- const metadata = struct[symbol_metadata(struct)].struct;
58
- const member = metadata.members.get(memberName);
59
- if (!member)
60
- throw new Error('Struct does not have member: ' + memberName);
61
- return member.offset;
52
+ const constructor = isStatic(type) ? type : type.constructor;
53
+ _polyfill_metadata(constructor);
54
+ const { struct } = constructor[Symbol.metadata];
55
+ if (isStatic(type) || !struct.isDynamic) {
56
+ return (struct.members.get(memberName)?.staticOffset
57
+ ?? _throw(new Error('Struct does not have member: ' + memberName)));
58
+ }
59
+ let offset = 0;
60
+ for (const member of struct.members.values()) {
61
+ if (member.name == memberName)
62
+ return offset;
63
+ offset += sizeof(type[member.name]);
64
+ }
65
+ throw new Error('Struct does not have member: ' + memberName);
62
66
  }
63
67
  /**
64
68
  * Aligns a number
@@ -71,24 +75,35 @@ export function align(value, alignment) {
71
75
  */
72
76
  export function struct(options = {}) {
73
77
  return function _decorateStruct(target, context) {
74
- context.metadata ??= {};
75
- context.metadata.struct ??= {};
76
- context.metadata.struct.init ??= [];
77
- let staticSize = 0;
78
78
  const members = new Map();
79
- for (const { name, type, length } of context.metadata.struct.init) {
79
+ let staticSize = 0, isDynamic = false;
80
+ for (const { name, type, length } of initMetadata(context)) {
80
81
  if (!primitive.isValid(type) && !isStatic(type))
81
82
  throw new TypeError('Not a valid type: ' + type);
83
+ if (typeof length == 'string') {
84
+ const countedBy = members.get(length);
85
+ if (!countedBy)
86
+ throw new Error(`"${length}" is undefined or declared after "${name}"`);
87
+ if (!primitive.isType(countedBy.type))
88
+ throw new Error(`"${length}" is not a number and cannot be used to count "${name}"`);
89
+ }
90
+ let decl = `${typeof type == 'string' ? type : type.name} ${name}`;
91
+ if (length !== undefined)
92
+ decl += `[${length}]`;
82
93
  members.set(name, {
83
- offset: options.isUnion ? 0 : staticSize,
94
+ name,
95
+ staticOffset: options.isUnion ? 0 : staticSize,
84
96
  type: primitive.isValid(type) ? primitive.normalize(type) : type,
85
97
  length,
98
+ decl,
86
99
  });
87
100
  const memberSize = typeof length == 'string' ? 0 : sizeof(type) * (length || 1);
101
+ isDynamic ||= typeof length == 'string';
88
102
  staticSize = options.isUnion ? Math.max(staticSize, memberSize) : staticSize + memberSize;
89
103
  staticSize = align(staticSize, options.align || 1);
104
+ _debugLog('define', target.name + '.' + name);
90
105
  }
91
- context.metadata.struct = { options, members, staticSize };
106
+ context.metadata.struct = { options, members, staticSize, isDynamic };
92
107
  return target;
93
108
  };
94
109
  }
@@ -104,13 +119,20 @@ export function member(type, length) {
104
119
  }
105
120
  if (!name)
106
121
  throw new ReferenceError('Invalid name for struct member');
107
- context.metadata ??= {};
108
- context.metadata.struct ??= {};
109
- context.metadata.struct.init ??= [];
110
- context.metadata.struct.init.push({ name, type, length });
122
+ initMetadata(context).push({ name, type, length });
111
123
  return value;
112
124
  };
113
125
  }
126
+ /** Gets the length of a member */
127
+ function _memberLength(instance, member) {
128
+ if (member.length === undefined)
129
+ return -1;
130
+ if (typeof member.length == 'string')
131
+ return instance[member.length];
132
+ return Number.isSafeInteger(member.length) && member.length >= 0
133
+ ? member.length
134
+ : _throw(new Error('Array lengths must be natural numbers'));
135
+ }
114
136
  /**
115
137
  * Serializes a struct into a Uint8Array
116
138
  */
@@ -118,47 +140,53 @@ export function serialize(instance) {
118
140
  if (isCustom(instance) && typeof instance[Symbol.serialize] == 'function')
119
141
  return instance[Symbol.serialize]();
120
142
  checkInstance(instance);
121
- const { options, members } = instance.constructor[symbol_metadata(instance.constructor)].struct;
122
- const buffer = new Uint8Array(sizeof(instance));
143
+ _polyfill_metadata(instance.constructor);
144
+ const { options, members } = instance.constructor[Symbol.metadata].struct;
145
+ const size = sizeof(instance);
146
+ const buffer = new Uint8Array(size);
123
147
  const view = new DataView(buffer.buffer);
148
+ _debugLog('serialize', instance.constructor.name);
149
+ let offset = 0, nextOffset = 0;
124
150
  // for unions we should write members in ascending last modified order, but we don't have that info.
125
- for (const [name, { type, length: rawLength, offset }] of members) {
126
- const length = _memberLength(instance, rawLength, name);
151
+ for (const member of members.values()) {
152
+ const length = _memberLength(instance, member);
153
+ _debugLog('\t', member.decl);
127
154
  for (let i = 0; i < Math.abs(length); i++) {
128
- const iOff = offset + sizeof(type) * i;
129
- let value = length != -1 ? instance[name][i] : instance[name];
155
+ let value = length != -1 ? instance[member.name][i] : instance[member.name];
130
156
  if (typeof value == 'string') {
131
157
  value = value.charCodeAt(0);
132
158
  }
133
- if (!primitive.isType(type)) {
134
- buffer.set(value ? serialize(value) : new Uint8Array(sizeof(type)), iOff);
159
+ offset = nextOffset;
160
+ nextOffset += isInstance(value) ? sizeof(value) : sizeof(member.type);
161
+ if (!primitive.isType(member.type)) {
162
+ buffer.set(value ? serialize(value) : new Uint8Array(sizeof(member.type)), offset);
135
163
  continue;
136
164
  }
137
- const fn = `set${capitalize(type)}`;
165
+ const fn = `set${capitalize(member.type)}`;
138
166
  if (fn == 'setInt64') {
139
- view.setBigInt64(iOff, BigInt(value), !options.bigEndian);
167
+ view.setBigInt64(offset, BigInt(value), !options.bigEndian);
140
168
  continue;
141
169
  }
142
170
  if (fn == 'setUint64') {
143
- view.setBigUint64(iOff, BigInt(value), !options.bigEndian);
171
+ view.setBigUint64(offset, BigInt(value), !options.bigEndian);
144
172
  continue;
145
173
  }
146
174
  if (fn == 'setInt128') {
147
- view.setBigUint64(iOff + (!options.bigEndian ? 0 : 8), value & primitive.mask64, !options.bigEndian);
148
- view.setBigInt64(iOff + (!options.bigEndian ? 8 : 0), value >> BigInt(64), !options.bigEndian);
175
+ view.setBigUint64(offset + (!options.bigEndian ? 0 : 8), value & primitive.mask64, !options.bigEndian);
176
+ view.setBigInt64(offset + (!options.bigEndian ? 8 : 0), value >> BigInt(64), !options.bigEndian);
149
177
  continue;
150
178
  }
151
179
  if (fn == 'setUint128') {
152
- view.setBigUint64(iOff + (!options.bigEndian ? 0 : 8), value & primitive.mask64, !options.bigEndian);
153
- view.setBigUint64(iOff + (!options.bigEndian ? 8 : 0), value >> BigInt(64), !options.bigEndian);
180
+ view.setBigUint64(offset + (!options.bigEndian ? 0 : 8), value & primitive.mask64, !options.bigEndian);
181
+ view.setBigUint64(offset + (!options.bigEndian ? 8 : 0), value >> BigInt(64), !options.bigEndian);
154
182
  continue;
155
183
  }
156
184
  if (fn == 'setFloat128') {
157
- view.setFloat64(iOff + (!options.bigEndian ? 0 : 8), Number(value), !options.bigEndian);
158
- view.setBigUint64(iOff + (!options.bigEndian ? 8 : 0), BigInt(0), !options.bigEndian);
185
+ view.setFloat64(offset + (!options.bigEndian ? 0 : 8), Number(value), !options.bigEndian);
186
+ view.setBigUint64(offset + (!options.bigEndian ? 8 : 0), BigInt(0), !options.bigEndian);
159
187
  continue;
160
188
  }
161
- view[fn](iOff, Number(value), !options.bigEndian);
189
+ view[fn](offset, Number(value), !options.bigEndian);
162
190
  }
163
191
  }
164
192
  return buffer;
@@ -171,53 +199,62 @@ export function deserialize(instance, _buffer) {
171
199
  if (isCustom(instance) && typeof instance[Symbol.deserialize] == 'function')
172
200
  return instance[Symbol.deserialize](buffer);
173
201
  checkInstance(instance);
174
- const { options, members } = instance.constructor[symbol_metadata(instance.constructor)].struct;
202
+ _polyfill_metadata(instance.constructor);
203
+ const { options, members } = instance.constructor[Symbol.metadata].struct;
175
204
  const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
176
- for (const [name, { type, offset, length: rawLength }] of members) {
177
- const length = _memberLength(instance, rawLength, name);
205
+ _debugLog('deserialize', instance.constructor.name);
206
+ let offset = 0, nextOffset = 0;
207
+ for (const member of members.values()) {
208
+ const length = _memberLength(instance, member);
209
+ _debugLog('\t', member.decl);
178
210
  for (let i = 0; i < Math.abs(length); i++) {
179
- let object = length != -1 ? instance[name] : instance;
180
- const key = length != -1 ? i : name, iOff = offset + sizeof(type) * i;
181
- if (typeof instance[name] == 'string') {
182
- instance[name] =
183
- instance[name].slice(0, i) + String.fromCharCode(view.getUint8(iOff)) + instance[name].slice(i + 1);
211
+ let object = length != -1 ? instance[member.name] : instance;
212
+ const key = length != -1 ? i : member.name;
213
+ offset = nextOffset;
214
+ if (!isInstance(object[key]))
215
+ nextOffset += sizeof(member.type);
216
+ if (typeof instance[member.name] == 'string') {
217
+ instance[member.name] =
218
+ instance[member.name].slice(0, i)
219
+ + String.fromCharCode(view.getUint8(offset))
220
+ + instance[member.name].slice(i + 1);
184
221
  continue;
185
222
  }
186
- if (!primitive.isType(type)) {
187
- if (object[key] === null || object[key] === undefined) {
223
+ if (!primitive.isType(member.type)) {
224
+ if (object[key] === null || object[key] === undefined)
188
225
  continue;
189
- }
190
- deserialize(object[key], new Uint8Array(buffer.subarray(iOff, iOff + sizeof(type))));
226
+ deserialize(object[key], new Uint8Array(buffer.subarray(offset)));
227
+ nextOffset += sizeof(object[key]);
191
228
  continue;
192
229
  }
193
230
  if (length && length != -1)
194
231
  object ||= [];
195
- const fn = `get${capitalize(type)}`;
232
+ const fn = `get${capitalize(member.type)}`;
196
233
  if (fn == 'getInt64') {
197
- object[key] = view.getBigInt64(iOff, !options.bigEndian);
234
+ object[key] = view.getBigInt64(offset, !options.bigEndian);
198
235
  continue;
199
236
  }
200
237
  if (fn == 'getUint64') {
201
- object[key] = view.getBigUint64(iOff, !options.bigEndian);
238
+ object[key] = view.getBigUint64(offset, !options.bigEndian);
202
239
  continue;
203
240
  }
204
241
  if (fn == 'getInt128') {
205
242
  object[key] =
206
- (view.getBigInt64(iOff + (!options.bigEndian ? 8 : 0), !options.bigEndian) << BigInt(64))
207
- | view.getBigUint64(iOff + (!options.bigEndian ? 0 : 8), !options.bigEndian);
243
+ (view.getBigInt64(offset + (!options.bigEndian ? 8 : 0), !options.bigEndian) << BigInt(64))
244
+ | view.getBigUint64(offset + (!options.bigEndian ? 0 : 8), !options.bigEndian);
208
245
  continue;
209
246
  }
210
247
  if (fn == 'getUint128') {
211
248
  object[key] =
212
- (view.getBigUint64(iOff + (!options.bigEndian ? 8 : 0), !options.bigEndian) << BigInt(64))
213
- | view.getBigUint64(iOff + (!options.bigEndian ? 0 : 8), !options.bigEndian);
249
+ (view.getBigUint64(offset + (!options.bigEndian ? 8 : 0), !options.bigEndian) << BigInt(64))
250
+ | view.getBigUint64(offset + (!options.bigEndian ? 0 : 8), !options.bigEndian);
214
251
  continue;
215
252
  }
216
253
  if (fn == 'getFloat128') {
217
- object[key] = view.getFloat64(iOff + (!options.bigEndian ? 0 : 8), !options.bigEndian);
254
+ object[key] = view.getFloat64(offset + (!options.bigEndian ? 0 : 8), !options.bigEndian);
218
255
  continue;
219
256
  }
220
- object[key] = view[fn](iOff, !options.bigEndian);
257
+ object[key] = view[fn](offset, !options.bigEndian);
221
258
  }
222
259
  }
223
260
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "utilium",
3
- "version": "1.7.11",
3
+ "version": "1.7.13",
4
4
  "description": "Typescript utilities",
5
5
  "funding": {
6
6
  "type": "individual",
package/src/debugging.ts CHANGED
@@ -92,3 +92,22 @@ export function createLogDecorator(options: CreateLoggerOptions) {
92
92
  } as T;
93
93
  };
94
94
  }
95
+
96
+ /**
97
+ * @internal @hidden
98
+ */
99
+ export let U_DEBUG = 'process' in globalThis && 'env' in globalThis.process && globalThis.process.env.U_DEBUG == 'true';
100
+
101
+ /**
102
+ * @internal @hidden
103
+ */
104
+ export function _setDebug(value: boolean) {
105
+ U_DEBUG = value;
106
+ }
107
+
108
+ /**
109
+ * @internal @hidden
110
+ */
111
+ export function _debugLog(...text: any[]) {
112
+ if (U_DEBUG) console.debug('[U]', ...text);
113
+ }
@@ -14,13 +14,19 @@ declare global {
14
14
  }
15
15
  }
16
16
 
17
+ /**
18
+ * Polyfill Symbol.metadata
19
+ * @see https://github.com/microsoft/TypeScript/issues/53461
20
+ */
21
+ (Symbol as { metadata: symbol }).metadata ??= Symbol.for('Symbol.metadata');
22
+
17
23
  Object.assign(Symbol, {
18
24
  size: Symbol('uSize'),
19
25
  serialize: Symbol('uSerialize'),
20
26
  deserialize: Symbol('uDeserialize'),
21
27
  });
22
28
 
23
- export type TypeLike = Custom | Like | primitive.Valid;
29
+ export type TypeLike = Custom | Like | primitive.Valid | undefined | null;
24
30
 
25
31
  export type Type = Custom | Static | primitive.Typename;
26
32
 
@@ -44,26 +50,43 @@ export interface Options {
44
50
  }
45
51
 
46
52
  export interface Member {
53
+ name: string;
47
54
  type: Type;
48
- offset: number;
55
+ staticOffset: number;
49
56
  length?: number | string;
57
+
58
+ /** A C-style type/name declaration string, used for diagnostics */
59
+ decl: string;
50
60
  }
51
61
 
52
62
  export interface Metadata {
53
63
  options: Partial<Options>;
54
64
  members: Map<string, Member>;
55
- init?: MemberInit[];
56
65
  staticSize: number;
66
+ isDynamic: boolean;
57
67
  }
58
68
 
59
69
  type _DecoratorMetadata<T extends Metadata = Metadata> = DecoratorMetadata & {
60
- struct?: Partial<T>;
70
+ struct?: T;
71
+ structInit?: MemberInit[];
61
72
  };
62
73
 
63
74
  export interface DecoratorContext<T extends Metadata = Metadata> {
64
75
  metadata: _DecoratorMetadata<T>;
65
76
  }
66
77
 
78
+ /**
79
+ * Initializes the struct metadata for a class
80
+ * This also handles copying metadata from parent classes
81
+ */
82
+ export function initMetadata(context: DecoratorContext): MemberInit[] {
83
+ context.metadata ??= {};
84
+
85
+ context.metadata.structInit = [...(context.metadata.structInit ?? [])];
86
+
87
+ return context.metadata.structInit;
88
+ }
89
+
67
90
  export type MemberContext = ClassMemberDecoratorContext & DecoratorContext;
68
91
 
69
92
  export interface Static<T extends Metadata = Metadata> {
@@ -84,18 +107,13 @@ export function isValidMetadata<T extends Metadata = Metadata>(
84
107
  return arg != null && typeof arg == 'object' && 'struct' in arg;
85
108
  }
86
109
 
87
- /**
88
- * Polyfill Symbol.metadata
89
- * @see https://github.com/microsoft/TypeScript/issues/53461
90
- */
91
- (Symbol as { metadata: symbol }).metadata ??= Symbol.for('Symbol.metadata');
92
-
93
110
  /**
94
111
  * Polyfill context.metadata
95
112
  * @see https://github.com/microsoft/TypeScript/issues/53461
113
+ * @internal @hidden
96
114
  */
97
- export function _polyfill_contextMetadata(target: object): void {
98
- if (!Symbol?.metadata || Symbol.metadata in target) return;
115
+ export function _polyfill_metadata(target: object): void {
116
+ if (Symbol.metadata in target) return;
99
117
 
100
118
  Object.defineProperty(target, Symbol.metadata, {
101
119
  enumerable: true,
@@ -105,26 +123,8 @@ export function _polyfill_contextMetadata(target: object): void {
105
123
  });
106
124
  }
107
125
 
108
- /**
109
- * Gets a reference to Symbol.metadata, even on platforms that do not expose it globally (like Node)
110
- */
111
- export function symbol_metadata(arg: ClassLike): typeof Symbol.metadata {
112
- const symbol_metadata =
113
- Symbol.metadata || Object.getOwnPropertySymbols(arg).find(s => s.description == 'Symbol.metadata');
114
- _polyfill_contextMetadata(arg);
115
- if (!symbol_metadata) {
116
- throw new ReferenceError('Could not get a reference to Symbol.metadata');
117
- }
118
-
119
- return symbol_metadata as typeof Symbol.metadata;
120
- }
121
-
122
126
  export function isStatic<T extends Metadata = Metadata>(arg: unknown): arg is Static<T> {
123
- return (
124
- typeof arg == 'function'
125
- && symbol_metadata(arg as ClassLike) in arg
126
- && isValidMetadata(arg[symbol_metadata(arg as ClassLike)])
127
- );
127
+ return typeof arg == 'function' && Symbol.metadata in arg && isValidMetadata(arg[Symbol.metadata]);
128
128
  }
129
129
 
130
130
  export interface Instance<T extends Metadata = Metadata> {
@@ -176,8 +176,10 @@ export function isCustom(arg: unknown): arg is Custom {
176
176
 
177
177
  export type Like<T extends Metadata = Metadata> = InstanceLike<T> | StaticLike<T>;
178
178
 
179
- export type Size<T extends TypeLike> = T extends { readonly [Symbol.size]: infer S }
180
- ? S
181
- : T extends primitive.Valid
182
- ? primitive.Size<T>
183
- : number;
179
+ export type Size<T extends TypeLike> = T extends undefined | null
180
+ ? 0
181
+ : T extends { readonly [Symbol.size]: infer S extends number }
182
+ ? S
183
+ : T extends primitive.Valid
184
+ ? primitive.Size<T>
185
+ : number;
package/src/struct.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { toUint8Array } from './buffer.js';
2
+ import { _debugLog } from './debugging.js';
2
3
  import * as primitive from './internal/primitives.js';
3
4
  import type {
4
5
  DecoratorContext,
@@ -10,47 +11,44 @@ import type {
10
11
  Metadata,
11
12
  Options,
12
13
  Size,
13
- Static,
14
14
  StaticLike,
15
15
  TypeLike,
16
16
  } from './internal/struct.js';
17
- import { checkInstance, checkStruct, isCustom, isStatic, symbol_metadata } from './internal/struct.js';
17
+ import {
18
+ _polyfill_metadata,
19
+ checkInstance,
20
+ checkStruct,
21
+ initMetadata,
22
+ isCustom,
23
+ isInstance,
24
+ isStatic,
25
+ } from './internal/struct.js';
18
26
  import { _throw } from './misc.js';
19
27
  import { capitalize } from './string.js';
20
28
  import type { ClassLike } from './types.js';
21
29
  export * as Struct from './internal/struct.js';
22
30
 
23
31
  /**
24
- * Gets the length of an array in a struct
25
- * @param length The numeric length or the name of the field which has the array length (like __counted_by)
26
- * @param name The name of the array field— only used for errors
32
+ * Gets the size in bytes of a type
27
33
  */
28
- function _memberLength<T extends Metadata>(
29
- struct: Instance<T>,
30
- length: string | number | undefined,
31
- name: string
32
- ): number {
33
- if (length === undefined) return -1;
34
- if (typeof length != 'string')
35
- return Number.isSafeInteger(length) && length >= 0
36
- ? length
37
- : _throw(new Error('Array lengths must be natural numbers'));
38
-
39
- if (!(length in struct)) throw new Error(`Can not use non-existent member to count ${name}: ` + length);
34
+ export function sizeof<T extends TypeLike>(type: T | T[]): Size<T> {
35
+ if (type === undefined || type === null) return 0 as Size<T>;
40
36
 
41
- const n = (struct as any)[length];
37
+ if (Array.isArray(type)) {
38
+ let size = 0;
42
39
 
43
- if (typeof n != 'number') throw new Error(`Can not use "${name}" to count ${length}`);
40
+ for (let i = 0; i < type.length; i++) {
41
+ size += sizeof(type[i]);
42
+ }
44
43
 
45
- return n;
46
- }
44
+ return size as Size<T>;
45
+ }
47
46
 
48
- /**
49
- * Gets the size in bytes of a type
50
- */
51
- export function sizeof<T extends TypeLike>(type: T): Size<T> {
52
- // primitive
47
+ // primitive or character
53
48
  if (typeof type == 'string') {
49
+ // Single character inside string, since sizeof(string) -> sizeof(string[0]) -> here
50
+ if (type.length == 1) return 1 as Size<T>;
51
+
54
52
  primitive.checkValid(type);
55
53
 
56
54
  return (+primitive.normalize(type).match(primitive.regex)![2] / 8) as Size<T>;
@@ -60,17 +58,19 @@ export function sizeof<T extends TypeLike>(type: T): Size<T> {
60
58
 
61
59
  checkStruct(type);
62
60
 
63
- const { struct } = isStatic(type)
64
- ? type[symbol_metadata(type)]
65
- : type.constructor[symbol_metadata(type.constructor)];
61
+ const constructor = isStatic(type) ? type : type.constructor;
62
+ _polyfill_metadata(constructor);
63
+ const { struct } = constructor[Symbol.metadata];
66
64
 
67
65
  if (isStatic(type)) return struct.staticSize as Size<T>;
68
66
 
69
67
  let size = struct.staticSize;
70
68
 
71
- for (const [name, { type: memberType, length: key }] of struct.members) {
72
- if (typeof key != 'string') continue;
73
- size += sizeof(memberType) * _memberLength(type, key, name);
69
+ for (const member of struct.members.values()) {
70
+ if (typeof member.length != 'string') continue;
71
+ for (let i = 0; i < (type as any)[member.length]; i++) {
72
+ size += sizeof((type as any)[member.name][i]);
73
+ }
74
74
  }
75
75
 
76
76
  return size as Size<T>;
@@ -82,12 +82,26 @@ export function sizeof<T extends TypeLike>(type: T): Size<T> {
82
82
  export function offsetof(type: StaticLike | InstanceLike, memberName: string): number {
83
83
  checkStruct(type);
84
84
 
85
- const struct = isStatic(type) ? type : type.constructor;
86
- const metadata = struct[symbol_metadata(struct)].struct;
85
+ const constructor = isStatic(type) ? type : type.constructor;
87
86
 
88
- const member = metadata.members.get(memberName);
89
- if (!member) throw new Error('Struct does not have member: ' + memberName);
90
- return member.offset;
87
+ _polyfill_metadata(constructor);
88
+ const { struct } = constructor[Symbol.metadata];
89
+
90
+ if (isStatic(type) || !struct.isDynamic) {
91
+ return (
92
+ struct.members.get(memberName)?.staticOffset
93
+ ?? _throw(new Error('Struct does not have member: ' + memberName))
94
+ );
95
+ }
96
+
97
+ let offset = 0;
98
+
99
+ for (const member of struct.members.values()) {
100
+ if (member.name == memberName) return offset;
101
+ offset += sizeof((type as any)[member.name]);
102
+ }
103
+
104
+ throw new Error('Struct does not have member: ' + memberName);
91
105
  }
92
106
 
93
107
  /**
@@ -105,26 +119,44 @@ export function struct(options: Partial<Options> = {}) {
105
119
  target: T,
106
120
  context: ClassDecoratorContext & DecoratorContext
107
121
  ): T {
108
- context.metadata ??= {};
109
- context.metadata.struct ??= {};
110
- context.metadata.struct.init ??= [];
111
-
112
- let staticSize = 0;
113
122
  const members = new Map<string, Member>();
114
- for (const { name, type, length } of context.metadata.struct.init) {
123
+
124
+ let staticSize = 0,
125
+ isDynamic = false;
126
+
127
+ for (const { name, type, length } of initMetadata(context)) {
115
128
  if (!primitive.isValid(type) && !isStatic(type)) throw new TypeError('Not a valid type: ' + type);
116
129
 
130
+ if (typeof length == 'string') {
131
+ const countedBy = members.get(length);
132
+
133
+ if (!countedBy) throw new Error(`"${length}" is undefined or declared after "${name}"`);
134
+
135
+ if (!primitive.isType(countedBy.type))
136
+ throw new Error(`"${length}" is not a number and cannot be used to count "${name}"`);
137
+ }
138
+
139
+ let decl = `${typeof type == 'string' ? type : type.name} ${name}`;
140
+
141
+ if (length !== undefined) decl += `[${length}]`;
142
+
117
143
  members.set(name, {
118
- offset: options.isUnion ? 0 : staticSize,
144
+ name,
145
+ staticOffset: options.isUnion ? 0 : staticSize,
119
146
  type: primitive.isValid(type) ? primitive.normalize(type) : type,
120
147
  length,
148
+ decl,
121
149
  });
150
+
122
151
  const memberSize = typeof length == 'string' ? 0 : sizeof(type) * (length || 1);
152
+ isDynamic ||= typeof length == 'string';
123
153
  staticSize = options.isUnion ? Math.max(staticSize, memberSize) : staticSize + memberSize;
124
154
  staticSize = align(staticSize, options.align || 1);
155
+
156
+ _debugLog('define', target.name + '.' + name);
125
157
  }
126
158
 
127
- context.metadata.struct = { options, members, staticSize } satisfies Metadata;
159
+ context.metadata.struct = { options, members, staticSize, isDynamic } satisfies Metadata;
128
160
 
129
161
  return target;
130
162
  };
@@ -143,14 +175,20 @@ export function member(type: primitive.Valid | ClassLike, length?: number | stri
143
175
 
144
176
  if (!name) throw new ReferenceError('Invalid name for struct member');
145
177
 
146
- context.metadata ??= {};
147
- context.metadata.struct ??= {};
148
- context.metadata.struct.init ??= [];
149
- context.metadata.struct.init.push({ name, type, length } satisfies MemberInit);
178
+ initMetadata(context).push({ name, type, length } satisfies MemberInit);
150
179
  return value;
151
180
  };
152
181
  }
153
182
 
183
+ /** Gets the length of a member */
184
+ function _memberLength<T extends Metadata>(instance: Instance<T>, member: Member): number {
185
+ if (member.length === undefined) return -1;
186
+ if (typeof member.length == 'string') return (instance as any)[member.length];
187
+ return Number.isSafeInteger(member.length) && member.length >= 0
188
+ ? member.length
189
+ : _throw(new Error('Array lengths must be natural numbers'));
190
+ }
191
+
154
192
  /**
155
193
  * Serializes a struct into a Uint8Array
156
194
  */
@@ -158,58 +196,69 @@ export function serialize(instance: unknown): Uint8Array {
158
196
  if (isCustom(instance) && typeof instance[Symbol.serialize] == 'function') return instance[Symbol.serialize]!();
159
197
 
160
198
  checkInstance(instance);
161
- const { options, members } = instance.constructor[symbol_metadata(instance.constructor)].struct;
199
+ _polyfill_metadata(instance.constructor);
200
+ const { options, members } = instance.constructor[Symbol.metadata].struct;
162
201
 
163
- const buffer = new Uint8Array(sizeof(instance));
202
+ const size = sizeof(instance);
203
+ const buffer = new Uint8Array(size);
164
204
  const view = new DataView(buffer.buffer);
165
205
 
206
+ _debugLog('serialize', instance.constructor.name);
207
+
208
+ let offset = 0,
209
+ nextOffset = 0;
210
+
166
211
  // for unions we should write members in ascending last modified order, but we don't have that info.
167
- for (const [name, { type, length: rawLength, offset }] of members) {
168
- const length = _memberLength(instance, rawLength, name);
169
- for (let i = 0; i < Math.abs(length); i++) {
170
- const iOff = offset + sizeof(type) * i;
212
+ for (const member of members.values()) {
213
+ const length = _memberLength(instance, member);
214
+
215
+ _debugLog('\t', member.decl);
171
216
 
172
- let value = length != -1 ? instance[name][i] : instance[name];
217
+ for (let i = 0; i < Math.abs(length); i++) {
218
+ let value = length != -1 ? instance[member.name][i] : instance[member.name];
173
219
  if (typeof value == 'string') {
174
220
  value = value.charCodeAt(0);
175
221
  }
176
222
 
177
- if (!primitive.isType(type)) {
178
- buffer.set(value ? serialize(value) : new Uint8Array(sizeof(type)), iOff);
223
+ offset = nextOffset;
224
+ nextOffset += isInstance(value) ? sizeof(value) : sizeof(member.type);
225
+
226
+ if (!primitive.isType(member.type)) {
227
+ buffer.set(value ? serialize(value) : new Uint8Array(sizeof(member.type)), offset);
179
228
  continue;
180
229
  }
181
230
 
182
- const fn = `set${capitalize(type)}` as const;
231
+ const fn = `set${capitalize(member.type)}` as const;
183
232
 
184
233
  if (fn == 'setInt64') {
185
- view.setBigInt64(iOff, BigInt(value), !options.bigEndian);
234
+ view.setBigInt64(offset, BigInt(value), !options.bigEndian);
186
235
  continue;
187
236
  }
188
237
 
189
238
  if (fn == 'setUint64') {
190
- view.setBigUint64(iOff, BigInt(value), !options.bigEndian);
239
+ view.setBigUint64(offset, BigInt(value), !options.bigEndian);
191
240
  continue;
192
241
  }
193
242
 
194
243
  if (fn == 'setInt128') {
195
- view.setBigUint64(iOff + (!options.bigEndian ? 0 : 8), value & primitive.mask64, !options.bigEndian);
196
- view.setBigInt64(iOff + (!options.bigEndian ? 8 : 0), value >> BigInt(64), !options.bigEndian);
244
+ view.setBigUint64(offset + (!options.bigEndian ? 0 : 8), value & primitive.mask64, !options.bigEndian);
245
+ view.setBigInt64(offset + (!options.bigEndian ? 8 : 0), value >> BigInt(64), !options.bigEndian);
197
246
  continue;
198
247
  }
199
248
 
200
249
  if (fn == 'setUint128') {
201
- view.setBigUint64(iOff + (!options.bigEndian ? 0 : 8), value & primitive.mask64, !options.bigEndian);
202
- view.setBigUint64(iOff + (!options.bigEndian ? 8 : 0), value >> BigInt(64), !options.bigEndian);
250
+ view.setBigUint64(offset + (!options.bigEndian ? 0 : 8), value & primitive.mask64, !options.bigEndian);
251
+ view.setBigUint64(offset + (!options.bigEndian ? 8 : 0), value >> BigInt(64), !options.bigEndian);
203
252
  continue;
204
253
  }
205
254
 
206
255
  if (fn == 'setFloat128') {
207
- view.setFloat64(iOff + (!options.bigEndian ? 0 : 8), Number(value), !options.bigEndian);
208
- view.setBigUint64(iOff + (!options.bigEndian ? 8 : 0), BigInt(0), !options.bigEndian);
256
+ view.setFloat64(offset + (!options.bigEndian ? 0 : 8), Number(value), !options.bigEndian);
257
+ view.setBigUint64(offset + (!options.bigEndian ? 8 : 0), BigInt(0), !options.bigEndian);
209
258
  continue;
210
259
  }
211
260
 
212
- view[fn](iOff, Number(value), !options.bigEndian);
261
+ view[fn](offset, Number(value), !options.bigEndian);
213
262
  }
214
263
  }
215
264
 
@@ -226,64 +275,77 @@ export function deserialize(instance: unknown, _buffer: ArrayBufferLike | ArrayB
226
275
  return instance[Symbol.deserialize]!(buffer);
227
276
 
228
277
  checkInstance(instance);
229
- const { options, members } = instance.constructor[symbol_metadata(instance.constructor)].struct;
278
+ _polyfill_metadata(instance.constructor);
279
+ const { options, members } = instance.constructor[Symbol.metadata].struct;
230
280
 
231
281
  const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
232
282
 
233
- for (const [name, { type, offset, length: rawLength }] of members) {
234
- const length = _memberLength(instance, rawLength, name);
283
+ _debugLog('deserialize', instance.constructor.name);
284
+
285
+ let offset = 0,
286
+ nextOffset = 0;
287
+
288
+ for (const member of members.values()) {
289
+ const length = _memberLength(instance, member);
290
+
291
+ _debugLog('\t', member.decl);
292
+
235
293
  for (let i = 0; i < Math.abs(length); i++) {
236
- let object = length != -1 ? instance[name] : instance;
237
- const key = length != -1 ? i : name,
238
- iOff = offset + sizeof(type) * i;
294
+ let object = length != -1 ? instance[member.name] : instance;
295
+ const key = length != -1 ? i : member.name;
239
296
 
240
- if (typeof instance[name] == 'string') {
241
- instance[name] =
242
- instance[name].slice(0, i) + String.fromCharCode(view.getUint8(iOff)) + instance[name].slice(i + 1);
297
+ offset = nextOffset;
298
+ if (!isInstance(object[key])) nextOffset += sizeof(member.type);
299
+
300
+ if (typeof instance[member.name] == 'string') {
301
+ instance[member.name] =
302
+ instance[member.name].slice(0, i)
303
+ + String.fromCharCode(view.getUint8(offset))
304
+ + instance[member.name].slice(i + 1);
243
305
  continue;
244
306
  }
245
307
 
246
- if (!primitive.isType(type)) {
247
- if (object[key] === null || object[key] === undefined) {
248
- continue;
249
- }
250
- deserialize(object[key], new Uint8Array(buffer.subarray(iOff, iOff + sizeof(type))));
308
+ if (!primitive.isType(member.type)) {
309
+ if (object[key] === null || object[key] === undefined) continue;
310
+
311
+ deserialize(object[key], new Uint8Array(buffer.subarray(offset)));
312
+ nextOffset += sizeof(object[key]);
251
313
  continue;
252
314
  }
253
315
 
254
316
  if (length && length != -1) object ||= [];
255
317
 
256
- const fn = `get${capitalize(type)}` as const;
318
+ const fn = `get${capitalize(member.type)}` as const;
257
319
  if (fn == 'getInt64') {
258
- object[key] = view.getBigInt64(iOff, !options.bigEndian);
320
+ object[key] = view.getBigInt64(offset, !options.bigEndian);
259
321
  continue;
260
322
  }
261
323
 
262
324
  if (fn == 'getUint64') {
263
- object[key] = view.getBigUint64(iOff, !options.bigEndian);
325
+ object[key] = view.getBigUint64(offset, !options.bigEndian);
264
326
  continue;
265
327
  }
266
328
 
267
329
  if (fn == 'getInt128') {
268
330
  object[key] =
269
- (view.getBigInt64(iOff + (!options.bigEndian ? 8 : 0), !options.bigEndian) << BigInt(64))
270
- | view.getBigUint64(iOff + (!options.bigEndian ? 0 : 8), !options.bigEndian);
331
+ (view.getBigInt64(offset + (!options.bigEndian ? 8 : 0), !options.bigEndian) << BigInt(64))
332
+ | view.getBigUint64(offset + (!options.bigEndian ? 0 : 8), !options.bigEndian);
271
333
  continue;
272
334
  }
273
335
 
274
336
  if (fn == 'getUint128') {
275
337
  object[key] =
276
- (view.getBigUint64(iOff + (!options.bigEndian ? 8 : 0), !options.bigEndian) << BigInt(64))
277
- | view.getBigUint64(iOff + (!options.bigEndian ? 0 : 8), !options.bigEndian);
338
+ (view.getBigUint64(offset + (!options.bigEndian ? 8 : 0), !options.bigEndian) << BigInt(64))
339
+ | view.getBigUint64(offset + (!options.bigEndian ? 0 : 8), !options.bigEndian);
278
340
  continue;
279
341
  }
280
342
 
281
343
  if (fn == 'getFloat128') {
282
- object[key] = view.getFloat64(iOff + (!options.bigEndian ? 0 : 8), !options.bigEndian);
344
+ object[key] = view.getFloat64(offset + (!options.bigEndian ? 0 : 8), !options.bigEndian);
283
345
  continue;
284
346
  }
285
347
 
286
- object[key] = view[fn](iOff, !options.bigEndian);
348
+ object[key] = view[fn](offset, !options.bigEndian);
287
349
  }
288
350
  }
289
351
  }