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.
- package/dist/debugging.d.ts +12 -0
- package/dist/debugging.js +17 -0
- package/dist/internal/struct.d.ts +17 -11
- package/dist/internal/struct.js +18 -21
- package/dist/struct.d.ts +1 -1
- package/dist/struct.js +120 -83
- package/package.json +1 -1
- package/src/debugging.ts +19 -0
- package/src/internal/struct.ts +38 -36
- package/src/struct.ts +153 -91
package/dist/debugging.d.ts
CHANGED
@@ -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
|
-
|
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?:
|
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
|
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 {};
|
package/dist/internal/struct.js
CHANGED
@@ -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
|
19
|
-
if (
|
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
|
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,
|
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
|
-
|
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
|
39
|
-
|
40
|
-
|
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
|
45
|
-
if (typeof
|
38
|
+
for (const member of struct.members.values()) {
|
39
|
+
if (typeof member.length != 'string')
|
46
40
|
continue;
|
47
|
-
|
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
|
57
|
-
|
58
|
-
const
|
59
|
-
if (!
|
60
|
-
|
61
|
-
|
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
|
-
|
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
|
-
|
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.
|
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
|
-
|
122
|
-
const
|
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
|
126
|
-
const length = _memberLength(instance,
|
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
|
-
|
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
|
-
|
134
|
-
|
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(
|
167
|
+
view.setBigInt64(offset, BigInt(value), !options.bigEndian);
|
140
168
|
continue;
|
141
169
|
}
|
142
170
|
if (fn == 'setUint64') {
|
143
|
-
view.setBigUint64(
|
171
|
+
view.setBigUint64(offset, BigInt(value), !options.bigEndian);
|
144
172
|
continue;
|
145
173
|
}
|
146
174
|
if (fn == 'setInt128') {
|
147
|
-
view.setBigUint64(
|
148
|
-
view.setBigInt64(
|
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(
|
153
|
-
view.setBigUint64(
|
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(
|
158
|
-
view.setBigUint64(
|
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](
|
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
|
-
|
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
|
-
|
177
|
-
|
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
|
181
|
-
|
182
|
-
|
183
|
-
|
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
|
-
|
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(
|
234
|
+
object[key] = view.getBigInt64(offset, !options.bigEndian);
|
198
235
|
continue;
|
199
236
|
}
|
200
237
|
if (fn == 'getUint64') {
|
201
|
-
object[key] = view.getBigUint64(
|
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(
|
207
|
-
| view.getBigUint64(
|
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(
|
213
|
-
| view.getBigUint64(
|
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(
|
254
|
+
object[key] = view.getFloat64(offset + (!options.bigEndian ? 0 : 8), !options.bigEndian);
|
218
255
|
continue;
|
219
256
|
}
|
220
|
-
object[key] = view[fn](
|
257
|
+
object[key] = view[fn](offset, !options.bigEndian);
|
221
258
|
}
|
222
259
|
}
|
223
260
|
}
|
package/package.json
CHANGED
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
|
+
}
|
package/src/internal/struct.ts
CHANGED
@@ -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
|
-
|
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?:
|
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
|
98
|
-
if (
|
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
|
180
|
-
?
|
181
|
-
: T extends
|
182
|
-
?
|
183
|
-
:
|
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 {
|
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
|
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
|
29
|
-
|
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
|
-
|
37
|
+
if (Array.isArray(type)) {
|
38
|
+
let size = 0;
|
42
39
|
|
43
|
-
|
40
|
+
for (let i = 0; i < type.length; i++) {
|
41
|
+
size += sizeof(type[i]);
|
42
|
+
}
|
44
43
|
|
45
|
-
|
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
|
64
|
-
|
65
|
-
|
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
|
72
|
-
if (typeof
|
73
|
-
|
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
|
86
|
-
const metadata = struct[symbol_metadata(struct)].struct;
|
85
|
+
const constructor = isStatic(type) ? type : type.constructor;
|
87
86
|
|
88
|
-
|
89
|
-
|
90
|
-
|
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
|
-
|
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
|
-
|
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.
|
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
|
-
|
199
|
+
_polyfill_metadata(instance.constructor);
|
200
|
+
const { options, members } = instance.constructor[Symbol.metadata].struct;
|
162
201
|
|
163
|
-
const
|
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
|
168
|
-
const length = _memberLength(instance,
|
169
|
-
|
170
|
-
|
212
|
+
for (const member of members.values()) {
|
213
|
+
const length = _memberLength(instance, member);
|
214
|
+
|
215
|
+
_debugLog('\t', member.decl);
|
171
216
|
|
172
|
-
|
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
|
-
|
178
|
-
|
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(
|
234
|
+
view.setBigInt64(offset, BigInt(value), !options.bigEndian);
|
186
235
|
continue;
|
187
236
|
}
|
188
237
|
|
189
238
|
if (fn == 'setUint64') {
|
190
|
-
view.setBigUint64(
|
239
|
+
view.setBigUint64(offset, BigInt(value), !options.bigEndian);
|
191
240
|
continue;
|
192
241
|
}
|
193
242
|
|
194
243
|
if (fn == 'setInt128') {
|
195
|
-
view.setBigUint64(
|
196
|
-
view.setBigInt64(
|
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(
|
202
|
-
view.setBigUint64(
|
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(
|
208
|
-
view.setBigUint64(
|
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](
|
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
|
-
|
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
|
-
|
234
|
-
|
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
|
-
|
241
|
-
|
242
|
-
|
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
|
-
|
249
|
-
|
250
|
-
|
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(
|
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(
|
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(
|
270
|
-
| view.getBigUint64(
|
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(
|
277
|
-
| view.getBigUint64(
|
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(
|
344
|
+
object[key] = view.getFloat64(offset + (!options.bigEndian ? 0 : 8), !options.bigEndian);
|
283
345
|
continue;
|
284
346
|
}
|
285
347
|
|
286
|
-
object[key] = view[fn](
|
348
|
+
object[key] = view[fn](offset, !options.bigEndian);
|
287
349
|
}
|
288
350
|
}
|
289
351
|
}
|