utilium 0.2.1 → 0.3.1

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/index.d.ts CHANGED
@@ -2,4 +2,6 @@ export * from './misc.js';
2
2
  export * from './numbers.js';
3
3
  export * from './objects.js';
4
4
  export * from './random.js';
5
+ export * from './string.js';
6
+ export * from './struct.js';
5
7
  export * from './types.js';
package/dist/index.js CHANGED
@@ -2,4 +2,6 @@ export * from './misc.js';
2
2
  export * from './numbers.js';
3
3
  export * from './objects.js';
4
4
  export * from './random.js';
5
+ export * from './string.js';
6
+ export * from './struct.js';
5
7
  export * from './types.js';
package/dist/objects.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- /// <reference types="node" />
1
+ /// <reference types="node" resolution-mode="require"/>
2
2
  import type * as FS from 'fs';
3
3
  export declare function filterObject<O extends object, R extends object>(object: O, predicate: (key: keyof O, value: O[keyof O]) => boolean): R;
4
4
  export declare function pick<T extends object, K extends keyof T>(object: T, ...keys: readonly K[]): Pick<T, K>;
@@ -0,0 +1,2 @@
1
+ export declare function capitalize<T extends string>(value: T): Capitalize<T>;
2
+ export declare function uncapitalize<T extends string>(value: T): Uncapitalize<T>;
package/dist/string.js ADDED
@@ -0,0 +1,6 @@
1
+ export function capitalize(value) {
2
+ return (value.at(0).toUpperCase() + value.slice(1));
3
+ }
4
+ export function uncapitalize(value) {
5
+ return (value.at(0).toLowerCase() + value.slice(1));
6
+ }
@@ -0,0 +1,125 @@
1
+ import { ClassLike } from './types.js';
2
+ export type PrimitiveType = `${'int' | 'uint'}${8 | 16 | 32 | 64}` | `float${32 | 64}`;
3
+ export type ValidPrimitiveType = PrimitiveType | Capitalize<PrimitiveType> | 'char';
4
+ /**
5
+ * Options for struct initialization
6
+ */
7
+ export interface StructOptions {
8
+ align: number;
9
+ bigEndian: boolean;
10
+ }
11
+ /**
12
+ * Gets the size in bytes of a type
13
+ */
14
+ export declare function sizeof(type: ValidPrimitiveType | ClassLike | object): number;
15
+ /**
16
+ * Aligns a number
17
+ */
18
+ export declare function align(value: number, alignment: number): number;
19
+ /**
20
+ * Decorates a class as a struct
21
+ */
22
+ export declare function struct(options?: Partial<StructOptions>): (target: ClassLike, _?: ClassDecoratorContext) => void;
23
+ /**
24
+ * Decorates a class member to be serialized
25
+ */
26
+ export declare function member(type: ValidPrimitiveType | ClassLike, length?: number): (target: object, context?: ClassMemberDecoratorContext | string | symbol) => void;
27
+ /**
28
+ * Serializes a struct into a Uint8Array
29
+ */
30
+ export declare function serialize(instance: unknown): Uint8Array;
31
+ /**
32
+ * Deserializes a struct from a Uint8Array
33
+ */
34
+ export declare function deserialize(instance: unknown, _buffer: ArrayBuffer | ArrayBufferView): void;
35
+ /**
36
+ * Shortcut types
37
+ *
38
+ * Instead of writing `@member(type)` you can write `@types.type`, or `@types.type(length)` for arrays
39
+ */
40
+ export declare const types: {
41
+ int8: {
42
+ (length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
43
+ (target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
44
+ };
45
+ int16: {
46
+ (length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
47
+ (target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
48
+ };
49
+ int32: {
50
+ (length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
51
+ (target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
52
+ };
53
+ int64: {
54
+ (length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
55
+ (target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
56
+ };
57
+ uint8: {
58
+ (length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
59
+ (target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
60
+ };
61
+ uint16: {
62
+ (length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
63
+ (target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
64
+ };
65
+ uint32: {
66
+ (length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
67
+ (target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
68
+ };
69
+ uint64: {
70
+ (length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
71
+ (target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
72
+ };
73
+ float32: {
74
+ (length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
75
+ (target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
76
+ };
77
+ float64: {
78
+ (length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
79
+ (target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
80
+ };
81
+ Int8: {
82
+ (length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
83
+ (target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
84
+ };
85
+ Int16: {
86
+ (length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
87
+ (target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
88
+ };
89
+ Int32: {
90
+ (length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
91
+ (target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
92
+ };
93
+ Int64: {
94
+ (length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
95
+ (target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
96
+ };
97
+ Uint8: {
98
+ (length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
99
+ (target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
100
+ };
101
+ Uint16: {
102
+ (length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
103
+ (target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
104
+ };
105
+ Uint32: {
106
+ (length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
107
+ (target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
108
+ };
109
+ Uint64: {
110
+ (length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
111
+ (target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
112
+ };
113
+ Float32: {
114
+ (length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
115
+ (target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
116
+ };
117
+ Float64: {
118
+ (length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
119
+ (target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
120
+ };
121
+ char: {
122
+ (length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
123
+ (target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
124
+ };
125
+ };
package/dist/struct.js ADDED
@@ -0,0 +1,180 @@
1
+ import { capitalize } from './string.js';
2
+ const primitiveTypes = ['int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64', 'float32', 'float64'];
3
+ const validPrimitiveTypes = [...primitiveTypes, ...primitiveTypes.map(t => capitalize(t)), 'char'];
4
+ const numberRegex = /^(u?int)(8|16|32|64)|(float)(32|64)$/i;
5
+ function normalizePrimitive(type) {
6
+ return type == 'char' ? 'uint8' : type.toLowerCase();
7
+ }
8
+ function isPrimitiveType(type) {
9
+ return numberRegex.test(type.toString());
10
+ }
11
+ function isValidPrimitive(type) {
12
+ return type == 'char' || numberRegex.test(type.toString().toLowerCase());
13
+ }
14
+ const init = Symbol('struct_init');
15
+ const metadata = Symbol('struct');
16
+ function isStatic(arg) {
17
+ return typeof arg == 'function' && metadata in arg;
18
+ }
19
+ function isInstance(arg) {
20
+ return metadata in (arg?.constructor || {});
21
+ }
22
+ function isStruct(arg) {
23
+ return isInstance(arg) || isStatic(arg);
24
+ }
25
+ /**
26
+ * Gets the size in bytes of a type
27
+ */
28
+ export function sizeof(type) {
29
+ // primitive
30
+ if (typeof type == 'string') {
31
+ if (!isValidPrimitive(type)) {
32
+ throw new TypeError('Invalid primitive type: ' + type);
33
+ }
34
+ return +normalizePrimitive(type).match(numberRegex)[2] / 8;
35
+ }
36
+ if (!isStruct(type)) {
37
+ throw new TypeError('Not a struct');
38
+ }
39
+ const meta = metadata in type ? type[metadata] : type.constructor[metadata];
40
+ return meta.size;
41
+ }
42
+ /**
43
+ * Aligns a number
44
+ */
45
+ export function align(value, alignment) {
46
+ return Math.ceil(value / alignment) * alignment;
47
+ }
48
+ /**
49
+ * Decorates a class as a struct
50
+ */
51
+ export function struct(options = {}) {
52
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
53
+ return function (target, _) {
54
+ target[init] || (target[init] = []);
55
+ let size = 0;
56
+ const members = new Map();
57
+ for (const { name, type, length } of target[init]) {
58
+ if (!isValidPrimitive(type) && !isStatic(type)) {
59
+ throw new TypeError('Not a valid type: ' + type);
60
+ }
61
+ members.set(name, {
62
+ offset: size,
63
+ type: isValidPrimitive(type) ? normalizePrimitive(type) : type,
64
+ length,
65
+ });
66
+ size += sizeof(type) * (length || 1);
67
+ size = align(size, options.align || 1);
68
+ }
69
+ target[metadata] = { options, members, size };
70
+ delete target[init];
71
+ };
72
+ }
73
+ /**
74
+ * Decorates a class member to be serialized
75
+ */
76
+ export function member(type, length) {
77
+ return function (target, context) {
78
+ var _a;
79
+ let name = typeof context == 'object' ? context.name : context;
80
+ if (typeof name == 'symbol') {
81
+ console.warn('Symbol used for struct member name will be coerced to string: ' + name.toString());
82
+ name = name.toString();
83
+ }
84
+ (_a = target.constructor)[init] || (_a[init] = []);
85
+ target.constructor[init].push({ name, type, length });
86
+ };
87
+ }
88
+ /**
89
+ * Serializes a struct into a Uint8Array
90
+ */
91
+ export function serialize(instance) {
92
+ if (!isInstance(instance)) {
93
+ throw new TypeError('Can not serialize, not a struct instance');
94
+ }
95
+ const { options, members } = instance.constructor[metadata];
96
+ const buffer = new Uint8Array(sizeof(instance));
97
+ const view = new DataView(buffer.buffer);
98
+ for (const [name, { type, length, offset }] of members) {
99
+ for (let i = 0; i < (length || 1); i++) {
100
+ const iOff = offset + sizeof(type) * i;
101
+ let value = length > 0 ? instance[name][i] : instance[name];
102
+ if (typeof value == 'string') {
103
+ value = value.charCodeAt(0);
104
+ }
105
+ if (!isPrimitiveType(type)) {
106
+ buffer.set(value ? serialize(value) : new Uint8Array(sizeof(type)), iOff);
107
+ continue;
108
+ }
109
+ const Type = capitalize(type);
110
+ const fn = ('set' + Type);
111
+ if (fn == 'setInt64') {
112
+ view.setBigInt64(iOff, BigInt(value), !options.bigEndian);
113
+ continue;
114
+ }
115
+ if (fn == 'setUint64') {
116
+ view.setBigUint64(iOff, BigInt(value), !options.bigEndian);
117
+ continue;
118
+ }
119
+ view[fn](iOff, Number(value), !options.bigEndian);
120
+ }
121
+ }
122
+ return buffer;
123
+ }
124
+ /**
125
+ * Deserializes a struct from a Uint8Array
126
+ */
127
+ export function deserialize(instance, _buffer) {
128
+ if (!isInstance(instance)) {
129
+ throw new TypeError('Can not deserialize, not a struct instance');
130
+ }
131
+ const { options, members } = instance.constructor[metadata];
132
+ const buffer = new Uint8Array('buffer' in _buffer ? _buffer.buffer : _buffer);
133
+ const view = new DataView(buffer.buffer);
134
+ for (const [name, { type, offset, length }] of members) {
135
+ for (let i = 0; i < (length || 1); i++) {
136
+ let object = length > 0 ? instance[name] : instance;
137
+ const key = length > 0 ? i : name, iOff = offset + sizeof(type) * i;
138
+ if (typeof instance[name] == 'string') {
139
+ instance[name] = instance[name].slice(0, i) + String.fromCharCode(view.getUint8(iOff)) + instance[name].slice(i + 1);
140
+ continue;
141
+ }
142
+ if (!isPrimitiveType(type)) {
143
+ if (object[key] === null || object[key] === undefined) {
144
+ continue;
145
+ }
146
+ deserialize(object[key], new Uint8Array(buffer.slice(iOff, sizeof(type))));
147
+ continue;
148
+ }
149
+ if (length > 0) {
150
+ object || (object = []);
151
+ }
152
+ const Type = capitalize(type);
153
+ const fn = ('get' + Type);
154
+ if (fn == 'getInt64') {
155
+ object[key] = view.getBigInt64(iOff, !options.bigEndian);
156
+ continue;
157
+ }
158
+ if (fn == 'getUint64') {
159
+ object[key] = view.getBigUint64(iOff, !options.bigEndian);
160
+ continue;
161
+ }
162
+ object[key] = view[fn](iOff, !options.bigEndian);
163
+ }
164
+ }
165
+ }
166
+ function _member(type) {
167
+ function _(targetOrLength, context) {
168
+ if (typeof targetOrLength == 'number') {
169
+ return member(type, targetOrLength);
170
+ }
171
+ return member(type)(targetOrLength, context);
172
+ }
173
+ return _;
174
+ }
175
+ /**
176
+ * Shortcut types
177
+ *
178
+ * Instead of writing `@member(type)` you can write `@types.type`, or `@types.type(length)` for arrays
179
+ */
180
+ export const types = Object.fromEntries(validPrimitiveTypes.map(t => [t, _member(t)]));
package/dist/types.d.ts CHANGED
@@ -170,4 +170,9 @@ export type Tuple<T, N extends number> = _Tuple<T, N>;
170
170
  * Makes all members of the tuple T optional
171
171
  */
172
172
  export type OptionalTuple<T extends unknown[]> = T extends [infer Head, ...infer Tail] ? [Head?, ...OptionalTuple<Tail>] : T;
173
+ /**
174
+ * Keys of a Map
175
+ */
176
+ export type MapKeys<T> = T extends Map<infer K, any> ? K : never;
177
+ export type ClassLike<Instance = unknown> = abstract new (...args: unknown[]) => Instance;
173
178
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "utilium",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "description": "Typescript utilies",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/index.ts CHANGED
@@ -2,4 +2,6 @@ export * from './misc.js';
2
2
  export * from './numbers.js';
3
3
  export * from './objects.js';
4
4
  export * from './random.js';
5
+ export * from './string.js';
6
+ export * from './struct.js';
5
7
  export * from './types.js';
package/src/string.ts ADDED
@@ -0,0 +1,7 @@
1
+ export function capitalize<T extends string>(value: T): Capitalize<T> {
2
+ return <Capitalize<T>>(value.at(0).toUpperCase() + value.slice(1));
3
+ }
4
+
5
+ export function uncapitalize<T extends string>(value: T): Uncapitalize<T> {
6
+ return <Uncapitalize<T>>(value.at(0).toLowerCase() + value.slice(1));
7
+ }
package/src/struct.ts ADDED
@@ -0,0 +1,264 @@
1
+ import { capitalize } from './string.js';
2
+ import { ClassLike } from './types.js';
3
+
4
+ export type PrimitiveType = `${'int' | 'uint'}${8 | 16 | 32 | 64}` | `float${32 | 64}`;
5
+ export type ValidPrimitiveType = PrimitiveType | Capitalize<PrimitiveType> | 'char';
6
+
7
+ const primitiveTypes = ['int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64', 'float32', 'float64'] satisfies PrimitiveType[];
8
+
9
+ const validPrimitiveTypes = [...primitiveTypes, ...primitiveTypes.map(t => capitalize(t)), 'char'] satisfies ValidPrimitiveType[];
10
+
11
+ const numberRegex = /^(u?int)(8|16|32|64)|(float)(32|64)$/i;
12
+
13
+ function normalizePrimitive(type: ValidPrimitiveType): PrimitiveType {
14
+ return type == 'char' ? 'uint8' : <PrimitiveType>type.toLowerCase();
15
+ }
16
+
17
+ function isPrimitiveType(type: unknown): type is PrimitiveType {
18
+ return numberRegex.test(type.toString());
19
+ }
20
+
21
+ function isValidPrimitive(type: unknown): type is ValidPrimitiveType {
22
+ return type == 'char' || numberRegex.test(type.toString().toLowerCase());
23
+ }
24
+
25
+ interface MemberInit {
26
+ name: string;
27
+ type: string | ClassLike;
28
+ length?: number;
29
+ }
30
+
31
+ const init = Symbol('struct_init');
32
+
33
+ /**
34
+ * Options for struct initialization
35
+ */
36
+ export interface StructOptions {
37
+ align: number;
38
+ bigEndian: boolean;
39
+ }
40
+
41
+ interface Member {
42
+ type: PrimitiveType | Static;
43
+ offset: number;
44
+ length?: number;
45
+ }
46
+
47
+ interface Metadata {
48
+ options: Partial<StructOptions>;
49
+ members: Map<string, Member>;
50
+ size: number;
51
+ }
52
+
53
+ const metadata = Symbol('struct');
54
+
55
+ interface Static {
56
+ [metadata]?: Metadata;
57
+ new (): Instance;
58
+ prototype: Instance;
59
+ }
60
+
61
+ function isStatic(arg: unknown): arg is Static {
62
+ return typeof arg == 'function' && metadata in arg;
63
+ }
64
+
65
+ interface Instance {
66
+ constructor: Static;
67
+ }
68
+
69
+ function isInstance(arg: unknown): arg is Instance {
70
+ return metadata in (arg?.constructor || {});
71
+ }
72
+
73
+ function isStruct(arg: unknown): arg is Instance | Static {
74
+ return isInstance(arg) || isStatic(arg);
75
+ }
76
+
77
+ /**
78
+ * Gets the size in bytes of a type
79
+ */
80
+ export function sizeof(type: ValidPrimitiveType | ClassLike | object): number {
81
+ // primitive
82
+ if (typeof type == 'string') {
83
+ if (!isValidPrimitive(type)) {
84
+ throw new TypeError('Invalid primitive type: ' + type);
85
+ }
86
+
87
+ return +normalizePrimitive(type).match(numberRegex)[2] / 8;
88
+ }
89
+
90
+ if (!isStruct(type)) {
91
+ throw new TypeError('Not a struct');
92
+ }
93
+
94
+ const meta: Metadata = metadata in type ? type[metadata] : type.constructor[metadata];
95
+ return meta.size;
96
+ }
97
+
98
+ /**
99
+ * Aligns a number
100
+ */
101
+ export function align(value: number, alignment: number): number {
102
+ return Math.ceil(value / alignment) * alignment;
103
+ }
104
+
105
+ /**
106
+ * Decorates a class as a struct
107
+ */
108
+ export function struct(options: Partial<StructOptions> = {}) {
109
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
110
+ return function (target: ClassLike, _?: ClassDecoratorContext) {
111
+ target[init] ||= [];
112
+ let size = 0;
113
+ const members = new Map();
114
+ for (const { name, type, length } of target[init] as MemberInit[]) {
115
+ if (!isValidPrimitive(type) && !isStatic(type)) {
116
+ throw new TypeError('Not a valid type: ' + type);
117
+ }
118
+ members.set(name, {
119
+ offset: size,
120
+ type: isValidPrimitive(type) ? normalizePrimitive(type) : type,
121
+ length,
122
+ });
123
+ size += sizeof(type) * (length || 1);
124
+ size = align(size, options.align || 1);
125
+ }
126
+
127
+ target[metadata] = { options, members, size } satisfies Metadata;
128
+ delete target[init];
129
+ };
130
+ }
131
+
132
+ /**
133
+ * Decorates a class member to be serialized
134
+ */
135
+ export function member(type: ValidPrimitiveType | ClassLike, length?: number) {
136
+ return function (target: object, context?: ClassMemberDecoratorContext | string | symbol) {
137
+ let name = typeof context == 'object' ? context.name : context;
138
+ if (typeof name == 'symbol') {
139
+ console.warn('Symbol used for struct member name will be coerced to string: ' + name.toString());
140
+ name = name.toString();
141
+ }
142
+
143
+ target.constructor[init] ||= [];
144
+ target.constructor[init].push({ name, type, length } satisfies MemberInit);
145
+ };
146
+ }
147
+
148
+ /**
149
+ * Serializes a struct into a Uint8Array
150
+ */
151
+ export function serialize(instance: unknown): Uint8Array {
152
+ if (!isInstance(instance)) {
153
+ throw new TypeError('Can not serialize, not a struct instance');
154
+ }
155
+ const { options, members } = instance.constructor[metadata];
156
+
157
+ const buffer = new Uint8Array(sizeof(instance));
158
+ const view = new DataView(buffer.buffer);
159
+
160
+ for (const [name, { type, length, offset }] of members) {
161
+ for (let i = 0; i < (length || 1); i++) {
162
+ const iOff = offset + sizeof(type) * i;
163
+
164
+ let value = length > 0 ? instance[name][i] : instance[name];
165
+ if (typeof value == 'string') {
166
+ value = value.charCodeAt(0);
167
+ }
168
+
169
+ if (!isPrimitiveType(type)) {
170
+ buffer.set(value ? serialize(value) : new Uint8Array(sizeof(type)), iOff);
171
+ continue;
172
+ }
173
+
174
+ const Type = capitalize(type);
175
+ const fn = <`set${typeof Type}`>('set' + Type);
176
+ if (fn == 'setInt64') {
177
+ view.setBigInt64(iOff, BigInt(value), !options.bigEndian);
178
+ continue;
179
+ }
180
+
181
+ if (fn == 'setUint64') {
182
+ view.setBigUint64(iOff, BigInt(value), !options.bigEndian);
183
+ continue;
184
+ }
185
+
186
+ view[fn](iOff, Number(value), !options.bigEndian);
187
+ }
188
+ }
189
+
190
+ return buffer;
191
+ }
192
+
193
+ /**
194
+ * Deserializes a struct from a Uint8Array
195
+ */
196
+ export function deserialize(instance: unknown, _buffer: ArrayBuffer | ArrayBufferView) {
197
+ if (!isInstance(instance)) {
198
+ throw new TypeError('Can not deserialize, not a struct instance');
199
+ }
200
+ const { options, members } = instance.constructor[metadata];
201
+
202
+ const buffer = new Uint8Array('buffer' in _buffer ? _buffer.buffer : _buffer);
203
+
204
+ const view = new DataView(buffer.buffer);
205
+
206
+ for (const [name, { type, offset, length }] of members) {
207
+ for (let i = 0; i < (length || 1); i++) {
208
+ let object = length > 0 ? instance[name] : instance;
209
+ const key = length > 0 ? i : name,
210
+ iOff = offset + sizeof(type) * i;
211
+
212
+ if (typeof instance[name] == 'string') {
213
+ instance[name] = instance[name].slice(0, i) + String.fromCharCode(view.getUint8(iOff)) + instance[name].slice(i + 1);
214
+ continue;
215
+ }
216
+
217
+ if (!isPrimitiveType(type)) {
218
+ if (object[key] === null || object[key] === undefined) {
219
+ continue;
220
+ }
221
+ deserialize(object[key], new Uint8Array(buffer.slice(iOff, sizeof(type))));
222
+ continue;
223
+ }
224
+
225
+ if (length > 0) {
226
+ object ||= [];
227
+ }
228
+
229
+ const Type = capitalize(type);
230
+ const fn = <`get${typeof Type}`>('get' + Type);
231
+ if (fn == 'getInt64') {
232
+ object[key] = view.getBigInt64(iOff, !options.bigEndian);
233
+ continue;
234
+ }
235
+
236
+ if (fn == 'getUint64') {
237
+ object[key] = view.getBigUint64(iOff, !options.bigEndian);
238
+ continue;
239
+ }
240
+
241
+ object[key] = view[fn](iOff, !options.bigEndian);
242
+ }
243
+ }
244
+ }
245
+
246
+ function _member<T extends ValidPrimitiveType>(type: T) {
247
+ function _(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
248
+ function _(target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
249
+ function _(targetOrLength: object | number, context?: string | symbol | ClassMemberDecoratorContext) {
250
+ if (typeof targetOrLength == 'number') {
251
+ return member(type, targetOrLength);
252
+ }
253
+
254
+ return member(type)(targetOrLength, context);
255
+ }
256
+ return _;
257
+ }
258
+
259
+ /**
260
+ * Shortcut types
261
+ *
262
+ * Instead of writing `@member(type)` you can write `@types.type`, or `@types.type(length)` for arrays
263
+ */
264
+ export const types = Object.fromEntries(validPrimitiveTypes.map(t => [t, _member(t)])) as { [K in ValidPrimitiveType]: ReturnType<typeof _member<K>> };
package/src/types.ts CHANGED
@@ -195,3 +195,10 @@ export type Tuple<T, N extends number> = _Tuple<T, N>;
195
195
  * Makes all members of the tuple T optional
196
196
  */
197
197
  export type OptionalTuple<T extends unknown[]> = T extends [infer Head, ...infer Tail] ? [Head?, ...OptionalTuple<Tail>] : T;
198
+
199
+ /**
200
+ * Keys of a Map
201
+ */
202
+ export type MapKeys<T> = T extends Map<infer K, any> ? K : never;
203
+
204
+ export type ClassLike<Instance = unknown> = abstract new (...args: unknown[]) => Instance;