utilium 1.10.0 → 2.0.0-pre.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/buffer.d.ts +340 -1
- package/dist/buffer.js +58 -0
- package/dist/internal/primitives.d.ts +91 -18
- package/dist/internal/primitives.js +90 -25
- package/dist/internal/struct.d.ts +22 -48
- package/dist/internal/struct.js +7 -24
- package/dist/objects.d.ts +6 -0
- package/dist/string.js +7 -1
- package/dist/struct.d.ts +17 -18
- package/dist/struct.js +122 -217
- package/package.json +1 -1
- package/src/buffer.ts +363 -1
- package/src/internal/primitives.ts +120 -46
- package/src/internal/struct.ts +39 -72
- package/src/objects.ts +7 -0
- package/src/string.ts +7 -1
- package/src/struct.ts +152 -267
@@ -1,38 +1,26 @@
|
|
1
1
|
import type { ClassLike } from '../types.js';
|
2
2
|
import type * as primitive from './primitives.js';
|
3
|
-
|
4
|
-
|
5
|
-
readonly size: unique symbol;
|
6
|
-
readonly serialize: unique symbol;
|
7
|
-
readonly deserialize: unique symbol;
|
8
|
-
}
|
9
|
-
}
|
10
|
-
export type TypeLike = Custom | Like | primitive.Valid | undefined | null;
|
11
|
-
export type Type = Custom | Static | primitive.Typename;
|
12
|
-
/**
|
13
|
-
* Member initialization data
|
14
|
-
* This is needed since class decorators are called *after* member decorators
|
15
|
-
*/
|
16
|
-
export interface MemberInit {
|
17
|
-
name: string;
|
18
|
-
type: string | ClassLike;
|
19
|
-
length?: number | string;
|
20
|
-
}
|
3
|
+
export type TypeLike = primitive.Type | Like | primitive.Valid | undefined | null;
|
4
|
+
export type Type = Static | primitive.Type;
|
21
5
|
/**
|
22
6
|
* Options for struct initialization
|
23
7
|
*/
|
24
8
|
export interface Options {
|
9
|
+
packed: boolean;
|
25
10
|
align: number;
|
26
|
-
bigEndian: boolean;
|
27
11
|
isUnion: boolean;
|
28
12
|
}
|
29
13
|
export interface Member {
|
30
14
|
name: string;
|
31
15
|
type: Type;
|
32
|
-
|
16
|
+
offset: number;
|
17
|
+
/** The size of the member, 0 for dynamically sized arrays */
|
18
|
+
size: number;
|
33
19
|
length?: number | string;
|
34
20
|
/** A C-style type/name declaration string, used for diagnostics */
|
35
21
|
decl: string;
|
22
|
+
/** Whether the member is little endian */
|
23
|
+
littleEndian: boolean;
|
36
24
|
}
|
37
25
|
export interface Metadata {
|
38
26
|
options: Partial<Options>;
|
@@ -43,9 +31,15 @@ export interface Metadata {
|
|
43
31
|
/** Whether the struct is a union */
|
44
32
|
isUnion: boolean;
|
45
33
|
}
|
34
|
+
export interface Init {
|
35
|
+
members: Member[];
|
36
|
+
size: number;
|
37
|
+
isDynamic: boolean;
|
38
|
+
isUnion: boolean;
|
39
|
+
}
|
46
40
|
type _DecoratorMetadata<T extends Metadata = Metadata> = DecoratorMetadata & {
|
47
41
|
struct?: T;
|
48
|
-
structInit?:
|
42
|
+
structInit?: Init;
|
49
43
|
};
|
50
44
|
export interface DecoratorContext<T extends Metadata = Metadata> {
|
51
45
|
metadata: _DecoratorMetadata<T>;
|
@@ -54,30 +48,21 @@ export interface DecoratorContext<T extends Metadata = Metadata> {
|
|
54
48
|
* Initializes the struct metadata for a class
|
55
49
|
* This also handles copying metadata from parent classes
|
56
50
|
*/
|
57
|
-
export declare function initMetadata(context: DecoratorContext):
|
58
|
-
export type MemberContext = ClassMemberDecoratorContext & DecoratorContext;
|
51
|
+
export declare function initMetadata(context: DecoratorContext): Init;
|
59
52
|
export interface Static<T extends Metadata = Metadata> {
|
60
|
-
[Symbol.metadata]:
|
61
|
-
|
62
|
-
|
63
|
-
new (): Instance<T>;
|
64
|
-
prototype: Instance<T>;
|
53
|
+
[Symbol.metadata]: Required<_DecoratorMetadata<T>>;
|
54
|
+
readonly prototype: Instance<T>;
|
55
|
+
new <TArrayBuffer extends ArrayBufferLike = ArrayBuffer>(buffer: TArrayBuffer, byteOffset?: number, length?: number): Instance<T> & ArrayBufferView<TArrayBuffer>;
|
56
|
+
new (array?: ArrayLike<number> | ArrayBuffer): Instance<T>;
|
65
57
|
}
|
66
58
|
export interface StaticLike<T extends Metadata = Metadata> extends ClassLike {
|
67
59
|
[Symbol.metadata]?: _DecoratorMetadata<T> | null;
|
68
|
-
new (): unknown;
|
69
60
|
}
|
70
61
|
export declare function isValidMetadata<T extends Metadata = Metadata>(arg: unknown): arg is DecoratorMetadata & {
|
71
62
|
struct: T;
|
72
63
|
};
|
73
|
-
/**
|
74
|
-
* Polyfill context.metadata
|
75
|
-
* @see https://github.com/microsoft/TypeScript/issues/53461
|
76
|
-
* @internal @hidden
|
77
|
-
*/
|
78
|
-
export declare function _polyfill_metadata(target: object): void;
|
79
64
|
export declare function isStatic<T extends Metadata = Metadata>(arg: unknown): arg is Static<T>;
|
80
|
-
export interface Instance<T extends Metadata = Metadata> {
|
65
|
+
export interface Instance<T extends Metadata = Metadata> extends ArrayBufferView, Record<PropertyKey, any> {
|
81
66
|
constructor: Static<T>;
|
82
67
|
}
|
83
68
|
export interface InstanceLike<T extends Metadata = Metadata> {
|
@@ -87,17 +72,6 @@ export declare function isInstance<T extends Metadata = Metadata>(arg: unknown):
|
|
87
72
|
export declare function checkInstance<T extends Metadata = Metadata>(arg: unknown): asserts arg is Instance<T> & Record<keyof any, any>;
|
88
73
|
export declare function isStruct<T extends Metadata = Metadata>(arg: unknown): arg is Instance<T> | Static<T>;
|
89
74
|
export declare function checkStruct<T extends Metadata = Metadata>(arg: unknown): asserts arg is Instance<T> | Static<T>;
|
90
|
-
/**
|
91
|
-
* A "custom" type, which can be used to implement non-builtin size, serialization, and deserialization
|
92
|
-
*/
|
93
|
-
export interface Custom {
|
94
|
-
readonly [Symbol.size]: number;
|
95
|
-
[Symbol.serialize]?(): Uint8Array;
|
96
|
-
[Symbol.deserialize]?(value: Uint8Array): void;
|
97
|
-
}
|
98
|
-
export declare function isCustom(arg: unknown): arg is Custom;
|
99
75
|
export type Like<T extends Metadata = Metadata> = InstanceLike<T> | StaticLike<T>;
|
100
|
-
export type Size<T extends TypeLike> = T extends undefined | null ? 0 : T extends
|
101
|
-
readonly [Symbol.size]: infer S extends number;
|
102
|
-
} ? S : T extends primitive.Valid ? primitive.Size<T> : number;
|
76
|
+
export type Size<T extends TypeLike> = T extends undefined | null ? 0 : T extends primitive.Valid ? primitive.Size<T> : number;
|
103
77
|
export {};
|
package/dist/internal/struct.js
CHANGED
@@ -3,38 +3,24 @@
|
|
3
3
|
* @see https://github.com/microsoft/TypeScript/issues/53461
|
4
4
|
*/
|
5
5
|
Symbol.metadata ??= Symbol.for('Symbol.metadata');
|
6
|
-
Object.assign(Symbol, {
|
7
|
-
size: Symbol('uSize'),
|
8
|
-
serialize: Symbol('uSerialize'),
|
9
|
-
deserialize: Symbol('uDeserialize'),
|
10
|
-
});
|
11
6
|
/**
|
12
7
|
* Initializes the struct metadata for a class
|
13
8
|
* This also handles copying metadata from parent classes
|
14
9
|
*/
|
15
10
|
export function initMetadata(context) {
|
16
11
|
context.metadata ??= {};
|
17
|
-
|
12
|
+
const existing = context.metadata.structInit ?? {};
|
13
|
+
context.metadata.structInit = {
|
14
|
+
members: [...(existing.members ?? [])],
|
15
|
+
size: existing.size ?? 0,
|
16
|
+
isDynamic: existing.isDynamic ?? false,
|
17
|
+
isUnion: existing.isUnion ?? false,
|
18
|
+
};
|
18
19
|
return context.metadata.structInit;
|
19
20
|
}
|
20
21
|
export function isValidMetadata(arg) {
|
21
22
|
return arg != null && typeof arg == 'object' && 'struct' in arg;
|
22
23
|
}
|
23
|
-
/**
|
24
|
-
* Polyfill context.metadata
|
25
|
-
* @see https://github.com/microsoft/TypeScript/issues/53461
|
26
|
-
* @internal @hidden
|
27
|
-
*/
|
28
|
-
export function _polyfill_metadata(target) {
|
29
|
-
if (Symbol.metadata in target)
|
30
|
-
return;
|
31
|
-
Object.defineProperty(target, Symbol.metadata, {
|
32
|
-
enumerable: true,
|
33
|
-
configurable: true,
|
34
|
-
writable: true,
|
35
|
-
value: Object.create(null),
|
36
|
-
});
|
37
|
-
}
|
38
24
|
export function isStatic(arg) {
|
39
25
|
return typeof arg == 'function' && Symbol.metadata in arg && isValidMetadata(arg[Symbol.metadata]);
|
40
26
|
}
|
@@ -56,6 +42,3 @@ export function checkStruct(arg) {
|
|
56
42
|
throw new TypeError((typeof arg == 'function' ? arg.name : typeof arg == 'object' && arg ? arg.constructor.name : arg)
|
57
43
|
+ ' is not a struct');
|
58
44
|
}
|
59
|
-
export function isCustom(arg) {
|
60
|
-
return typeof arg == 'object' && arg != null && Symbol.size in arg;
|
61
|
-
}
|
package/dist/objects.d.ts
CHANGED
@@ -48,3 +48,9 @@ export type Bound<T extends object, This = any> = T & {
|
|
48
48
|
* Binds a this value for all of the functions in an object (not recursive)
|
49
49
|
*/
|
50
50
|
export declare function bindFunctions<T extends object, This = any>(fns: T, thisValue: This): Bound<T, This>;
|
51
|
+
/**
|
52
|
+
* Makes all properties in T mutable
|
53
|
+
*/
|
54
|
+
export type Mutable<T> = {
|
55
|
+
-readonly [P in keyof T]: T[P];
|
56
|
+
};
|
package/dist/string.js
CHANGED
@@ -16,7 +16,13 @@ const decoder = new TextDecoder();
|
|
16
16
|
* Decodes a UTF-8 string from a buffer
|
17
17
|
*/
|
18
18
|
export function decodeUTF8(input) {
|
19
|
-
|
19
|
+
if (!input)
|
20
|
+
return '';
|
21
|
+
if (input.buffer instanceof ArrayBuffer && !input.buffer.resizable)
|
22
|
+
return decoder.decode(input);
|
23
|
+
const buffer = new Uint8Array(input.byteLength);
|
24
|
+
buffer.set(input);
|
25
|
+
return decoder.decode(buffer);
|
20
26
|
}
|
21
27
|
export function encodeASCII(input) {
|
22
28
|
const data = new Uint8Array(input.length);
|
package/dist/struct.d.ts
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
import * as primitive from './internal/primitives.js';
|
2
|
-
import type { DecoratorContext, InstanceLike,
|
3
|
-
import type { ClassLike } from './types.js';
|
2
|
+
import type { DecoratorContext, InstanceLike, Options, Size, StaticLike, TypeLike } from './internal/struct.js';
|
4
3
|
export * as Struct from './internal/struct.js';
|
5
4
|
/**
|
6
5
|
* Gets the size in bytes of a type
|
@@ -10,29 +9,29 @@ export declare function sizeof<T extends TypeLike>(type: T | T[]): Size<T>;
|
|
10
9
|
* Returns the offset (in bytes) of a member in a struct.
|
11
10
|
*/
|
12
11
|
export declare function offsetof(type: StaticLike | InstanceLike, memberName: string): number;
|
13
|
-
/**
|
14
|
-
* Aligns a number
|
15
|
-
*/
|
12
|
+
/** Aligns a number */
|
16
13
|
export declare function align(value: number, alignment: number): number;
|
17
14
|
/**
|
18
15
|
* Decorates a class as a struct
|
19
16
|
*/
|
20
|
-
export declare function struct(options?: Partial<Options>): <
|
17
|
+
export declare function struct(options?: Partial<Options>): <T extends StaticLike>(target: T, context: ClassDecoratorContext<T> & DecoratorContext) => void;
|
18
|
+
export interface MemberOptions {
|
19
|
+
bigEndian?: boolean;
|
20
|
+
length?: number | string;
|
21
|
+
align?: number;
|
22
|
+
typeName?: string;
|
23
|
+
}
|
21
24
|
/**
|
22
25
|
* Decorates a class member to be serialized
|
23
26
|
*/
|
24
|
-
export declare function member(type: primitive.
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
export declare function deserialize(instance: unknown, _buffer: ArrayBufferLike | ArrayBufferView): void;
|
33
|
-
declare function _member<T extends primitive.Valid>(type: T): {
|
34
|
-
<const V>(length: number | string): (value: V, context: MemberContext) => V;
|
35
|
-
<const V>(value: V, context: MemberContext): V;
|
27
|
+
export declare function member<V>(type: primitive.Type | StaticLike, opt?: MemberOptions): (value: Target<V>, context: Context<V>) => Result<V>;
|
28
|
+
type Target<V> = ClassAccessorDecoratorTarget<any, V>;
|
29
|
+
type Result<V> = ClassAccessorDecoratorResult<any, V>;
|
30
|
+
type Context<V> = ClassAccessorDecoratorContext<any, V> & DecoratorContext;
|
31
|
+
type Decorator<V> = (value: Target<V>, context: Context<V>) => Result<V>;
|
32
|
+
declare function _member<T extends primitive.Valid>(typeName: T): {
|
33
|
+
<V>(length: number | string): Decorator<V>;
|
34
|
+
<V>(value: Target<V>, context: Context<V>): Result<V>;
|
36
35
|
};
|
37
36
|
/**
|
38
37
|
* Shortcut types
|
package/dist/struct.js
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
import {
|
1
|
+
import { BufferViewArray } from './buffer.js';
|
2
2
|
import { _debugLog } from './debugging.js';
|
3
3
|
import * as primitive from './internal/primitives.js';
|
4
|
-
import {
|
4
|
+
import { checkStruct, initMetadata, isInstance, isStatic, isStruct } from './internal/struct.js';
|
5
5
|
import { _throw } from './misc.js';
|
6
|
-
import {
|
6
|
+
import { getAllPrototypes } from './objects.js';
|
7
7
|
export * as Struct from './internal/struct.js';
|
8
8
|
/**
|
9
9
|
* Gets the size in bytes of a type
|
@@ -21,38 +21,28 @@ export function sizeof(type) {
|
|
21
21
|
// primitive or character
|
22
22
|
if (typeof type == 'string') {
|
23
23
|
primitive.checkValid(type);
|
24
|
-
return
|
24
|
+
return primitive.types[primitive.normalize(type)].size;
|
25
25
|
}
|
26
|
-
if (
|
27
|
-
return type
|
26
|
+
if (primitive.isType(type))
|
27
|
+
return type.size;
|
28
28
|
checkStruct(type);
|
29
29
|
const constructor = isStatic(type) ? type : type.constructor;
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
}
|
44
|
-
if (typeof member.length != 'string')
|
45
|
-
continue;
|
46
|
-
let subSize = 0;
|
47
|
-
for (let i = 0; i < type[member.length]; i++) {
|
48
|
-
subSize += sizeof(isStruct(value[i]) ? value[i] : member.type);
|
30
|
+
const { struct, structInit } = constructor[Symbol.metadata];
|
31
|
+
if (isStatic(type) || !struct.isDynamic)
|
32
|
+
return struct.staticSize;
|
33
|
+
const last = structInit.members.at(-1);
|
34
|
+
const length = type[last.length];
|
35
|
+
let dynamicSize = 0;
|
36
|
+
if (primitive.isType(last.type)) {
|
37
|
+
dynamicSize = last.type.size * length;
|
38
|
+
}
|
39
|
+
else {
|
40
|
+
const value = type[last.name];
|
41
|
+
for (let i = 0; i < length; i++) {
|
42
|
+
dynamicSize += sizeof(isStruct(value[i]) ? value[i] : last.type);
|
49
43
|
}
|
50
|
-
if (struct.isUnion)
|
51
|
-
size = Math.max(size, subSize);
|
52
|
-
else
|
53
|
-
size += subSize;
|
54
44
|
}
|
55
|
-
return
|
45
|
+
return (struct.isUnion ? Math.max(struct.staticSize, dynamicSize) : struct.staticSize + dynamicSize);
|
56
46
|
}
|
57
47
|
/**
|
58
48
|
* Returns the offset (in bytes) of a member in a struct.
|
@@ -60,24 +50,12 @@ export function sizeof(type) {
|
|
60
50
|
export function offsetof(type, memberName) {
|
61
51
|
checkStruct(type);
|
62
52
|
const constructor = isStatic(type) ? type : type.constructor;
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
?? _throw(new Error('Struct does not have member: ' + memberName)));
|
68
|
-
}
|
69
|
-
let offset = 0;
|
70
|
-
for (const member of struct.members.values()) {
|
71
|
-
if (member.name == memberName)
|
72
|
-
return offset;
|
73
|
-
const value = type[member.name];
|
74
|
-
offset += sizeof(isStruct(value) ? value : member.type);
|
75
|
-
}
|
76
|
-
throw new Error('Struct does not have member: ' + memberName);
|
53
|
+
const member = constructor[Symbol.metadata].struct.members.get(memberName);
|
54
|
+
if (!member)
|
55
|
+
throw new Error('Struct does not have member: ' + memberName);
|
56
|
+
return member.offset;
|
77
57
|
}
|
78
|
-
/**
|
79
|
-
* Aligns a number
|
80
|
-
*/
|
58
|
+
/** Aligns a number */
|
81
59
|
export function align(value, alignment) {
|
82
60
|
return Math.ceil(value / alignment) * alignment;
|
83
61
|
}
|
@@ -86,51 +64,33 @@ export function align(value, alignment) {
|
|
86
64
|
*/
|
87
65
|
export function struct(options = {}) {
|
88
66
|
return function _decorateStruct(target, context) {
|
67
|
+
const init = initMetadata(context);
|
89
68
|
const members = new Map();
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
const countedBy = members.get(length);
|
96
|
-
if (!countedBy)
|
97
|
-
throw new Error(`"${length}" is undefined or declared after "${name}"`);
|
98
|
-
if (!primitive.isType(countedBy.type))
|
99
|
-
throw new Error(`"${length}" is not a number and cannot be used to count "${name}"`);
|
100
|
-
}
|
101
|
-
let decl = `${typeof type == 'string' ? type : type.name} ${name}`;
|
102
|
-
if (length !== undefined)
|
103
|
-
decl += `[${length}]`;
|
104
|
-
members.set(name, {
|
105
|
-
name,
|
106
|
-
staticOffset: options.isUnion ? 0 : staticSize,
|
107
|
-
type: primitive.isValid(type) ? primitive.normalize(type) : type,
|
108
|
-
length,
|
109
|
-
decl,
|
110
|
-
});
|
111
|
-
const memberSize = typeof length == 'string' || (isStatic(type) && type[Symbol.metadata].struct.isDynamic)
|
112
|
-
? 0
|
113
|
-
: sizeof(type) * (length || 1);
|
114
|
-
isDynamic ||= isStatic(type) ? type[Symbol.metadata].struct.isDynamic : typeof length == 'string';
|
115
|
-
staticSize = options.isUnion ? Math.max(staticSize, memberSize) : staticSize + memberSize;
|
116
|
-
staticSize = align(staticSize, options.align || 1);
|
117
|
-
_debugLog('define', target.name + '.' + name);
|
69
|
+
for (const member of init.members) {
|
70
|
+
if (options.isUnion)
|
71
|
+
member.offset = 0;
|
72
|
+
_debugLog('define', target.name + '.' + member.name);
|
73
|
+
members.set(member.name, member);
|
118
74
|
}
|
119
75
|
context.metadata.struct = {
|
120
76
|
options,
|
121
77
|
members,
|
122
|
-
staticSize,
|
123
|
-
isDynamic,
|
78
|
+
staticSize: init.size,
|
79
|
+
isDynamic: init.isDynamic,
|
124
80
|
isUnion: options.isUnion ?? false,
|
125
81
|
};
|
126
|
-
return target;
|
127
82
|
};
|
128
83
|
}
|
129
84
|
/**
|
130
85
|
* Decorates a class member to be serialized
|
131
86
|
*/
|
132
|
-
export function member(type,
|
133
|
-
return function (value, context) {
|
87
|
+
export function member(type, opt = {}) {
|
88
|
+
return function __decorateMember(value, context) {
|
89
|
+
if (context.kind != 'accessor')
|
90
|
+
throw new Error('Member must be an accessor');
|
91
|
+
const init = initMetadata(context);
|
92
|
+
if (init.isDynamic)
|
93
|
+
throw new Error('Dynamic members must be declared at the end of the struct');
|
134
94
|
let name = context.name;
|
135
95
|
if (typeof name == 'symbol') {
|
136
96
|
console.warn('Symbol used for struct member name will be coerced to string: ' + name.toString());
|
@@ -138,155 +98,100 @@ export function member(type, length) {
|
|
138
98
|
}
|
139
99
|
if (!name)
|
140
100
|
throw new ReferenceError('Invalid name for struct member');
|
141
|
-
|
142
|
-
|
101
|
+
if (!primitive.isType(type) && !isStatic(type))
|
102
|
+
throw new TypeError('Not a valid type: ' + type.name);
|
103
|
+
if (typeof opt.length == 'string') {
|
104
|
+
const countedBy = init.members.find(m => m.name == opt.length);
|
105
|
+
if (!countedBy)
|
106
|
+
throw new Error(`"${opt.length}" is not declared and cannot be used to count "${name}"`);
|
107
|
+
if (!primitive.isType(countedBy.type))
|
108
|
+
throw new Error(`"${opt.length}" is not a number and cannot be used to count "${name}"`);
|
109
|
+
init.isDynamic = true;
|
110
|
+
}
|
111
|
+
const size = align(sizeof(type) * (typeof opt.length == 'string' ? 0 : (opt.length ?? 1)), opt.align ?? sizeof(type));
|
112
|
+
const member = {
|
113
|
+
name,
|
114
|
+
offset: init.size,
|
115
|
+
type,
|
116
|
+
length: opt.length,
|
117
|
+
size,
|
118
|
+
decl: `${opt.typeName ?? type.name} ${name}${opt.length !== undefined ? `[${JSON.stringify(opt.length)}]` : ''}`,
|
119
|
+
littleEndian: !opt.bigEndian,
|
120
|
+
};
|
121
|
+
init.members.push(member);
|
122
|
+
// Apply after setting `offset`
|
123
|
+
init.size += size;
|
124
|
+
return {
|
125
|
+
get() {
|
126
|
+
return _get(this, member);
|
127
|
+
},
|
128
|
+
set(value) {
|
129
|
+
_set(this, member, value);
|
130
|
+
},
|
131
|
+
};
|
143
132
|
};
|
144
133
|
}
|
145
134
|
/** Gets the length of a member */
|
146
|
-
function _memberLength(instance,
|
147
|
-
if (
|
135
|
+
function _memberLength(instance, length) {
|
136
|
+
if (length === undefined)
|
148
137
|
return -1;
|
149
|
-
if (typeof
|
150
|
-
return instance[
|
151
|
-
return Number.isSafeInteger(
|
152
|
-
?
|
138
|
+
if (typeof length == 'string')
|
139
|
+
return instance[length];
|
140
|
+
return Number.isSafeInteger(length) && length >= 0
|
141
|
+
? length
|
153
142
|
: _throw(new Error('Array lengths must be natural numbers'));
|
154
143
|
}
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
const buffer = new Uint8Array(size);
|
166
|
-
const view = new DataView(buffer.buffer);
|
167
|
-
_debugLog('serialize', instance.constructor.name);
|
168
|
-
let offset = 0, nextOffset = 0;
|
169
|
-
// for unions we should write members in ascending last modified order, but we don't have that info.
|
170
|
-
for (const member of members.values()) {
|
171
|
-
const length = _memberLength(instance, member);
|
172
|
-
_debugLog('\t', member.decl);
|
173
|
-
for (let i = 0; i < Math.abs(length); i++) {
|
174
|
-
let value = length != -1 ? instance[member.name][i] : instance[member.name];
|
175
|
-
if (typeof value == 'string') {
|
176
|
-
value = value.charCodeAt(0);
|
177
|
-
}
|
178
|
-
offset = nextOffset;
|
179
|
-
nextOffset += isInstance(value) ? sizeof(value) : sizeof(member.type);
|
180
|
-
if (!primitive.isType(member.type)) {
|
181
|
-
buffer.set(value ? serialize(value) : new Uint8Array(sizeof(member.type)), offset);
|
182
|
-
continue;
|
183
|
-
}
|
184
|
-
const fn = `set${capitalize(member.type)}`;
|
185
|
-
if (fn == 'setInt64') {
|
186
|
-
view.setBigInt64(offset, BigInt(value), !options.bigEndian);
|
187
|
-
continue;
|
188
|
-
}
|
189
|
-
if (fn == 'setUint64') {
|
190
|
-
view.setBigUint64(offset, BigInt(value), !options.bigEndian);
|
191
|
-
continue;
|
192
|
-
}
|
193
|
-
if (fn == 'setInt128') {
|
194
|
-
view.setBigUint64(offset + (!options.bigEndian ? 0 : 8), value & primitive.mask64, !options.bigEndian);
|
195
|
-
view.setBigInt64(offset + (!options.bigEndian ? 8 : 0), value >> BigInt(64), !options.bigEndian);
|
196
|
-
continue;
|
197
|
-
}
|
198
|
-
if (fn == 'setUint128') {
|
199
|
-
view.setBigUint64(offset + (!options.bigEndian ? 0 : 8), value & primitive.mask64, !options.bigEndian);
|
200
|
-
view.setBigUint64(offset + (!options.bigEndian ? 8 : 0), value >> BigInt(64), !options.bigEndian);
|
201
|
-
continue;
|
202
|
-
}
|
203
|
-
if (fn == 'setFloat128') {
|
204
|
-
view.setFloat64(offset + (!options.bigEndian ? 0 : 8), Number(value), !options.bigEndian);
|
205
|
-
view.setBigUint64(offset + (!options.bigEndian ? 8 : 0), BigInt(0), !options.bigEndian);
|
206
|
-
continue;
|
207
|
-
}
|
208
|
-
view[fn](offset, Number(value), !options.bigEndian);
|
144
|
+
function _set(instance, member, value, index) {
|
145
|
+
const { name, type, length: rawLength } = member;
|
146
|
+
const length = _memberLength(instance, rawLength);
|
147
|
+
if (!primitive.isType(type)) {
|
148
|
+
if (!isInstance(value))
|
149
|
+
return _debugLog(`Tried to set "${name}" to a non-instance value`);
|
150
|
+
if (length > 0 && typeof index != 'number') {
|
151
|
+
for (let i = 0; i < length; i++)
|
152
|
+
_set(instance, member, value[i], i);
|
153
|
+
return;
|
209
154
|
}
|
155
|
+
if (!Array.from(getAllPrototypes(value.constructor)).some(c => c === type))
|
156
|
+
throw new Error(`${value.constructor.name} is not a subtype of ${type.name}`);
|
157
|
+
const offset = instance.byteOffset + member.offset + (index ?? 0) * sizeof(type);
|
158
|
+
// It's already the same value
|
159
|
+
if (value.buffer === instance.buffer && value.byteOffset === offset)
|
160
|
+
return;
|
161
|
+
const current = new Uint8Array(instance.buffer, offset, sizeof(value));
|
162
|
+
current.set(new Uint8Array(value.buffer, value.byteOffset, sizeof(value)));
|
163
|
+
return;
|
210
164
|
}
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
export function deserialize(instance, _buffer) {
|
217
|
-
const buffer = toUint8Array(_buffer);
|
218
|
-
if (isCustom(instance) && typeof instance[Symbol.deserialize] == 'function')
|
219
|
-
return instance[Symbol.deserialize](buffer);
|
220
|
-
checkInstance(instance);
|
221
|
-
_polyfill_metadata(instance.constructor);
|
222
|
-
const { options, members } = instance.constructor[Symbol.metadata].struct;
|
223
|
-
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
224
|
-
_debugLog('deserialize', instance.constructor.name);
|
225
|
-
let offset = 0, nextOffset = 0;
|
226
|
-
for (const member of members.values()) {
|
227
|
-
const length = _memberLength(instance, member);
|
228
|
-
_debugLog('\t', member.decl);
|
229
|
-
for (let i = 0; i < Math.abs(length); i++) {
|
230
|
-
let object = length != -1 ? instance[member.name] : instance;
|
231
|
-
const key = length != -1 ? i : member.name;
|
232
|
-
const isNullish = object[key] === null || object[key] === undefined;
|
233
|
-
const needsAllocation = isNullish && isStatic(member.type) && member.type[Symbol.metadata].struct.isDynamic;
|
234
|
-
offset = nextOffset;
|
235
|
-
if (!isInstance(object[key]) && !needsAllocation)
|
236
|
-
nextOffset += sizeof(member.type);
|
237
|
-
if (typeof instance[member.name] == 'string') {
|
238
|
-
instance[member.name] =
|
239
|
-
instance[member.name].slice(0, i)
|
240
|
-
+ String.fromCharCode(view.getUint8(offset))
|
241
|
-
+ instance[member.name].slice(i + 1);
|
242
|
-
continue;
|
243
|
-
}
|
244
|
-
if (!primitive.isType(member.type)) {
|
245
|
-
if (needsAllocation && isStatic(member.type))
|
246
|
-
object[key] ??= new member.type();
|
247
|
-
else if (isNullish)
|
248
|
-
continue;
|
249
|
-
deserialize(object[key], new Uint8Array(buffer.subarray(offset)));
|
250
|
-
nextOffset += sizeof(object[key]);
|
251
|
-
continue;
|
252
|
-
}
|
253
|
-
if (length && length != -1)
|
254
|
-
object ||= [];
|
255
|
-
const fn = `get${capitalize(member.type)}`;
|
256
|
-
if (fn == 'getInt64') {
|
257
|
-
object[key] = view.getBigInt64(offset, !options.bigEndian);
|
258
|
-
continue;
|
259
|
-
}
|
260
|
-
if (fn == 'getUint64') {
|
261
|
-
object[key] = view.getBigUint64(offset, !options.bigEndian);
|
262
|
-
continue;
|
263
|
-
}
|
264
|
-
if (fn == 'getInt128') {
|
265
|
-
object[key] =
|
266
|
-
(view.getBigInt64(offset + (!options.bigEndian ? 8 : 0), !options.bigEndian) << BigInt(64))
|
267
|
-
| view.getBigUint64(offset + (!options.bigEndian ? 0 : 8), !options.bigEndian);
|
268
|
-
continue;
|
269
|
-
}
|
270
|
-
if (fn == 'getUint128') {
|
271
|
-
object[key] =
|
272
|
-
(view.getBigUint64(offset + (!options.bigEndian ? 8 : 0), !options.bigEndian) << BigInt(64))
|
273
|
-
| view.getBigUint64(offset + (!options.bigEndian ? 0 : 8), !options.bigEndian);
|
274
|
-
continue;
|
275
|
-
}
|
276
|
-
if (fn == 'getFloat128') {
|
277
|
-
object[key] = view.getFloat64(offset + (!options.bigEndian ? 0 : 8), !options.bigEndian);
|
278
|
-
continue;
|
279
|
-
}
|
280
|
-
object[key] = view[fn](offset, !options.bigEndian);
|
165
|
+
const view = new DataView(instance.buffer, instance.byteOffset, instance.byteLength);
|
166
|
+
if (length > 0 && typeof index != 'number') {
|
167
|
+
for (let i = 0; i < length; i++) {
|
168
|
+
const offset = member.offset + i * type.size;
|
169
|
+
type.set(view, offset, member.littleEndian, value[i]);
|
281
170
|
}
|
171
|
+
return;
|
282
172
|
}
|
173
|
+
if (typeof value == 'string')
|
174
|
+
value = value.charCodeAt(0);
|
175
|
+
type.set(view, member.offset + (index ?? 0) * type.size, member.littleEndian, value);
|
283
176
|
}
|
284
|
-
function
|
177
|
+
function _get(instance, member, index) {
|
178
|
+
const { type, length: rawLength } = member;
|
179
|
+
const length = _memberLength(instance, rawLength);
|
180
|
+
if (length > 0 && typeof index != 'number') {
|
181
|
+
return new (primitive.isType(type) ? type.array : BufferViewArray(type, sizeof(type)))(instance.buffer, instance.byteOffset + member.offset, length * sizeof(type));
|
182
|
+
}
|
183
|
+
const offset = member.offset + (index ?? 0) * sizeof(type);
|
184
|
+
if (isStatic(type))
|
185
|
+
return new type(instance.buffer, offset, sizeof(type));
|
186
|
+
const view = new DataView(instance.buffer, instance.byteOffset, instance.byteLength);
|
187
|
+
return type.get(view, offset, member.littleEndian);
|
188
|
+
}
|
189
|
+
function _member(typeName) {
|
190
|
+
const type = primitive.types[primitive.normalize(typeName)];
|
285
191
|
function _structMemberDecorator(valueOrLength, context) {
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
return member(type)(valueOrLength, context);
|
192
|
+
return typeof valueOrLength == 'number' || typeof valueOrLength == 'string'
|
193
|
+
? member(type, { length: valueOrLength, typeName })
|
194
|
+
: member(type, { typeName })(valueOrLength, context);
|
290
195
|
}
|
291
196
|
return _structMemberDecorator;
|
292
197
|
}
|