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.
@@ -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 | string;
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 | string;
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 | string): Decorator<V>;
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.length);
104
+ const countedBy = init.members.find(m => m.name == opt.countedBy);
105
105
  if (!countedBy)
106
- throw new Error(`"${opt.length}" is not declared and cannot be used to count "${name}"`);
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.length}" is not a number and cannot be used to count "${name}"`);
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 length == 'string')
139
- return instance[length];
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: rawLength } = member;
146
- const length = _memberLength(instance, rawLength);
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: rawLength } = member;
179
- const length = _memberLength(instance, rawLength);
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' || typeof valueOrLength == 'string'
193
- ? member(type, { length: valueOrLength, typeName })
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "utilium",
3
- "version": "2.0.0-pre.1",
3
+ "version": "2.0.0-pre.2",
4
4
  "description": "Typescript utilities",
5
5
  "funding": {
6
6
  "type": "individual",
@@ -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 | string;
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 | string;
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.length);
149
+ const countedBy = init.members.find(m => m.name == opt.countedBy);
149
150
 
150
- if (!countedBy) throw new Error(`"${opt.length}" is not declared and cannot be used to count "${name}"`);
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.length}" is not a number and cannot be used to count "${name}"`);
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 | string): 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 length == 'string') return instance[length];
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: rawLength } = member;
200
- const length = _memberLength(instance, rawLength);
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: rawLength } = member;
242
- const length = _memberLength(instance, rawLength);
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 | string): Decorator<V>;
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 | string,
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' || typeof valueOrLength == 'string'
276
- ? member<V>(type, { length: valueOrLength, typeName })
277
- : member<V>(type, { typeName })(valueOrLength, context!);
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;