utilium 0.2.0 → 0.3.0
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 +2 -0
- package/dist/index.js +2 -0
- package/dist/string.d.ts +2 -0
- package/dist/string.js +6 -0
- package/dist/struct.d.ts +99 -0
- package/dist/struct.js +157 -0
- package/dist/types.d.ts +5 -0
- package/package.json +1 -1
- package/src/index.ts +2 -0
- package/src/string.ts +7 -0
- package/src/struct.ts +238 -0
- package/src/types.ts +7 -0
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/string.d.ts
ADDED
package/dist/string.js
ADDED
package/dist/struct.d.ts
ADDED
@@ -0,0 +1,99 @@
|
|
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
|
+
export interface StructOptions {
|
5
|
+
align: number;
|
6
|
+
bigEndian: boolean;
|
7
|
+
}
|
8
|
+
export declare function sizeof(type: ValidPrimitiveType | ClassLike | object): number;
|
9
|
+
export declare function align(value: number, alignment: number): number;
|
10
|
+
export declare function struct(options?: Partial<StructOptions>): (target: ClassLike, _?: ClassDecoratorContext) => void;
|
11
|
+
export declare function member(type: ValidPrimitiveType | ClassLike, length?: number): (target: object, context?: ClassMemberDecoratorContext | string | symbol) => void;
|
12
|
+
export declare function serialize(instance: unknown): Uint8Array;
|
13
|
+
export declare function deserialize(instance: unknown, _buffer: Uint8Array): void;
|
14
|
+
export declare const types: {
|
15
|
+
int8: {
|
16
|
+
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
|
17
|
+
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
|
18
|
+
};
|
19
|
+
int16: {
|
20
|
+
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
|
21
|
+
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
|
22
|
+
};
|
23
|
+
int32: {
|
24
|
+
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
|
25
|
+
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
|
26
|
+
};
|
27
|
+
int64: {
|
28
|
+
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
|
29
|
+
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
|
30
|
+
};
|
31
|
+
uint8: {
|
32
|
+
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
|
33
|
+
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
|
34
|
+
};
|
35
|
+
uint16: {
|
36
|
+
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
|
37
|
+
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
|
38
|
+
};
|
39
|
+
uint32: {
|
40
|
+
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
|
41
|
+
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
|
42
|
+
};
|
43
|
+
uint64: {
|
44
|
+
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
|
45
|
+
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
|
46
|
+
};
|
47
|
+
float32: {
|
48
|
+
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
|
49
|
+
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
|
50
|
+
};
|
51
|
+
float64: {
|
52
|
+
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
|
53
|
+
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
|
54
|
+
};
|
55
|
+
Int8: {
|
56
|
+
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
|
57
|
+
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
|
58
|
+
};
|
59
|
+
Int16: {
|
60
|
+
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
|
61
|
+
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
|
62
|
+
};
|
63
|
+
Int32: {
|
64
|
+
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
|
65
|
+
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
|
66
|
+
};
|
67
|
+
Int64: {
|
68
|
+
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
|
69
|
+
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
|
70
|
+
};
|
71
|
+
Uint8: {
|
72
|
+
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
|
73
|
+
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
|
74
|
+
};
|
75
|
+
Uint16: {
|
76
|
+
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
|
77
|
+
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
|
78
|
+
};
|
79
|
+
Uint32: {
|
80
|
+
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
|
81
|
+
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
|
82
|
+
};
|
83
|
+
Uint64: {
|
84
|
+
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
|
85
|
+
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
|
86
|
+
};
|
87
|
+
Float32: {
|
88
|
+
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
|
89
|
+
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
|
90
|
+
};
|
91
|
+
Float64: {
|
92
|
+
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
|
93
|
+
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
|
94
|
+
};
|
95
|
+
char: {
|
96
|
+
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
|
97
|
+
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
|
98
|
+
};
|
99
|
+
};
|
package/dist/struct.js
ADDED
@@ -0,0 +1,157 @@
|
|
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
|
+
export function sizeof(type) {
|
26
|
+
// primitive
|
27
|
+
if (typeof type == 'string') {
|
28
|
+
if (!isValidPrimitive(type)) {
|
29
|
+
throw new TypeError('Invalid primitive type: ' + type);
|
30
|
+
}
|
31
|
+
return +normalizePrimitive(type).match(numberRegex)[2] / 8;
|
32
|
+
}
|
33
|
+
if (!isStruct(type)) {
|
34
|
+
throw new TypeError('Not a struct');
|
35
|
+
}
|
36
|
+
const meta = metadata in type ? type[metadata] : type.constructor[metadata];
|
37
|
+
return meta.size;
|
38
|
+
}
|
39
|
+
export function align(value, alignment) {
|
40
|
+
return Math.ceil(value / alignment) * alignment;
|
41
|
+
}
|
42
|
+
export function struct(options = {}) {
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
44
|
+
return function (target, _) {
|
45
|
+
target[init] || (target[init] = []);
|
46
|
+
let size = 0;
|
47
|
+
const members = new Map();
|
48
|
+
for (const { name, type, length } of target[init]) {
|
49
|
+
if (!isValidPrimitive(type) && !isStatic(type)) {
|
50
|
+
throw new TypeError('Not a valid type: ' + type);
|
51
|
+
}
|
52
|
+
members.set(name, {
|
53
|
+
offset: size,
|
54
|
+
type: isValidPrimitive(type) ? normalizePrimitive(type) : type,
|
55
|
+
length,
|
56
|
+
});
|
57
|
+
size += sizeof(type) * (length || 1);
|
58
|
+
size = align(size, options.align || 1);
|
59
|
+
}
|
60
|
+
target[metadata] = { options, members, size };
|
61
|
+
delete target[init];
|
62
|
+
};
|
63
|
+
}
|
64
|
+
export function member(type, length) {
|
65
|
+
return function (target, context) {
|
66
|
+
var _a;
|
67
|
+
let name = typeof context == 'object' ? context.name : context;
|
68
|
+
if (typeof name == 'symbol') {
|
69
|
+
console.warn('Symbol used for struct member name will be coerced to string: ' + name.toString());
|
70
|
+
name = name.toString();
|
71
|
+
}
|
72
|
+
(_a = target.constructor)[init] || (_a[init] = []);
|
73
|
+
target.constructor[init].push({ name, type, length });
|
74
|
+
};
|
75
|
+
}
|
76
|
+
export function serialize(instance) {
|
77
|
+
if (!isInstance(instance)) {
|
78
|
+
throw new TypeError('Can not serialize, not a struct instance');
|
79
|
+
}
|
80
|
+
const { options, members } = instance.constructor[metadata];
|
81
|
+
const buffer = new Uint8Array(sizeof(instance));
|
82
|
+
const view = new DataView(buffer.buffer);
|
83
|
+
for (const [name, { type, length, offset }] of members) {
|
84
|
+
for (let i = 0; i < (length || 1); i++) {
|
85
|
+
const iOff = offset + sizeof(type) * i;
|
86
|
+
let value = length > 0 ? instance[name][i] : instance[name];
|
87
|
+
if (typeof value == 'string') {
|
88
|
+
value = value.charCodeAt(0);
|
89
|
+
}
|
90
|
+
if (!isPrimitiveType(type)) {
|
91
|
+
buffer.set(value ? serialize(value) : new Uint8Array(sizeof(type)), iOff);
|
92
|
+
continue;
|
93
|
+
}
|
94
|
+
const Type = capitalize(type);
|
95
|
+
const fn = ('set' + Type);
|
96
|
+
if (fn == 'setInt64') {
|
97
|
+
view.setBigInt64(iOff, BigInt(value), !options.bigEndian);
|
98
|
+
continue;
|
99
|
+
}
|
100
|
+
if (fn == 'setUint64') {
|
101
|
+
view.setBigUint64(iOff, BigInt(value), !options.bigEndian);
|
102
|
+
continue;
|
103
|
+
}
|
104
|
+
view[fn](iOff, Number(value), !options.bigEndian);
|
105
|
+
}
|
106
|
+
}
|
107
|
+
return buffer;
|
108
|
+
}
|
109
|
+
export function deserialize(instance, _buffer) {
|
110
|
+
if (!isInstance(instance)) {
|
111
|
+
throw new TypeError('Can not deserialize, not a struct instance');
|
112
|
+
}
|
113
|
+
const { options, members } = instance.constructor[metadata];
|
114
|
+
const buffer = new Uint8Array('buffer' in _buffer ? _buffer.buffer : _buffer);
|
115
|
+
const view = new DataView(buffer.buffer);
|
116
|
+
for (const [name, { type, offset, length }] of members) {
|
117
|
+
for (let i = 0; i < (length || 1); i++) {
|
118
|
+
let object = length > 0 ? instance[name] : instance;
|
119
|
+
const key = length > 0 ? i : name, iOff = offset + sizeof(type) * i;
|
120
|
+
if (typeof instance[name] == 'string') {
|
121
|
+
instance[name] = instance[name].slice(0, i) + String.fromCharCode(view.getUint8(iOff)) + instance[name].slice(i + 1);
|
122
|
+
continue;
|
123
|
+
}
|
124
|
+
if (!isPrimitiveType(type)) {
|
125
|
+
if (object[key] === null || object[key] === undefined) {
|
126
|
+
continue;
|
127
|
+
}
|
128
|
+
deserialize(object[key], new Uint8Array(buffer.slice(iOff, sizeof(type))));
|
129
|
+
continue;
|
130
|
+
}
|
131
|
+
if (length > 0) {
|
132
|
+
object || (object = []);
|
133
|
+
}
|
134
|
+
const Type = capitalize(type);
|
135
|
+
const fn = ('get' + Type);
|
136
|
+
if (fn == 'getInt64') {
|
137
|
+
object[key] = view.getBigInt64(iOff, !options.bigEndian);
|
138
|
+
continue;
|
139
|
+
}
|
140
|
+
if (fn == 'getUint64') {
|
141
|
+
object[key] = view.getBigUint64(iOff, !options.bigEndian);
|
142
|
+
continue;
|
143
|
+
}
|
144
|
+
object[key] = view[fn](iOff, !options.bigEndian);
|
145
|
+
}
|
146
|
+
}
|
147
|
+
}
|
148
|
+
function _member(type) {
|
149
|
+
function _(targetOrLength, context) {
|
150
|
+
if (typeof targetOrLength == 'number') {
|
151
|
+
return member(type, targetOrLength);
|
152
|
+
}
|
153
|
+
return member(type)(targetOrLength, context);
|
154
|
+
}
|
155
|
+
return _;
|
156
|
+
}
|
157
|
+
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
package/src/index.ts
CHANGED
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,238 @@
|
|
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
|
+
export interface StructOptions {
|
34
|
+
align: number;
|
35
|
+
bigEndian: boolean;
|
36
|
+
}
|
37
|
+
|
38
|
+
interface Member {
|
39
|
+
type: PrimitiveType | Static;
|
40
|
+
offset: number;
|
41
|
+
length?: number;
|
42
|
+
}
|
43
|
+
|
44
|
+
interface Metadata {
|
45
|
+
options: Partial<StructOptions>;
|
46
|
+
members: Map<string, Member>;
|
47
|
+
size: number;
|
48
|
+
}
|
49
|
+
|
50
|
+
const metadata = Symbol('struct');
|
51
|
+
|
52
|
+
interface Static {
|
53
|
+
[metadata]?: Metadata;
|
54
|
+
new (): Instance;
|
55
|
+
prototype: Instance;
|
56
|
+
}
|
57
|
+
|
58
|
+
function isStatic(arg: unknown): arg is Static {
|
59
|
+
return typeof arg == 'function' && metadata in arg;
|
60
|
+
}
|
61
|
+
|
62
|
+
interface Instance {
|
63
|
+
constructor: Static;
|
64
|
+
}
|
65
|
+
|
66
|
+
function isInstance(arg: unknown): arg is Instance {
|
67
|
+
return metadata in (arg?.constructor || {});
|
68
|
+
}
|
69
|
+
|
70
|
+
function isStruct(arg: unknown): arg is Instance | Static {
|
71
|
+
return isInstance(arg) || isStatic(arg);
|
72
|
+
}
|
73
|
+
|
74
|
+
export function sizeof(type: ValidPrimitiveType | ClassLike | object): number {
|
75
|
+
// primitive
|
76
|
+
if (typeof type == 'string') {
|
77
|
+
if (!isValidPrimitive(type)) {
|
78
|
+
throw new TypeError('Invalid primitive type: ' + type);
|
79
|
+
}
|
80
|
+
|
81
|
+
return +normalizePrimitive(type).match(numberRegex)[2] / 8;
|
82
|
+
}
|
83
|
+
|
84
|
+
if (!isStruct(type)) {
|
85
|
+
throw new TypeError('Not a struct');
|
86
|
+
}
|
87
|
+
|
88
|
+
const meta: Metadata = metadata in type ? type[metadata] : type.constructor[metadata];
|
89
|
+
return meta.size;
|
90
|
+
}
|
91
|
+
|
92
|
+
export function align(value: number, alignment: number): number {
|
93
|
+
return Math.ceil(value / alignment) * alignment;
|
94
|
+
}
|
95
|
+
|
96
|
+
export function struct(options: Partial<StructOptions> = {}) {
|
97
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
98
|
+
return function (target: ClassLike, _?: ClassDecoratorContext) {
|
99
|
+
target[init] ||= [];
|
100
|
+
let size = 0;
|
101
|
+
const members = new Map();
|
102
|
+
for (const { name, type, length } of target[init] as MemberInit[]) {
|
103
|
+
if (!isValidPrimitive(type) && !isStatic(type)) {
|
104
|
+
throw new TypeError('Not a valid type: ' + type);
|
105
|
+
}
|
106
|
+
members.set(name, {
|
107
|
+
offset: size,
|
108
|
+
type: isValidPrimitive(type) ? normalizePrimitive(type) : type,
|
109
|
+
length,
|
110
|
+
});
|
111
|
+
size += sizeof(type) * (length || 1);
|
112
|
+
size = align(size, options.align || 1);
|
113
|
+
}
|
114
|
+
|
115
|
+
target[metadata] = { options, members, size } satisfies Metadata;
|
116
|
+
delete target[init];
|
117
|
+
};
|
118
|
+
}
|
119
|
+
|
120
|
+
export function member(type: ValidPrimitiveType | ClassLike, length?: number) {
|
121
|
+
return function (target: object, context?: ClassMemberDecoratorContext | string | symbol) {
|
122
|
+
let name = typeof context == 'object' ? context.name : context;
|
123
|
+
if (typeof name == 'symbol') {
|
124
|
+
console.warn('Symbol used for struct member name will be coerced to string: ' + name.toString());
|
125
|
+
name = name.toString();
|
126
|
+
}
|
127
|
+
|
128
|
+
target.constructor[init] ||= [];
|
129
|
+
target.constructor[init].push({ name, type, length } satisfies MemberInit);
|
130
|
+
};
|
131
|
+
}
|
132
|
+
|
133
|
+
export function serialize(instance: unknown): Uint8Array {
|
134
|
+
if (!isInstance(instance)) {
|
135
|
+
throw new TypeError('Can not serialize, not a struct instance');
|
136
|
+
}
|
137
|
+
const { options, members } = instance.constructor[metadata];
|
138
|
+
|
139
|
+
const buffer = new Uint8Array(sizeof(instance));
|
140
|
+
const view = new DataView(buffer.buffer);
|
141
|
+
|
142
|
+
for (const [name, { type, length, offset }] of members) {
|
143
|
+
for (let i = 0; i < (length || 1); i++) {
|
144
|
+
const iOff = offset + sizeof(type) * i;
|
145
|
+
|
146
|
+
let value = length > 0 ? instance[name][i] : instance[name];
|
147
|
+
if (typeof value == 'string') {
|
148
|
+
value = value.charCodeAt(0);
|
149
|
+
}
|
150
|
+
|
151
|
+
if (!isPrimitiveType(type)) {
|
152
|
+
buffer.set(value ? serialize(value) : new Uint8Array(sizeof(type)), iOff);
|
153
|
+
continue;
|
154
|
+
}
|
155
|
+
|
156
|
+
const Type = capitalize(type);
|
157
|
+
const fn = <`set${typeof Type}`>('set' + Type);
|
158
|
+
if (fn == 'setInt64') {
|
159
|
+
view.setBigInt64(iOff, BigInt(value), !options.bigEndian);
|
160
|
+
continue;
|
161
|
+
}
|
162
|
+
|
163
|
+
if (fn == 'setUint64') {
|
164
|
+
view.setBigUint64(iOff, BigInt(value), !options.bigEndian);
|
165
|
+
continue;
|
166
|
+
}
|
167
|
+
|
168
|
+
view[fn](iOff, Number(value), !options.bigEndian);
|
169
|
+
}
|
170
|
+
}
|
171
|
+
|
172
|
+
return buffer;
|
173
|
+
}
|
174
|
+
|
175
|
+
export function deserialize(instance: unknown, _buffer: Uint8Array) {
|
176
|
+
if (!isInstance(instance)) {
|
177
|
+
throw new TypeError('Can not deserialize, not a struct instance');
|
178
|
+
}
|
179
|
+
const { options, members } = instance.constructor[metadata];
|
180
|
+
|
181
|
+
const buffer = new Uint8Array('buffer' in _buffer ? _buffer.buffer : _buffer);
|
182
|
+
|
183
|
+
const view = new DataView(buffer.buffer);
|
184
|
+
|
185
|
+
for (const [name, { type, offset, length }] of members) {
|
186
|
+
for (let i = 0; i < (length || 1); i++) {
|
187
|
+
let object = length > 0 ? instance[name] : instance;
|
188
|
+
const key = length > 0 ? i : name,
|
189
|
+
iOff = offset + sizeof(type) * i;
|
190
|
+
|
191
|
+
if (typeof instance[name] == 'string') {
|
192
|
+
instance[name] = instance[name].slice(0, i) + String.fromCharCode(view.getUint8(iOff)) + instance[name].slice(i + 1);
|
193
|
+
continue;
|
194
|
+
}
|
195
|
+
|
196
|
+
if (!isPrimitiveType(type)) {
|
197
|
+
if (object[key] === null || object[key] === undefined) {
|
198
|
+
continue;
|
199
|
+
}
|
200
|
+
deserialize(object[key], new Uint8Array(buffer.slice(iOff, sizeof(type))));
|
201
|
+
continue;
|
202
|
+
}
|
203
|
+
|
204
|
+
if (length > 0) {
|
205
|
+
object ||= [];
|
206
|
+
}
|
207
|
+
|
208
|
+
const Type = capitalize(type);
|
209
|
+
const fn = <`get${typeof Type}`>('get' + Type);
|
210
|
+
if (fn == 'getInt64') {
|
211
|
+
object[key] = view.getBigInt64(iOff, !options.bigEndian);
|
212
|
+
continue;
|
213
|
+
}
|
214
|
+
|
215
|
+
if (fn == 'getUint64') {
|
216
|
+
object[key] = view.getBigUint64(iOff, !options.bigEndian);
|
217
|
+
continue;
|
218
|
+
}
|
219
|
+
|
220
|
+
object[key] = view[fn](iOff, !options.bigEndian);
|
221
|
+
}
|
222
|
+
}
|
223
|
+
}
|
224
|
+
|
225
|
+
function _member<T extends ValidPrimitiveType>(type: T) {
|
226
|
+
function _(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void;
|
227
|
+
function _(target: object, context?: string | symbol | ClassMemberDecoratorContext): void;
|
228
|
+
function _(targetOrLength: object | number, context?: string | symbol | ClassMemberDecoratorContext) {
|
229
|
+
if (typeof targetOrLength == 'number') {
|
230
|
+
return member(type, targetOrLength);
|
231
|
+
}
|
232
|
+
|
233
|
+
return member(type)(targetOrLength, context);
|
234
|
+
}
|
235
|
+
return _;
|
236
|
+
}
|
237
|
+
|
238
|
+
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;
|