@nnilky/structo 1.0.1 → 1.0.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/structo/datatypes/containers/array.d.ts +2 -0
- package/dist/structo/datatypes/containers/array.js +22 -0
- package/dist/structo/datatypes/containers/fastObject.d.ts +6 -0
- package/dist/structo/datatypes/containers/fastObject.js +46 -0
- package/dist/structo/datatypes/containers/list.d.ts +5 -0
- package/dist/structo/datatypes/containers/list.js +22 -0
- package/dist/structo/datatypes/containers/object.d.ts +9 -0
- package/dist/structo/datatypes/containers/object.js +24 -0
- package/dist/structo/datatypes/containers/sizedbuffer.d.ts +2 -0
- package/dist/structo/datatypes/containers/sizedbuffer.js +17 -0
- package/dist/structo/datatypes/index.d.ts +15 -0
- package/dist/structo/datatypes/index.js +15 -0
- package/dist/structo/datatypes/numbers/bigints.d.ts +3 -0
- package/dist/structo/datatypes/numbers/bigints.js +37 -0
- package/dist/structo/datatypes/numbers/floats.d.ts +3 -0
- package/dist/structo/datatypes/numbers/floats.js +30 -0
- package/dist/structo/datatypes/numbers/sints.d.ts +5 -0
- package/dist/structo/datatypes/numbers/sints.js +72 -0
- package/dist/structo/datatypes/numbers/uints.d.ts +5 -0
- package/dist/structo/datatypes/numbers/uints.js +76 -0
- package/dist/structo/datatypes/transforms/pipe.d.ts +11 -0
- package/dist/structo/datatypes/transforms/pipe.js +4 -0
- package/dist/structo/datatypes/transforms/readOffset.d.ts +2 -0
- package/dist/structo/datatypes/transforms/readOffset.js +18 -0
- package/dist/structo/datatypes/transforms/transform.d.ts +2 -0
- package/dist/structo/datatypes/transforms/transform.js +13 -0
- package/dist/structo/datatypes/values/buffer.d.ts +2 -0
- package/dist/structo/datatypes/values/buffer.js +18 -0
- package/dist/structo/datatypes/values/byteliteral.d.ts +2 -0
- package/dist/structo/datatypes/values/byteliteral.js +20 -0
- package/dist/structo/datatypes/values/string.d.ts +2 -0
- package/dist/structo/datatypes/values/string.js +21 -0
- package/dist/structo/index.d.ts +4 -0
- package/dist/structo/index.js +3 -0
- package/dist/structo/read.d.ts +7 -0
- package/dist/structo/read.js +10 -0
- package/dist/structo/types.d.ts +18 -0
- package/dist/structo/types.js +1 -0
- package/dist/structo/write.d.ts +3 -0
- package/dist/structo/write.js +41 -0
- package/package.json +4 -4
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export function array(size, type) {
|
|
2
|
+
const { read: readType, write: writeType, size: typeSize } = type;
|
|
3
|
+
return {
|
|
4
|
+
size: type.size ? size * type.size : undefined,
|
|
5
|
+
write: (ctx, value) => {
|
|
6
|
+
if (value.length !== size)
|
|
7
|
+
throw new Error("Invalid Size");
|
|
8
|
+
if (typeSize)
|
|
9
|
+
ctx.alloc(size * typeSize);
|
|
10
|
+
for (let i = 0; i < size; i++) {
|
|
11
|
+
writeType(ctx, value[i]);
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
read: (ctx) => {
|
|
15
|
+
const arr = new Array(size);
|
|
16
|
+
for (let i = 0; i < size; i++) {
|
|
17
|
+
arr[i] = readType(ctx);
|
|
18
|
+
}
|
|
19
|
+
return arr;
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { InferInput, Serializer } from "../../types";
|
|
2
|
+
type InferObject<T> = T extends Record<string, Serializer<any>> ? {
|
|
3
|
+
[Key in keyof T]: InferInput<T[Key]>;
|
|
4
|
+
} : never;
|
|
5
|
+
export declare function fastObject<T extends Record<string, Serializer<any>>>(definition: T): Serializer<InferObject<T>>;
|
|
6
|
+
export {};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
const definitionSymbol = Symbol();
|
|
2
|
+
export function fastObject(definition) {
|
|
3
|
+
let serializers = [];
|
|
4
|
+
let writeBody = "";
|
|
5
|
+
let readBody = "";
|
|
6
|
+
function generateSerializers(serializer, keys) {
|
|
7
|
+
if (definitionSymbol in serializer) {
|
|
8
|
+
const definition = serializer[definitionSymbol];
|
|
9
|
+
readBody += `${keys[keys.length - 1]}: {`;
|
|
10
|
+
for (const key of Object.keys(definition)) {
|
|
11
|
+
generateSerializers(definition[key], [...keys, key]);
|
|
12
|
+
}
|
|
13
|
+
readBody += `},`;
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
let path = "";
|
|
17
|
+
for (const key of keys) {
|
|
18
|
+
if (key.match(/[a-zA-Z_][a-zA-Z0-9_]*/)) {
|
|
19
|
+
path += `.${key}`;
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
path += `[${JSON.stringify(key)}]`;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
let name = `s${Object.keys(serializers).length}`;
|
|
26
|
+
serializers.push([name, serializer]);
|
|
27
|
+
writeBody += `${name}(c, v${path});`;
|
|
28
|
+
readBody += `${keys[keys.length - 1]}: ${name}(c),`;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
for (const key of Object.keys(definition)) {
|
|
32
|
+
generateSerializers(definition[key], [key]);
|
|
33
|
+
}
|
|
34
|
+
const writeFactory = new Function(...serializers.map((v) => v[0]), `return (c, v) => {${writeBody}}`);
|
|
35
|
+
const readFactory = new Function(...serializers.map((v) => v[0]), `return (c, v) => ({${readBody}})`);
|
|
36
|
+
const write = writeFactory(...serializers.map((v) => v[1].write));
|
|
37
|
+
const read = readFactory(...serializers.map((v) => v[1].read));
|
|
38
|
+
let size = Object.values(definition).reduce((total, v) => total + v.size, 0);
|
|
39
|
+
return {
|
|
40
|
+
//@ts-ignore
|
|
41
|
+
[definitionSymbol]: definition,
|
|
42
|
+
size: isNaN(size) ? undefined : size,
|
|
43
|
+
write,
|
|
44
|
+
read,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export function list(options) {
|
|
2
|
+
const { read: readLength, write: writeLength } = options.length;
|
|
3
|
+
const { read: readType, write: writeType, size: sizeType } = options.type;
|
|
4
|
+
return {
|
|
5
|
+
write: (ctx, value) => {
|
|
6
|
+
writeLength(ctx, value.length);
|
|
7
|
+
if (sizeType)
|
|
8
|
+
ctx.alloc(value.length * sizeType);
|
|
9
|
+
for (const v of value) {
|
|
10
|
+
writeType(ctx, v);
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
read: (ctx) => {
|
|
14
|
+
const size = readLength(ctx);
|
|
15
|
+
const arr = new Array(size);
|
|
16
|
+
for (let i = 0; i < size; i++) {
|
|
17
|
+
arr[i] = readType(ctx);
|
|
18
|
+
}
|
|
19
|
+
return arr;
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { InferInput, InferOutput, Serializer } from "../../types";
|
|
2
|
+
type InferObjectInfer<T> = T extends Record<string, Serializer<any>> ? {
|
|
3
|
+
[Key in keyof T]: InferInput<T[Key]>;
|
|
4
|
+
} : never;
|
|
5
|
+
type InferObjectOutput<T> = T extends Record<string, Serializer<any>> ? {
|
|
6
|
+
[Key in keyof T]: InferOutput<T[Key]>;
|
|
7
|
+
} : never;
|
|
8
|
+
export declare function object<T extends Record<string, Serializer<any>>>(definition: T): Serializer<InferObjectInfer<T>, InferObjectOutput<T>>;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export function object(definition) {
|
|
2
|
+
const entires = Object.entries(definition);
|
|
3
|
+
// Use the fact: number + undefined = NaN
|
|
4
|
+
// Check for NaN afterwards
|
|
5
|
+
let computedSize = Object.values(definition).reduce((total, v) => total + v.size, 0);
|
|
6
|
+
const size = isNaN(computedSize) ? undefined : computedSize;
|
|
7
|
+
return {
|
|
8
|
+
size,
|
|
9
|
+
write: (ctx, value) => {
|
|
10
|
+
if (size)
|
|
11
|
+
ctx.alloc(size);
|
|
12
|
+
for (let i = 0; i < entires.length; i++) {
|
|
13
|
+
entires[i][1].write(ctx, value[entires[i][0]]);
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
read: (ctx) => {
|
|
17
|
+
const output = new Array(entires.length);
|
|
18
|
+
for (let i = 0; i < entires.length; i++) {
|
|
19
|
+
output[i] = [entires[i][0], entires[i][1].read(ctx)];
|
|
20
|
+
}
|
|
21
|
+
return Object.fromEntries(output);
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function sizedBuffer(length) {
|
|
2
|
+
return {
|
|
3
|
+
write: (ctx, value) => {
|
|
4
|
+
length.write(ctx, value.byteLength);
|
|
5
|
+
const bytes = new Uint8Array(value);
|
|
6
|
+
ctx.alloc(value.byteLength);
|
|
7
|
+
new Uint8Array(ctx.view.buffer).set(bytes, ctx.offset);
|
|
8
|
+
ctx.offset += value.byteLength;
|
|
9
|
+
},
|
|
10
|
+
read: (ctx) => {
|
|
11
|
+
const size = length.read(ctx);
|
|
12
|
+
const slice = ctx.buffer.slice(ctx.offset, ctx.offset + size);
|
|
13
|
+
ctx.offset += size;
|
|
14
|
+
return slice;
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export { u64Bigint, s64Bigint } from "./numbers/bigints";
|
|
2
|
+
export { f32, f64 } from "./numbers/floats";
|
|
3
|
+
export { s8, s16, s32, s64 } from "./numbers/sints";
|
|
4
|
+
export { u8, u16, u32, u64 } from "./numbers/uints";
|
|
5
|
+
export { array } from "./containers/array";
|
|
6
|
+
export { fastObject } from "./containers/fastObject";
|
|
7
|
+
export { object } from "./containers/object";
|
|
8
|
+
export { list } from "./containers/list";
|
|
9
|
+
export { sizedBuffer } from "./containers/sizedbuffer";
|
|
10
|
+
export { string } from "./values/string";
|
|
11
|
+
export { buffer } from "./values/buffer";
|
|
12
|
+
export { byteLiteral } from "./values/byteliteral";
|
|
13
|
+
export { type Transform as Pipeline, pipe } from "./transforms/pipe";
|
|
14
|
+
export { positionOffset } from "./transforms/readOffset";
|
|
15
|
+
export { transform } from "./transforms/transform";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export { u64Bigint, s64Bigint } from "./numbers/bigints";
|
|
2
|
+
export { f32, f64 } from "./numbers/floats";
|
|
3
|
+
export { s8, s16, s32, s64 } from "./numbers/sints";
|
|
4
|
+
export { u8, u16, u32, u64 } from "./numbers/uints";
|
|
5
|
+
export { array } from "./containers/array";
|
|
6
|
+
export { fastObject } from "./containers/fastObject";
|
|
7
|
+
export { object } from "./containers/object";
|
|
8
|
+
export { list } from "./containers/list";
|
|
9
|
+
export { sizedBuffer } from "./containers/sizedbuffer";
|
|
10
|
+
export { string } from "./values/string";
|
|
11
|
+
export { buffer } from "./values/buffer";
|
|
12
|
+
export { byteLiteral } from "./values/byteliteral";
|
|
13
|
+
export { pipe } from "./transforms/pipe";
|
|
14
|
+
export { positionOffset } from "./transforms/readOffset";
|
|
15
|
+
export { transform } from "./transforms/transform";
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const checkValue = (value, start, end) => {
|
|
2
|
+
if (value < start || value >= end) {
|
|
3
|
+
throw new Error("Out of Range");
|
|
4
|
+
}
|
|
5
|
+
};
|
|
6
|
+
export function u64Bigint(endian = "little") {
|
|
7
|
+
return {
|
|
8
|
+
size: 8,
|
|
9
|
+
write: (ctx, value) => {
|
|
10
|
+
checkValue(value, 0n, 2n ** 64n);
|
|
11
|
+
ctx.alloc(8);
|
|
12
|
+
ctx.view.setBigUint64(ctx.offset, BigInt(value), endian === "little");
|
|
13
|
+
ctx.offset += 8;
|
|
14
|
+
},
|
|
15
|
+
read: (ctx) => {
|
|
16
|
+
const value = ctx.view.getBigUint64(ctx.offset, endian === "little");
|
|
17
|
+
ctx.offset += 8;
|
|
18
|
+
return value;
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export function s64Bigint(endian = "little") {
|
|
23
|
+
return {
|
|
24
|
+
size: 8,
|
|
25
|
+
write: (ctx, value) => {
|
|
26
|
+
checkValue(value, -(2n ** 63n), 2n ** 63n);
|
|
27
|
+
ctx.alloc(8);
|
|
28
|
+
ctx.view.setBigInt64(ctx.offset, BigInt(value), endian === "little");
|
|
29
|
+
ctx.offset += 8;
|
|
30
|
+
},
|
|
31
|
+
read: (ctx) => {
|
|
32
|
+
const value = ctx.view.getBigInt64(ctx.offset, endian === "little");
|
|
33
|
+
ctx.offset += 8;
|
|
34
|
+
return value;
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export function f32(endian = "little") {
|
|
2
|
+
return {
|
|
3
|
+
size: 4,
|
|
4
|
+
write: (ctx, value) => {
|
|
5
|
+
ctx.alloc(4);
|
|
6
|
+
ctx.view.setFloat32(ctx.offset, value, endian === "little");
|
|
7
|
+
ctx.offset += 4;
|
|
8
|
+
},
|
|
9
|
+
read: (ctx) => {
|
|
10
|
+
const value = ctx.view.getFloat32(ctx.offset, endian === "little");
|
|
11
|
+
ctx.offset += 4;
|
|
12
|
+
return value;
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export function f64(endian = "little") {
|
|
17
|
+
return {
|
|
18
|
+
size: 8,
|
|
19
|
+
write: (ctx, value) => {
|
|
20
|
+
ctx.alloc(8);
|
|
21
|
+
ctx.view.setFloat64(ctx.offset, value, endian === "little");
|
|
22
|
+
ctx.offset += 8;
|
|
23
|
+
},
|
|
24
|
+
read: (ctx) => {
|
|
25
|
+
const value = ctx.view.getFloat64(ctx.offset, endian === "little");
|
|
26
|
+
ctx.offset += 8;
|
|
27
|
+
return value;
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Serializer } from "../../types";
|
|
2
|
+
export declare function s8(): Serializer<number>;
|
|
3
|
+
export declare function s16(endian?: "little" | "big"): Serializer<number>;
|
|
4
|
+
export declare function s32(endian?: "little" | "big"): Serializer<number>;
|
|
5
|
+
export declare function s64(endian?: "little" | "big"): Serializer<number>;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
const checkValue = (value, start, end) => {
|
|
2
|
+
if (!Number.isInteger(value)) {
|
|
3
|
+
throw new Error("Not Integer");
|
|
4
|
+
}
|
|
5
|
+
if (value < start || value >= end) {
|
|
6
|
+
throw new Error("Out of Range");
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
export function s8() {
|
|
10
|
+
return {
|
|
11
|
+
size: 1,
|
|
12
|
+
write: (ctx, value) => {
|
|
13
|
+
checkValue(value, -(2 ** 7), 2 ** 7);
|
|
14
|
+
ctx.alloc(1);
|
|
15
|
+
ctx.view.setInt8(ctx.offset, value);
|
|
16
|
+
ctx.offset += 1;
|
|
17
|
+
},
|
|
18
|
+
read: (ctx) => {
|
|
19
|
+
const value = ctx.view.getInt8(ctx.offset);
|
|
20
|
+
ctx.offset += 1;
|
|
21
|
+
return value;
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export function s16(endian = "little") {
|
|
26
|
+
return {
|
|
27
|
+
size: 2,
|
|
28
|
+
write: (ctx, value) => {
|
|
29
|
+
checkValue(value, -(2 ** 15), 2 ** 15);
|
|
30
|
+
ctx.alloc(2);
|
|
31
|
+
ctx.view.setInt16(ctx.offset, value, endian === "little");
|
|
32
|
+
ctx.offset += 2;
|
|
33
|
+
},
|
|
34
|
+
read: (ctx) => {
|
|
35
|
+
const value = ctx.view.getInt16(ctx.offset, endian === "little");
|
|
36
|
+
ctx.offset += 2;
|
|
37
|
+
return value;
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export function s32(endian = "little") {
|
|
42
|
+
return {
|
|
43
|
+
size: 4,
|
|
44
|
+
write: (ctx, value) => {
|
|
45
|
+
checkValue(value, -(2 ** 31), 2 ** 31);
|
|
46
|
+
ctx.alloc(4);
|
|
47
|
+
ctx.view.setInt32(ctx.offset, value, endian === "little");
|
|
48
|
+
ctx.offset += 4;
|
|
49
|
+
},
|
|
50
|
+
read: (ctx) => {
|
|
51
|
+
const value = ctx.view.getInt32(ctx.offset, endian === "little");
|
|
52
|
+
ctx.offset += 4;
|
|
53
|
+
return value;
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export function s64(endian = "little") {
|
|
58
|
+
return {
|
|
59
|
+
size: 8,
|
|
60
|
+
write: (ctx, value) => {
|
|
61
|
+
checkValue(value, -(2 ** 63), 2 ** 63);
|
|
62
|
+
ctx.alloc(8);
|
|
63
|
+
ctx.view.setBigInt64(ctx.offset, BigInt(value), endian === "little");
|
|
64
|
+
ctx.offset += 8;
|
|
65
|
+
},
|
|
66
|
+
read: (ctx) => {
|
|
67
|
+
const value = Number(ctx.view.getBigInt64(ctx.offset, endian === "little"));
|
|
68
|
+
ctx.offset += 8;
|
|
69
|
+
return value;
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Serializer } from "../../types";
|
|
2
|
+
export declare function u8(): Serializer<number>;
|
|
3
|
+
export declare function u16(endian?: "little" | "big"): Serializer<number>;
|
|
4
|
+
export declare function u32(endian?: "little" | "big"): Serializer<number>;
|
|
5
|
+
export declare function u64(endian?: "little" | "big"): Serializer<number>;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export function u8() {
|
|
2
|
+
return {
|
|
3
|
+
size: 1,
|
|
4
|
+
write: (ctx, value) => {
|
|
5
|
+
if (!Number.isInteger(value))
|
|
6
|
+
throw new Error("Not Integer");
|
|
7
|
+
if (value < 0 || value >= 2 ** 8)
|
|
8
|
+
throw new Error("Out of Range");
|
|
9
|
+
ctx.alloc(1);
|
|
10
|
+
ctx.view.setUint8(ctx.offset, value);
|
|
11
|
+
ctx.offset += 1;
|
|
12
|
+
},
|
|
13
|
+
read: (ctx) => {
|
|
14
|
+
const value = ctx.view.getUint8(ctx.offset);
|
|
15
|
+
ctx.offset += 1;
|
|
16
|
+
return value;
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export function u16(endian = "little") {
|
|
21
|
+
return {
|
|
22
|
+
size: 2,
|
|
23
|
+
write: (ctx, value) => {
|
|
24
|
+
if (!Number.isInteger(value))
|
|
25
|
+
throw new Error("Not Integer");
|
|
26
|
+
if (value < 0 || value >= 2 ** 16)
|
|
27
|
+
throw new Error("Out of Range");
|
|
28
|
+
ctx.alloc(2);
|
|
29
|
+
ctx.view.setUint16(ctx.offset, value, endian === "little");
|
|
30
|
+
ctx.offset += 2;
|
|
31
|
+
},
|
|
32
|
+
read: (ctx) => {
|
|
33
|
+
const value = ctx.view.getUint16(ctx.offset, endian === "little");
|
|
34
|
+
ctx.offset += 2;
|
|
35
|
+
return value;
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export function u32(endian = "little") {
|
|
40
|
+
return {
|
|
41
|
+
size: 4,
|
|
42
|
+
write: (ctx, value) => {
|
|
43
|
+
if (!Number.isInteger(value))
|
|
44
|
+
throw new Error("Not Integer");
|
|
45
|
+
if (value < 0 || value >= 2 ** 32)
|
|
46
|
+
throw new Error("Out of Range");
|
|
47
|
+
ctx.alloc(4);
|
|
48
|
+
ctx.view.setUint32(ctx.offset, value, endian === "little");
|
|
49
|
+
ctx.offset += 4;
|
|
50
|
+
},
|
|
51
|
+
read: (ctx) => {
|
|
52
|
+
const value = ctx.view.getUint32(ctx.offset, endian === "little");
|
|
53
|
+
ctx.offset += 4;
|
|
54
|
+
return value;
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export function u64(endian = "little") {
|
|
59
|
+
return {
|
|
60
|
+
size: 8,
|
|
61
|
+
write: (ctx, value) => {
|
|
62
|
+
if (!Number.isInteger(value))
|
|
63
|
+
throw new Error("Not Integer");
|
|
64
|
+
if (value < 0 || value >= 2 ** 64)
|
|
65
|
+
throw new Error("Out of Range");
|
|
66
|
+
ctx.alloc(8);
|
|
67
|
+
ctx.view.setBigUint64(ctx.offset, BigInt(value), endian === "little");
|
|
68
|
+
ctx.offset += 8;
|
|
69
|
+
},
|
|
70
|
+
read: (ctx) => {
|
|
71
|
+
const value = Number(ctx.view.getBigUint64(ctx.offset, endian === "little"));
|
|
72
|
+
ctx.offset += 8;
|
|
73
|
+
return value;
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Serializer } from "../../types";
|
|
2
|
+
export type Transform<T = any, TNext = T> = (type: Serializer<TNext>) => Serializer<T>;
|
|
3
|
+
export declare function pipe<TStart, T1>(type: Serializer<TStart>, p1: Transform<T1, TStart>): Serializer<T1>;
|
|
4
|
+
export declare function pipe<TStart, T1, T2>(type: Serializer<TStart>, p1: Transform<T1, TStart>, p2: Transform<T2, T1>): Serializer<T2>;
|
|
5
|
+
export declare function pipe<TStart, T1, T2, T3>(type: Serializer<TStart>, p1: Transform<T1, TStart>, p2: Transform<T2, T1>, p3: Transform<T3, T2>): Serializer<T3>;
|
|
6
|
+
export declare function pipe<TStart, T1, T2, T3, T4>(type: Serializer<TStart>, p1: Transform<T1, TStart>, p2: Transform<T2, T1>, p3: Transform<T3, T2>, p4: Transform<T4, T3>): Serializer<T4>;
|
|
7
|
+
export declare function pipe<TStart, T1, T2, T3, T4, T5>(type: Serializer<TStart>, p1: Transform<T1, TStart>, p2: Transform<T2, T1>, p3: Transform<T3, T2>, p4: Transform<T4, T3>, p5: Transform<T5, T4>): Serializer<T5>;
|
|
8
|
+
export declare function pipe<TStart, T1, T2, T3, T4, T5, T6>(type: Serializer<TStart>, p1: Transform<T1, TStart>, p2: Transform<T2, T1>, p3: Transform<T3, T2>, p4: Transform<T4, T3>, p5: Transform<T5, T6>): Serializer<T6>;
|
|
9
|
+
export declare function pipe<TStart, T1, T2, T3, T4, T5, T6, T7>(type: Serializer<TStart>, p1: Transform<T1, TStart>, p2: Transform<T2, T1>, p3: Transform<T3, T2>, p4: Transform<T4, T3>, p5: Transform<T5, T6>, p6: Transform<T6, T7>): Serializer<T7>;
|
|
10
|
+
export declare function pipe<TStart, T1, T2, T3, T4, T5, T6, T7, T8>(type: Serializer<TStart>, p1: Transform<T1, TStart>, p2: Transform<T2, T1>, p3: Transform<T3, T2>, p4: Transform<T4, T3>, p5: Transform<T5, T6>, p6: Transform<T6, T7>, p7: Transform<T7, T8>): Serializer<T8>;
|
|
11
|
+
export declare function pipe<TStart, T1, T2, T3, T4, T5, T6, T7, T8, T9>(type: Serializer<TStart>, p1: Transform<T1, TStart>, p2: Transform<T2, T1>, p3: Transform<T3, T2>, p4: Transform<T4, T3>, p5: Transform<T5, T6>, p6: Transform<T6, T7>, p7: Transform<T7, T8>, p8: Transform<T8, T9>): Serializer<T9>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function positionOffset(delta) {
|
|
2
|
+
return (type) => ({
|
|
3
|
+
size: type.size,
|
|
4
|
+
read: (ctx) => {
|
|
5
|
+
let start = ctx.offset;
|
|
6
|
+
ctx.offset += delta;
|
|
7
|
+
const value = type.read(ctx);
|
|
8
|
+
ctx.offset = start;
|
|
9
|
+
return value;
|
|
10
|
+
},
|
|
11
|
+
write: (ctx, value) => {
|
|
12
|
+
let start = ctx.offset;
|
|
13
|
+
ctx.offset += delta;
|
|
14
|
+
type.write(ctx, value);
|
|
15
|
+
ctx.offset = start;
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function transform(callback) {
|
|
2
|
+
return (type) => ({
|
|
3
|
+
size: type.size,
|
|
4
|
+
read: (ctx) => {
|
|
5
|
+
const value = type.read(ctx);
|
|
6
|
+
return callback(value);
|
|
7
|
+
},
|
|
8
|
+
write: (ctx, value) => {
|
|
9
|
+
let outValue = callback(value);
|
|
10
|
+
type.write(ctx, outValue);
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function buffer(size) {
|
|
2
|
+
return {
|
|
3
|
+
size,
|
|
4
|
+
write: (ctx, value) => {
|
|
5
|
+
const bytes = new Uint8Array(value);
|
|
6
|
+
if (bytes.length !== size)
|
|
7
|
+
throw new Error("Invalid Length");
|
|
8
|
+
ctx.alloc(size);
|
|
9
|
+
new Uint8Array(ctx.buffer).set(bytes, ctx.offset);
|
|
10
|
+
ctx.offset += size;
|
|
11
|
+
},
|
|
12
|
+
read: (ctx) => {
|
|
13
|
+
const slice = ctx.buffer.slice(ctx.offset, ctx.offset + size);
|
|
14
|
+
ctx.offset += size;
|
|
15
|
+
return slice;
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export function byteLiteral(bytes) {
|
|
2
|
+
const length = bytes.length;
|
|
3
|
+
return {
|
|
4
|
+
size: bytes.length,
|
|
5
|
+
read: (ctx) => {
|
|
6
|
+
const arr = new Uint8Array(ctx.view.buffer);
|
|
7
|
+
for (let i = 0; i < length; i++) {
|
|
8
|
+
if (arr[ctx.offset + i] !== bytes[i]) {
|
|
9
|
+
throw new Error("Invalid Value");
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
ctx.offset += length;
|
|
13
|
+
return bytes;
|
|
14
|
+
},
|
|
15
|
+
write(ctx) {
|
|
16
|
+
new Uint8Array(ctx.view.buffer).set(bytes, ctx.offset);
|
|
17
|
+
ctx.offset += length;
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export function string(length) {
|
|
2
|
+
const { read: readLength, write: writeLength } = length;
|
|
3
|
+
const encoder = new TextEncoder();
|
|
4
|
+
const decoder = new TextDecoder();
|
|
5
|
+
return {
|
|
6
|
+
write: (ctx, value) => {
|
|
7
|
+
const bytes = encoder.encode(value);
|
|
8
|
+
writeLength(ctx, bytes.byteLength);
|
|
9
|
+
ctx.alloc(bytes.byteLength);
|
|
10
|
+
const arr = new Uint8Array(ctx.view.buffer);
|
|
11
|
+
arr.set(bytes, ctx.offset);
|
|
12
|
+
ctx.offset += bytes.byteLength;
|
|
13
|
+
},
|
|
14
|
+
read: (ctx) => {
|
|
15
|
+
const length = readLength(ctx);
|
|
16
|
+
const section = ctx.buffer.slice(ctx.offset, ctx.offset + length);
|
|
17
|
+
ctx.offset += length;
|
|
18
|
+
return decoder.decode(section);
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Serializer } from "./types";
|
|
2
|
+
export declare function read<T>(serializer: Serializer<T>, buffer: ArrayBuffer): T;
|
|
3
|
+
export declare function createReaderContext(buffer: ArrayBuffer): {
|
|
4
|
+
offset: number;
|
|
5
|
+
buffer: ArrayBuffer;
|
|
6
|
+
view: DataView<ArrayBuffer>;
|
|
7
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type Serializer<TIn, TOut = TIn> = {
|
|
2
|
+
size?: number | undefined;
|
|
3
|
+
write: (ctx: WriterContext, value: TIn) => void;
|
|
4
|
+
read: (ctx: ReaderContext) => TOut;
|
|
5
|
+
};
|
|
6
|
+
export interface WriterContext {
|
|
7
|
+
buffer: ArrayBuffer;
|
|
8
|
+
view: DataView;
|
|
9
|
+
offset: number;
|
|
10
|
+
alloc: (length: number) => void;
|
|
11
|
+
}
|
|
12
|
+
export interface ReaderContext {
|
|
13
|
+
buffer: ArrayBuffer;
|
|
14
|
+
view: DataView;
|
|
15
|
+
offset: number;
|
|
16
|
+
}
|
|
17
|
+
export type InferInput<T> = T extends Serializer<infer V> ? V : never;
|
|
18
|
+
export type InferOutput<T> = T extends Serializer<any, infer V> ? V : never;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export function write(serializer, value) {
|
|
2
|
+
const ctx = createdWriterContext(serializer);
|
|
3
|
+
serializer.write(ctx, value);
|
|
4
|
+
if (ctx.buffer.byteLength === ctx.offset) {
|
|
5
|
+
return ctx.buffer;
|
|
6
|
+
}
|
|
7
|
+
else {
|
|
8
|
+
return ctx.buffer.transfer(ctx.offset);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function createdWriterContext(type) {
|
|
12
|
+
if (type.size) {
|
|
13
|
+
let buffer = new ArrayBuffer(type.size);
|
|
14
|
+
const view = new DataView(buffer);
|
|
15
|
+
return {
|
|
16
|
+
offset: 0,
|
|
17
|
+
buffer,
|
|
18
|
+
view,
|
|
19
|
+
alloc: Function.prototype,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
let bufferLength = 64;
|
|
24
|
+
let buffer = new ArrayBuffer(bufferLength);
|
|
25
|
+
const view = new DataView(buffer);
|
|
26
|
+
return {
|
|
27
|
+
offset: 0,
|
|
28
|
+
buffer,
|
|
29
|
+
view,
|
|
30
|
+
alloc(length) {
|
|
31
|
+
if (length < 0)
|
|
32
|
+
return;
|
|
33
|
+
while (this.offset + length >= bufferLength) {
|
|
34
|
+
bufferLength = this.buffer.byteLength * 2;
|
|
35
|
+
this.buffer = this.buffer.transfer(bufferLength);
|
|
36
|
+
this.view = new DataView(this.buffer);
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "A library for serializing and deserializing binary content",
|
|
4
4
|
"keywords": ["binary", "library", "utility", "web", "node"],
|
|
5
5
|
"license": "ISC",
|
|
6
|
-
"version": "1.0.
|
|
6
|
+
"version": "1.0.2",
|
|
7
7
|
"author": "Ben Brady",
|
|
8
8
|
"private": false,
|
|
9
9
|
"publishConfig": {"access": "public"},
|
|
@@ -34,9 +34,9 @@
|
|
|
34
34
|
"files": [
|
|
35
35
|
"LICENSE",
|
|
36
36
|
"README.md",
|
|
37
|
-
"./dist
|
|
38
|
-
"./dist
|
|
39
|
-
"./dist
|
|
37
|
+
"./dist/**/*.d.ts",
|
|
38
|
+
"./dist/**/*.js.map",
|
|
39
|
+
"./dist/**/*.js"
|
|
40
40
|
],
|
|
41
41
|
|
|
42
42
|
"scripts": {
|