utilium 2.0.0-pre.1 → 2.0.0-pre.2
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/internal/struct.d.ts +2 -1
- package/dist/struct.d.ts +3 -2
- package/dist/struct.js +14 -13
- package/package.json +1 -1
- package/src/internal/struct.ts +2 -1
- package/src/struct.ts +21 -16
@@ -16,7 +16,8 @@ export interface Member {
|
|
16
16
|
offset: number;
|
17
17
|
/** The size of the member, 0 for dynamically sized arrays */
|
18
18
|
size: number;
|
19
|
-
length?: number
|
19
|
+
length?: number;
|
20
|
+
countedBy?: string;
|
20
21
|
/** A C-style type/name declaration string, used for diagnostics */
|
21
22
|
decl: string;
|
22
23
|
/** Whether the member is little endian */
|
package/dist/struct.d.ts
CHANGED
@@ -17,9 +17,10 @@ export declare function align(value: number, alignment: number): number;
|
|
17
17
|
export declare function struct(options?: Partial<Options>): <T extends StaticLike>(target: T, context: ClassDecoratorContext<T> & DecoratorContext) => void;
|
18
18
|
export interface MemberOptions {
|
19
19
|
bigEndian?: boolean;
|
20
|
-
length?: number
|
20
|
+
length?: number;
|
21
21
|
align?: number;
|
22
22
|
typeName?: string;
|
23
|
+
countedBy?: string;
|
23
24
|
}
|
24
25
|
/**
|
25
26
|
* Decorates a class member to be serialized
|
@@ -30,7 +31,7 @@ type Result<V> = ClassAccessorDecoratorResult<any, V>;
|
|
30
31
|
type Context<V> = ClassAccessorDecoratorContext<any, V> & DecoratorContext;
|
31
32
|
type Decorator<V> = (value: Target<V>, context: Context<V>) => Result<V>;
|
32
33
|
declare function _member<T extends primitive.Valid>(typeName: T): {
|
33
|
-
<V>(length: number
|
34
|
+
<V>(length: number, options?: Omit<MemberOptions, "length">): Decorator<V>;
|
34
35
|
<V>(value: Target<V>, context: Context<V>): Result<V>;
|
35
36
|
};
|
36
37
|
/**
|
package/dist/struct.js
CHANGED
@@ -101,11 +101,11 @@ export function member(type, opt = {}) {
|
|
101
101
|
if (!primitive.isType(type) && !isStatic(type))
|
102
102
|
throw new TypeError('Not a valid type: ' + type.name);
|
103
103
|
if (typeof opt.length == 'string') {
|
104
|
-
const countedBy = init.members.find(m => m.name == opt.
|
104
|
+
const countedBy = init.members.find(m => m.name == opt.countedBy);
|
105
105
|
if (!countedBy)
|
106
|
-
throw new Error(`"${opt.
|
106
|
+
throw new Error(`"${opt.countedBy}" is not declared and cannot be used to count "${name}"`);
|
107
107
|
if (!primitive.isType(countedBy.type))
|
108
|
-
throw new Error(`"${opt.
|
108
|
+
throw new Error(`"${opt.countedBy}" is not a number and cannot be used to count "${name}"`);
|
109
109
|
init.isDynamic = true;
|
110
110
|
}
|
111
111
|
const size = align(sizeof(type) * (typeof opt.length == 'string' ? 0 : (opt.length ?? 1)), opt.align ?? sizeof(type));
|
@@ -114,6 +114,7 @@ export function member(type, opt = {}) {
|
|
114
114
|
offset: init.size,
|
115
115
|
type,
|
116
116
|
length: opt.length,
|
117
|
+
countedBy: opt.countedBy,
|
117
118
|
size,
|
118
119
|
decl: `${opt.typeName ?? type.name} ${name}${opt.length !== undefined ? `[${JSON.stringify(opt.length)}]` : ''}`,
|
119
120
|
littleEndian: !opt.bigEndian,
|
@@ -132,18 +133,18 @@ export function member(type, opt = {}) {
|
|
132
133
|
};
|
133
134
|
}
|
134
135
|
/** Gets the length of a member */
|
135
|
-
function _memberLength(instance, length) {
|
136
|
+
function _memberLength(instance, length, countedBy) {
|
136
137
|
if (length === undefined)
|
137
138
|
return -1;
|
138
|
-
if (typeof
|
139
|
-
|
139
|
+
if (typeof countedBy == 'string')
|
140
|
+
length = Math.min(length, instance[countedBy]);
|
140
141
|
return Number.isSafeInteger(length) && length >= 0
|
141
142
|
? length
|
142
143
|
: _throw(new Error('Array lengths must be natural numbers'));
|
143
144
|
}
|
144
145
|
function _set(instance, member, value, index) {
|
145
|
-
const { name, type, length:
|
146
|
-
const length = _memberLength(instance,
|
146
|
+
const { name, type, length: maxLength, countedBy } = member;
|
147
|
+
const length = _memberLength(instance, maxLength, countedBy);
|
147
148
|
if (!primitive.isType(type)) {
|
148
149
|
if (!isInstance(value))
|
149
150
|
return _debugLog(`Tried to set "${name}" to a non-instance value`);
|
@@ -175,8 +176,8 @@ function _set(instance, member, value, index) {
|
|
175
176
|
type.set(view, member.offset + (index ?? 0) * type.size, member.littleEndian, value);
|
176
177
|
}
|
177
178
|
function _get(instance, member, index) {
|
178
|
-
const { type, length:
|
179
|
-
const length = _memberLength(instance,
|
179
|
+
const { type, length: maxLength, countedBy } = member;
|
180
|
+
const length = _memberLength(instance, maxLength, countedBy);
|
180
181
|
if (length > 0 && typeof index != 'number') {
|
181
182
|
return new (primitive.isType(type) ? type.array : BufferViewArray(type, sizeof(type)))(instance.buffer, instance.byteOffset + member.offset, length * sizeof(type));
|
182
183
|
}
|
@@ -189,9 +190,9 @@ function _get(instance, member, index) {
|
|
189
190
|
function _member(typeName) {
|
190
191
|
const type = primitive.types[primitive.normalize(typeName)];
|
191
192
|
function _structMemberDecorator(valueOrLength, context) {
|
192
|
-
return typeof valueOrLength == 'number'
|
193
|
-
? member(type, { length: valueOrLength,
|
194
|
-
: member(type, { typeName })(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'));
|
195
196
|
}
|
196
197
|
return _structMemberDecorator;
|
197
198
|
}
|
package/package.json
CHANGED
package/src/internal/struct.ts
CHANGED
@@ -27,7 +27,8 @@ export interface Member {
|
|
27
27
|
|
28
28
|
/** The size of the member, 0 for dynamically sized arrays */
|
29
29
|
size: number;
|
30
|
-
length?: number
|
30
|
+
length?: number;
|
31
|
+
countedBy?: string;
|
31
32
|
|
32
33
|
/** A C-style type/name declaration string, used for diagnostics */
|
33
34
|
decl: string;
|
package/src/struct.ts
CHANGED
@@ -118,9 +118,10 @@ export function struct(options: Partial<Options> = {}) {
|
|
118
118
|
|
119
119
|
export interface MemberOptions {
|
120
120
|
bigEndian?: boolean;
|
121
|
-
length?: number
|
121
|
+
length?: number;
|
122
122
|
align?: number;
|
123
123
|
typeName?: string;
|
124
|
+
countedBy?: string;
|
124
125
|
}
|
125
126
|
|
126
127
|
/**
|
@@ -145,12 +146,12 @@ export function member<V>(type: primitive.Type | StaticLike, opt: MemberOptions
|
|
145
146
|
if (!primitive.isType(type) && !isStatic(type)) throw new TypeError('Not a valid type: ' + type.name);
|
146
147
|
|
147
148
|
if (typeof opt.length == 'string') {
|
148
|
-
const countedBy = init.members.find(m => m.name == opt.
|
149
|
+
const countedBy = init.members.find(m => m.name == opt.countedBy);
|
149
150
|
|
150
|
-
if (!countedBy) throw new Error(`"${opt.
|
151
|
+
if (!countedBy) throw new Error(`"${opt.countedBy}" is not declared and cannot be used to count "${name}"`);
|
151
152
|
|
152
153
|
if (!primitive.isType(countedBy.type))
|
153
|
-
throw new Error(`"${opt.
|
154
|
+
throw new Error(`"${opt.countedBy}" is not a number and cannot be used to count "${name}"`);
|
154
155
|
|
155
156
|
init.isDynamic = true;
|
156
157
|
}
|
@@ -165,6 +166,7 @@ export function member<V>(type: primitive.Type | StaticLike, opt: MemberOptions
|
|
165
166
|
offset: init.size,
|
166
167
|
type,
|
167
168
|
length: opt.length,
|
169
|
+
countedBy: opt.countedBy,
|
168
170
|
size,
|
169
171
|
decl: `${opt.typeName ?? type.name} ${name}${opt.length !== undefined ? `[${JSON.stringify(opt.length)}]` : ''}`,
|
170
172
|
littleEndian: !opt.bigEndian,
|
@@ -187,17 +189,17 @@ export function member<V>(type: primitive.Type | StaticLike, opt: MemberOptions
|
|
187
189
|
}
|
188
190
|
|
189
191
|
/** Gets the length of a member */
|
190
|
-
function _memberLength<T extends Metadata>(instance: Instance<T>, length?: number
|
192
|
+
function _memberLength<T extends Metadata>(instance: Instance<T>, length?: number, countedBy?: string): number {
|
191
193
|
if (length === undefined) return -1;
|
192
|
-
if (typeof
|
194
|
+
if (typeof countedBy == 'string') length = Math.min(length, instance[countedBy]);
|
193
195
|
return Number.isSafeInteger(length) && length >= 0
|
194
196
|
? length
|
195
197
|
: _throw(new Error('Array lengths must be natural numbers'));
|
196
198
|
}
|
197
199
|
|
198
200
|
function _set(instance: Instance, member: Member, value: any, index?: number) {
|
199
|
-
const { name, type, length:
|
200
|
-
const length = _memberLength(instance,
|
201
|
+
const { name, type, length: maxLength, countedBy } = member;
|
202
|
+
const length = _memberLength(instance, maxLength, countedBy);
|
201
203
|
|
202
204
|
if (!primitive.isType(type)) {
|
203
205
|
if (!isInstance(value)) return _debugLog(`Tried to set "${name}" to a non-instance value`);
|
@@ -238,8 +240,8 @@ function _set(instance: Instance, member: Member, value: any, index?: number) {
|
|
238
240
|
}
|
239
241
|
|
240
242
|
function _get(instance: Instance, member: Member, index?: number) {
|
241
|
-
const { type, length:
|
242
|
-
const length = _memberLength(instance,
|
243
|
+
const { type, length: maxLength, countedBy } = member;
|
244
|
+
const length = _memberLength(instance, maxLength, countedBy);
|
243
245
|
|
244
246
|
if (length > 0 && typeof index != 'number') {
|
245
247
|
return new (primitive.isType(type) ? type.array : BufferViewArray(type, sizeof(type)))(
|
@@ -266,15 +268,18 @@ type Decorator<V> = (value: Target<V>, context: Context<V>) => Result<V>;
|
|
266
268
|
function _member<T extends primitive.Valid>(typeName: T) {
|
267
269
|
const type = primitive.types[primitive.normalize(typeName)];
|
268
270
|
|
269
|
-
function _structMemberDecorator<V>(length: number
|
271
|
+
function _structMemberDecorator<V>(length: number, options?: Omit<MemberOptions, 'length'>): Decorator<V>;
|
270
272
|
function _structMemberDecorator<V>(value: Target<V>, context: Context<V>): Result<V>;
|
271
273
|
function _structMemberDecorator<V>(
|
272
|
-
valueOrLength: Target<V> | number
|
273
|
-
context?: Context<V>
|
274
|
+
valueOrLength: Target<V> | number,
|
275
|
+
context?: Context<V> | Omit<MemberOptions, 'length'>
|
274
276
|
): Decorator<V> | Result<V> {
|
275
|
-
return typeof valueOrLength == 'number'
|
276
|
-
? member<V>(type, { length: valueOrLength,
|
277
|
-
: member<V>(type, { typeName })(
|
277
|
+
return typeof valueOrLength == 'number'
|
278
|
+
? member<V>(type, { typeName, length: valueOrLength, ...context })
|
279
|
+
: member<V>(type, { typeName })(
|
280
|
+
valueOrLength,
|
281
|
+
context && 'name' in context ? context : _throw('Invalid decorator context object')
|
282
|
+
);
|
278
283
|
}
|
279
284
|
|
280
285
|
return _structMemberDecorator;
|