@nnilky/structo 1.0.9 → 1.1.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/README.md +4 -4
- package/dist/datatypes/containers/array.js +9 -12
- package/dist/datatypes/containers/exhuastiveArray.js +6 -6
- package/dist/datatypes/containers/list.js +7 -7
- package/dist/datatypes/containers/object.js +9 -8
- package/dist/datatypes/numbers/bigints.js +2 -2
- package/dist/datatypes/numbers/floats.js +12 -9
- package/dist/datatypes/numbers/sints.js +13 -10
- package/dist/datatypes/numbers/uints.js +13 -10
- package/dist/datatypes/values/bytes.d.ts +2 -2
- package/dist/datatypes/values/bytes.js +6 -6
- package/dist/datatypes/values/bytes.test.js +2 -2
- package/dist/datatypes/values/sizedbytes.d.ts +1 -1
- package/dist/datatypes/values/sizedbytes.js +3 -4
- package/dist/datatypes/values/sizedbytes.test.js +1 -1
- package/dist/datatypes/values/string.js +2 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/read.d.ts +2 -3
- package/dist/read.js +10 -12
- package/dist/transforms/enum.d.ts +1 -1
- package/dist/transforms/literal.d.ts +1 -1
- package/dist/transforms/toAscii.d.ts +1 -1
- package/dist/transforms/toAscii.js +2 -2
- package/dist/transforms/toBase64.d.ts +1 -1
- package/dist/transforms/toBase64.js +2 -2
- package/dist/transforms/toBytes.d.ts +1 -1
- package/dist/transforms/toBytes.js +2 -2
- package/dist/transforms/toHex.d.ts +3 -3
- package/dist/transforms/toHex.js +4 -4
- package/dist/transforms/toTypedArray.d.ts +11 -6
- package/dist/transforms/toTypedArray.js +10 -5
- package/dist/transforms/toTypedArray.test.js +18 -9
- package/dist/types.d.ts +11 -9
- package/dist/utilities/remember.d.ts +1 -1
- package/dist/utilities/remember.js +3 -3
- package/dist/utils.test.d.ts +1 -1
- package/dist/utils.test.js +1 -3
- package/dist/write.d.ts +2 -2
- package/dist/write.js +47 -34
- package/package.json +7 -2
- package/dist/datatypes/containers/sizedbytes.d.ts +0 -2
- package/dist/datatypes/containers/sizedbytes.js +0 -17
- package/dist/datatypes/containers/sizedbytes.test.d.ts +0 -1
- package/dist/datatypes/containers/sizedbytes.test.js +0 -27
- package/dist/datatypes/containers/string.d.ts +0 -2
- package/dist/datatypes/containers/string.js +0 -24
- package/dist/datatypes/containers/string.test.d.ts +0 -1
- package/dist/datatypes/containers/string.test.js +0 -24
- package/dist/datatypes/transforms/encode.d.ts +0 -2
- package/dist/datatypes/transforms/encode.js +0 -7
- package/dist/datatypes/transforms/fixedOffset.d.ts +0 -2
- package/dist/datatypes/transforms/fixedOffset.js +0 -18
- package/dist/datatypes/transforms/modify.d.ts +0 -2
- package/dist/datatypes/transforms/modify.js +0 -7
- package/dist/datatypes/transforms/noAdvance.d.ts +0 -16
- package/dist/datatypes/transforms/noAdvance.js +0 -30
- package/dist/datatypes/transforms/pipe.d.ts +0 -11
- package/dist/datatypes/transforms/pipe.js +0 -16
- package/dist/datatypes/utilities/remember.d.ts +0 -15
- package/dist/datatypes/utilities/remember.js +0 -36
- package/dist/datatypes/utilities/remember.test.d.ts +0 -1
- package/dist/datatypes/utilities/remember.test.js +0 -44
- package/dist/datatypes/utils.test.d.ts +0 -8
- package/dist/datatypes/utils.test.js +0 -37
- package/dist/datatypes/values/byteliteral.d.ts +0 -2
- package/dist/datatypes/values/byteliteral.js +0 -20
- package/dist/datatypes/values/json.d.ts +0 -10
- package/dist/datatypes/values/json.js +0 -21
- package/dist/transforms/fixedOffset.d.ts +0 -2
- package/dist/transforms/fixedOffset.js +0 -18
- package/dist/transforms/noAdvance.d.ts +0 -16
- package/dist/transforms/noAdvance.js +0 -30
- package/dist/transforms/noAdvance.test.d.ts +0 -1
- package/dist/transforms/noAdvance.test.js +0 -17
package/dist/transforms/toHex.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { encode } from "./encode.js";
|
|
2
2
|
/**
|
|
3
|
-
* Converts an
|
|
3
|
+
* Converts an Uint8Array to uppercase hex
|
|
4
4
|
*
|
|
5
5
|
* ```ts
|
|
6
6
|
* st.pipe(
|
|
@@ -9,11 +9,11 @@ import { encode } from "./encode.js";
|
|
|
9
9
|
* )
|
|
10
10
|
* ```
|
|
11
11
|
*
|
|
12
|
-
* `
|
|
12
|
+
* `Uint8Array([0, 255, 0])` => `00FF00`
|
|
13
13
|
*/
|
|
14
14
|
export function toHex() {
|
|
15
15
|
return encode({
|
|
16
|
-
encode: (v) => Uint8Array.fromHex(v)
|
|
17
|
-
decode: (v) =>
|
|
16
|
+
encode: (v) => Uint8Array.fromHex(v),
|
|
17
|
+
decode: (v) => v.toHex().toUpperCase(),
|
|
18
18
|
});
|
|
19
19
|
}
|
|
@@ -1,16 +1,21 @@
|
|
|
1
|
-
type
|
|
2
|
-
buffer: ArrayBuffer;
|
|
1
|
+
type TypedArrayLike = {
|
|
2
|
+
buffer: ArrayBuffer | SharedArrayBuffer;
|
|
3
|
+
byteOffset: number;
|
|
4
|
+
byteLength: number;
|
|
5
|
+
BYTES_PER_ELEMENT: number;
|
|
3
6
|
};
|
|
4
|
-
type
|
|
7
|
+
type TypedArray<T extends TypedArrayLike> = {
|
|
8
|
+
BYTES_PER_ELEMENT: number;
|
|
9
|
+
} & (new (array: ArrayBuffer | SharedArrayBuffer, offset?: number, length?: number) => T);
|
|
5
10
|
/**
|
|
6
|
-
* Converts
|
|
11
|
+
* Converts a `Uint8Array` into the provided `TypedArray`, etc Float64Arrayt
|
|
7
12
|
*
|
|
8
13
|
* ```
|
|
9
14
|
* st.pipe(
|
|
10
15
|
* st.bytes(16),
|
|
11
|
-
* toTypedArray(
|
|
16
|
+
* toTypedArray(Float32Array),
|
|
12
17
|
* )
|
|
13
18
|
* ```
|
|
14
19
|
*/
|
|
15
|
-
export declare function toTypedArray<T extends
|
|
20
|
+
export declare function toTypedArray<T extends TypedArrayLike>(Array: TypedArray<T>): import("./pipe.ts").Transform<T, Uint8Array<ArrayBufferLike>>;
|
|
16
21
|
export {};
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import { encode } from "./encode.js";
|
|
2
2
|
/**
|
|
3
|
-
* Converts
|
|
3
|
+
* Converts a `Uint8Array` into the provided `TypedArray`, etc Float64Arrayt
|
|
4
4
|
*
|
|
5
5
|
* ```
|
|
6
6
|
* st.pipe(
|
|
7
7
|
* st.bytes(16),
|
|
8
|
-
* toTypedArray(
|
|
8
|
+
* toTypedArray(Float32Array),
|
|
9
9
|
* )
|
|
10
10
|
* ```
|
|
11
11
|
*/
|
|
12
|
-
export function toTypedArray(
|
|
12
|
+
export function toTypedArray(Array) {
|
|
13
13
|
return encode({
|
|
14
|
-
encode: (
|
|
15
|
-
decode: (
|
|
14
|
+
encode: (arr) => new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength / Uint8Array.BYTES_PER_ELEMENT),
|
|
15
|
+
decode: (bytes) => {
|
|
16
|
+
if (bytes.byteLength % Array.BYTES_PER_ELEMENT !== 0) {
|
|
17
|
+
throw new Error(`Provided a ${bytes.byteLength} buffer to a TypedArray that uses ${bytes.BYTES_PER_ELEMENT} bytes per element`);
|
|
18
|
+
}
|
|
19
|
+
return new Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / Array.BYTES_PER_ELEMENT);
|
|
20
|
+
},
|
|
16
21
|
});
|
|
17
22
|
}
|
|
@@ -1,23 +1,32 @@
|
|
|
1
1
|
import { describe, it } from "bun:test";
|
|
2
2
|
import { encodeTest, encodeSnapshotTest, expectError } from "../utils.test.js";
|
|
3
3
|
import * as st from "../index.js";
|
|
4
|
-
describe("st.
|
|
4
|
+
describe("st.toTypedArray", () => {
|
|
5
5
|
it("encode correctly", () => {
|
|
6
6
|
encodeTest(st.pipe(st.bytes(6), //
|
|
7
7
|
st.toTypedArray(Uint8Array)), new Uint8Array([1, 2, 3, 4, 5, 6]));
|
|
8
8
|
});
|
|
9
9
|
it("encode different types correctly", () => {
|
|
10
|
-
encodeTest(st.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
st.
|
|
10
|
+
encodeTest(st.object({
|
|
11
|
+
padding: st.u64(),
|
|
12
|
+
data: st.pipe(st.bytes(3), //
|
|
13
|
+
st.toTypedArray(Uint8Array)),
|
|
14
|
+
}), { padding: 0, data: new Uint8Array([1, 2, 3]) });
|
|
15
|
+
encodeTest(st.object({
|
|
16
|
+
padding: st.u64(),
|
|
17
|
+
data: st.pipe(st.bytes(5 * 2), //
|
|
18
|
+
st.toTypedArray(Uint16Array)),
|
|
19
|
+
}), { padding: 0, data: new Uint16Array([1, 2, 3, 63, 74]) });
|
|
20
|
+
encodeTest(st.object({
|
|
21
|
+
padding: st.u64(),
|
|
22
|
+
data: st.pipe(st.bytes(3 * 8), //
|
|
23
|
+
st.toTypedArray(Float64Array)),
|
|
24
|
+
}), { padding: 0, data: new Float64Array([Math.random(), Math.random(), Math.random()]) });
|
|
16
25
|
});
|
|
17
|
-
it("errors
|
|
26
|
+
it("errors when non-standard size", () => {
|
|
18
27
|
expectError(() => {
|
|
19
28
|
st.write(st.pipe(st.bytes(3), //
|
|
20
|
-
st.toTypedArray(Uint16Array)), new Uint16Array([1]));
|
|
29
|
+
st.toTypedArray(Uint16Array)), new Uint16Array([1, 2]));
|
|
21
30
|
});
|
|
22
31
|
});
|
|
23
32
|
it("snapshot tests", () => {
|
package/dist/types.d.ts
CHANGED
|
@@ -4,18 +4,20 @@ export type Serializer<TIn, TOut = TIn> = {
|
|
|
4
4
|
read: (ctx: ReaderContext) => TOut;
|
|
5
5
|
};
|
|
6
6
|
export type SerializationContext = WriterContext | ReaderContext;
|
|
7
|
-
export interface WriterContext {
|
|
8
|
-
stack: string[];
|
|
9
|
-
buffer: ArrayBuffer;
|
|
10
|
-
view: DataView;
|
|
7
|
+
export interface WriterContext<TBuffer extends ArrayBuffer | SharedArrayBuffer = ArrayBuffer | SharedArrayBuffer> {
|
|
11
8
|
offset: number;
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
export interface ReaderContext {
|
|
15
|
-
stack: string[];
|
|
16
|
-
buffer: ArrayBuffer;
|
|
9
|
+
buffer: TBuffer;
|
|
17
10
|
view: DataView;
|
|
11
|
+
bytes: Uint8Array;
|
|
12
|
+
path: string[];
|
|
13
|
+
reserve: (length: number) => void;
|
|
14
|
+
}
|
|
15
|
+
export interface ReaderContext<TBuffer extends ArrayBuffer | SharedArrayBuffer = ArrayBuffer | SharedArrayBuffer> {
|
|
18
16
|
offset: number;
|
|
17
|
+
buffer: TBuffer;
|
|
18
|
+
view: DataView;
|
|
19
|
+
bytes: Uint8Array;
|
|
20
|
+
path: string[];
|
|
19
21
|
}
|
|
20
22
|
export type InferInput<T> = T extends Serializer<infer V> ? V : never;
|
|
21
23
|
export type InferOutput<T> = T extends Serializer<any, infer V> ? V : never;
|
|
@@ -5,7 +5,7 @@ import type { Serializer } from "../types.js";
|
|
|
5
5
|
* This is useful for checksums and other values calculated from a writen value
|
|
6
6
|
*
|
|
7
7
|
* ```
|
|
8
|
-
* const data = st.createRememberedValue<
|
|
8
|
+
* const data = st.createRememberedValue<Uint8Array>()
|
|
9
9
|
* st.object({
|
|
10
10
|
* data: data.save(st.bytes(1024))
|
|
11
11
|
* checksum: crc32(data.load())
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This is useful for checksums and other values calculated from a writen value
|
|
5
5
|
*
|
|
6
6
|
* ```
|
|
7
|
-
* const data = st.createRememberedValue<
|
|
7
|
+
* const data = st.createRememberedValue<Uint8Array>()
|
|
8
8
|
* st.object({
|
|
9
9
|
* data: data.save(st.bytes(1024))
|
|
10
10
|
* checksum: crc32(data.load())
|
|
@@ -18,7 +18,7 @@ export function createRememberedValue() {
|
|
|
18
18
|
*
|
|
19
19
|
* ---
|
|
20
20
|
* ```
|
|
21
|
-
* const data = st.createRememberedValue<
|
|
21
|
+
* const data = st.createRememberedValue<Uint8Array>()
|
|
22
22
|
* st.object({
|
|
23
23
|
* data: data.save(st.bytes(1024))
|
|
24
24
|
* checksum: crc32(data.load())
|
|
@@ -50,7 +50,7 @@ export function createRememberedValue() {
|
|
|
50
50
|
*
|
|
51
51
|
* ---
|
|
52
52
|
* ```
|
|
53
|
-
* const data = st.createRememberedValue<
|
|
53
|
+
* const data = st.createRememberedValue<Uint8Array>()
|
|
54
54
|
* st.object({
|
|
55
55
|
* data: data.save(st.bytes(1024))
|
|
56
56
|
* checksum: crc32(data.load())
|
package/dist/utils.test.d.ts
CHANGED
|
@@ -6,4 +6,4 @@ export declare const encodeFailTest: <TIn, TOut>(serializer: st.Serializer<TIn,
|
|
|
6
6
|
export declare const expectEncodeSize: <TIn, TOut>(serializer: st.Serializer<TIn, TOut>, size: number, value: TIn) => void;
|
|
7
7
|
export declare const encodeSnapshotTest: <T>(serializer: st.Serializer<T>, value: T) => void;
|
|
8
8
|
export declare const expectError: (callback: () => void) => void;
|
|
9
|
-
export declare const bytes: (bytes: number[]) => ArrayBuffer
|
|
9
|
+
export declare const bytes: (bytes: number[]) => Uint8Array<ArrayBuffer>;
|
package/dist/utils.test.js
CHANGED
package/dist/write.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Serializer } from "./types.js";
|
|
2
2
|
export declare function write<TIn, TOut>(serializer: Serializer<TIn, TOut>, value: TIn): ArrayBuffer;
|
|
3
|
-
export declare function
|
|
3
|
+
export declare function writeInto<TIn, TOut, TBuffer extends ArrayBuffer | SharedArrayBuffer>(buffer: TBuffer, offset: number, serializer: Serializer<TIn, TOut>, value: TIn): void;
|
package/dist/write.js
CHANGED
|
@@ -1,49 +1,62 @@
|
|
|
1
1
|
export function write(serializer, value) {
|
|
2
|
-
|
|
2
|
+
let byteLength = serializer.size ?? 4096;
|
|
3
|
+
let buffer_ = new ArrayBuffer(byteLength);
|
|
4
|
+
let ctx = {
|
|
5
|
+
path: [],
|
|
6
|
+
offset: 0,
|
|
7
|
+
buffer: buffer_,
|
|
8
|
+
bytes: new Uint8Array(buffer_),
|
|
9
|
+
view: new DataView(buffer_),
|
|
10
|
+
reserve: (length) => {
|
|
11
|
+
if (length <= 0)
|
|
12
|
+
return;
|
|
13
|
+
while (ctx.offset + length > byteLength) {
|
|
14
|
+
byteLength *= 2;
|
|
15
|
+
ctx.buffer = ctx.buffer.transfer(byteLength);
|
|
16
|
+
ctx.view = new DataView(ctx.buffer);
|
|
17
|
+
ctx.bytes = new Uint8Array(ctx.buffer);
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
if (serializer.size) {
|
|
22
|
+
ctx.reserve = (length) => {
|
|
23
|
+
if (ctx.offset + length > byteLength) {
|
|
24
|
+
throw new Error("Attempted to allocate space when writing into buffer");
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
3
28
|
try {
|
|
4
29
|
serializer.write(ctx, value);
|
|
5
30
|
}
|
|
6
31
|
catch (e) {
|
|
7
|
-
const path = ctx.
|
|
8
|
-
throw new Error(`Serialization error at
|
|
32
|
+
const path = ctx.path.length === 0 ? "root" : "value" + ctx.path.join("");
|
|
33
|
+
throw new Error(`Serialization error at ${path}`, { cause: e });
|
|
9
34
|
}
|
|
10
35
|
if (ctx.buffer.byteLength === ctx.offset) {
|
|
11
36
|
return ctx.buffer;
|
|
12
37
|
}
|
|
13
38
|
else {
|
|
14
|
-
return ctx.buffer.
|
|
39
|
+
return ctx.buffer.transferToFixedLength(ctx.offset);
|
|
15
40
|
}
|
|
16
41
|
}
|
|
17
|
-
export function
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
42
|
+
export function writeInto(buffer, offset, serializer, value) {
|
|
43
|
+
let ctx = {
|
|
44
|
+
path: [],
|
|
45
|
+
offset: offset,
|
|
46
|
+
buffer: buffer,
|
|
47
|
+
bytes: new Uint8Array(buffer),
|
|
48
|
+
view: new DataView(buffer),
|
|
49
|
+
reserve(length) {
|
|
50
|
+
if (ctx.offset + length > ctx.buffer.byteLength) {
|
|
51
|
+
throw new Error("Attempted to allocate space when writing into buffer");
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
try {
|
|
56
|
+
serializer.write(ctx, value);
|
|
28
57
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const view = new DataView(buffer);
|
|
33
|
-
return {
|
|
34
|
-
stack: [],
|
|
35
|
-
offset: 0,
|
|
36
|
-
buffer,
|
|
37
|
-
view,
|
|
38
|
-
alloc(length) {
|
|
39
|
-
if (length < 0)
|
|
40
|
-
return;
|
|
41
|
-
while (this.offset + length >= bufferLength) {
|
|
42
|
-
bufferLength = this.buffer.byteLength * 2;
|
|
43
|
-
this.buffer = this.buffer.transfer(bufferLength);
|
|
44
|
-
this.view = new DataView(this.buffer);
|
|
45
|
-
}
|
|
46
|
-
},
|
|
47
|
-
};
|
|
58
|
+
catch (e) {
|
|
59
|
+
const path = ctx.path.join("") ?? "root";
|
|
60
|
+
throw new Error(`Serialization error at value${path}`, { cause: e });
|
|
48
61
|
}
|
|
49
62
|
}
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"node"
|
|
10
10
|
],
|
|
11
11
|
"license": "ISC",
|
|
12
|
-
"version": "1.0
|
|
12
|
+
"version": "1.1.0",
|
|
13
13
|
"author": "Ben Brady",
|
|
14
14
|
"private": false,
|
|
15
15
|
"publishConfig": {
|
|
@@ -49,13 +49,18 @@
|
|
|
49
49
|
"@types/node": "^25.9.2",
|
|
50
50
|
"bun-types": "^1.3.14",
|
|
51
51
|
"jest": "^30.4.2",
|
|
52
|
+
"tsx": "^4.22.4",
|
|
52
53
|
"typescript": "^6.0.3"
|
|
53
54
|
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"@mitata/counters": "^0.0.8",
|
|
57
|
+
"mitata": "^1.0.34"
|
|
58
|
+
},
|
|
54
59
|
"scripts": {
|
|
55
60
|
"build": "tsc",
|
|
56
61
|
"prepublish": "tsc",
|
|
57
62
|
"check": "tsc --noEmit",
|
|
58
|
-
"test": "bun test src
|
|
63
|
+
"test": "bun test src ",
|
|
59
64
|
"test:coverage": "bun test src --only-failures --coverage"
|
|
60
65
|
}
|
|
61
66
|
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export function sizedBytes(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
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { describe, it } from "bun:test";
|
|
2
|
-
import { bytes, expectEncode, expectError } from "../utils.test";
|
|
3
|
-
import * as st from "../../index";
|
|
4
|
-
describe("st.sizedBytes", () => {
|
|
5
|
-
it("encode correctly", () => {
|
|
6
|
-
const buffer = st.sizedBytes(st.u8());
|
|
7
|
-
expectEncode(buffer, bytes([1, 2]));
|
|
8
|
-
});
|
|
9
|
-
it("encodes empty correctly", () => {
|
|
10
|
-
const spec = st.sizedBytes(st.u8());
|
|
11
|
-
expectEncode(spec, bytes([]));
|
|
12
|
-
});
|
|
13
|
-
it("holds large data", () => {
|
|
14
|
-
const size = 1024 * 1024 * 8; // 8MB
|
|
15
|
-
const spec = st.sizedBytes(st.u32());
|
|
16
|
-
const data = new Uint8Array(size);
|
|
17
|
-
data.set([3, 4], 1000);
|
|
18
|
-
data.set([3, 4], 2000);
|
|
19
|
-
expectEncode(spec, data.buffer);
|
|
20
|
-
});
|
|
21
|
-
it("errors on invalid length", () => {
|
|
22
|
-
const spec = st.sizedBytes(st.u8());
|
|
23
|
-
expectError(() => {
|
|
24
|
-
st.write(spec, bytes(Array.from({ length: 256 }, () => 0)));
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
});
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
export function string(length) {
|
|
2
|
-
const encoder = new TextEncoder();
|
|
3
|
-
const decoder = new TextDecoder();
|
|
4
|
-
const lengthSize = length.size ?? 0;
|
|
5
|
-
return {
|
|
6
|
-
write: (ctx, value) => {
|
|
7
|
-
if (typeof value !== "string")
|
|
8
|
-
throw new Error("Expected String to encoder");
|
|
9
|
-
const bytes = encoder.encode(value);
|
|
10
|
-
const size = bytes.byteLength;
|
|
11
|
-
ctx.alloc(size + lengthSize);
|
|
12
|
-
length.write(ctx, size);
|
|
13
|
-
const arr = new Uint8Array(ctx.buffer, ctx.offset);
|
|
14
|
-
arr.set(bytes);
|
|
15
|
-
ctx.offset += size;
|
|
16
|
-
},
|
|
17
|
-
read: (ctx) => {
|
|
18
|
-
const size = length.read(ctx);
|
|
19
|
-
const section = ctx.buffer.slice(ctx.offset, ctx.offset + size);
|
|
20
|
-
ctx.offset += size;
|
|
21
|
-
return decoder.decode(section);
|
|
22
|
-
},
|
|
23
|
-
};
|
|
24
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { describe, it } from "bun:test";
|
|
2
|
-
import { expectEncode, expectError } from "../utils.test";
|
|
3
|
-
import * as st from "../../index";
|
|
4
|
-
describe("st.string", () => {
|
|
5
|
-
const string_u8 = st.string(st.u8());
|
|
6
|
-
const string_u32 = st.string(st.u32());
|
|
7
|
-
it("encode correctly", () => {
|
|
8
|
-
expectEncode(string_u8, "foo");
|
|
9
|
-
});
|
|
10
|
-
it("works on empty strings", () => {
|
|
11
|
-
expectEncode(string_u32, "");
|
|
12
|
-
});
|
|
13
|
-
it("errors on numbers", () => {
|
|
14
|
-
expectError(() => {
|
|
15
|
-
//@ts-expect-error, intentional mistake
|
|
16
|
-
st.write(st.string(st.u8()), 8);
|
|
17
|
-
});
|
|
18
|
-
});
|
|
19
|
-
it("errors on too long strings", () => {
|
|
20
|
-
expectError(() => {
|
|
21
|
-
st.write(string_u8, "A".repeat(256));
|
|
22
|
-
});
|
|
23
|
-
});
|
|
24
|
-
});
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export function fixedOffset(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
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { Serializer } from "../../types";
|
|
2
|
-
/**
|
|
3
|
-
* Whilst reading this type, don't advance the offset after reading
|
|
4
|
-
*
|
|
5
|
-
* This can be useful for taggedUnions where they key is the first value in all the variants
|
|
6
|
-
*
|
|
7
|
-
* ```
|
|
8
|
-
* st.object({
|
|
9
|
-
* stringLength: st.pipe(
|
|
10
|
-
* st.u16(),
|
|
11
|
-
* st.noAdvance(),
|
|
12
|
-
* ),
|
|
13
|
-
* text: st.string(st.u16()),
|
|
14
|
-
* })
|
|
15
|
-
*/
|
|
16
|
-
export declare function noAdvance<T>(): (type: Serializer<T>) => Serializer<T>;
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Whilst reading this type, don't advance the offset after reading
|
|
3
|
-
*
|
|
4
|
-
* This can be useful for taggedUnions where they key is the first value in all the variants
|
|
5
|
-
*
|
|
6
|
-
* ```
|
|
7
|
-
* st.object({
|
|
8
|
-
* stringLength: st.pipe(
|
|
9
|
-
* st.u16(),
|
|
10
|
-
* st.noAdvance(),
|
|
11
|
-
* ),
|
|
12
|
-
* text: st.string(st.u16()),
|
|
13
|
-
* })
|
|
14
|
-
*/
|
|
15
|
-
export function noAdvance() {
|
|
16
|
-
return (type) => ({
|
|
17
|
-
size: type.size,
|
|
18
|
-
read: (ctx) => {
|
|
19
|
-
let start = ctx.offset;
|
|
20
|
-
const value = type.read(ctx);
|
|
21
|
-
ctx.offset = start;
|
|
22
|
-
return value;
|
|
23
|
-
},
|
|
24
|
-
write: (ctx, value) => {
|
|
25
|
-
let start = ctx.offset;
|
|
26
|
-
type.write(ctx, value);
|
|
27
|
-
ctx.offset = start;
|
|
28
|
-
},
|
|
29
|
-
});
|
|
30
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
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>;
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pipe lets you chain modification functions together
|
|
3
|
-
* ```
|
|
4
|
-
* st.object({
|
|
5
|
-
* age: st.u32(),
|
|
6
|
-
* ageInMonths: st.pipe(
|
|
7
|
-
* st.u32(),
|
|
8
|
-
* st.modify(v => v * 12),
|
|
9
|
-
* st.offset(-8),
|
|
10
|
-
* )})
|
|
11
|
-
* ```
|
|
12
|
-
*/
|
|
13
|
-
export function pipe(type, ...pipeline) {
|
|
14
|
-
//@ts-ignore
|
|
15
|
-
return pipeline.reduce((v, func) => func(v), type);
|
|
16
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { Serializer } from "../../types";
|
|
2
|
-
/**
|
|
3
|
-
* ```
|
|
4
|
-
* const length = st.createRememberedValue<number>()
|
|
5
|
-
* st.object({
|
|
6
|
-
* length: length.save(st.u32()),
|
|
7
|
-
* type: st.u8(),
|
|
8
|
-
* data: st.sizedBytes(length.load())
|
|
9
|
-
* })
|
|
10
|
-
* ```
|
|
11
|
-
*/
|
|
12
|
-
export declare function createRememberedValue<T>(): {
|
|
13
|
-
save: (serializer: Serializer<T>) => Serializer<T>;
|
|
14
|
-
load: (serializer?: Serializer<T>) => Serializer<T>;
|
|
15
|
-
};
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ```
|
|
3
|
-
* const length = st.createRememberedValue<number>()
|
|
4
|
-
* st.object({
|
|
5
|
-
* length: length.save(st.u32()),
|
|
6
|
-
* type: st.u8(),
|
|
7
|
-
* data: st.sizedBytes(length.load())
|
|
8
|
-
* })
|
|
9
|
-
* ```
|
|
10
|
-
*/
|
|
11
|
-
export function createRememberedValue() {
|
|
12
|
-
const stack = [];
|
|
13
|
-
function save(serializer) {
|
|
14
|
-
return {
|
|
15
|
-
size: serializer.size,
|
|
16
|
-
read: (ctx) => {
|
|
17
|
-
const value = serializer.read(ctx);
|
|
18
|
-
stack.push(value);
|
|
19
|
-
return value;
|
|
20
|
-
},
|
|
21
|
-
write: (ctx, value) => {
|
|
22
|
-
serializer.write(ctx, value);
|
|
23
|
-
stack.push(value);
|
|
24
|
-
return value;
|
|
25
|
-
},
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
function load(serializer) {
|
|
29
|
-
return {
|
|
30
|
-
size: serializer?.size ?? 0,
|
|
31
|
-
read: () => stack.pop(),
|
|
32
|
-
write: (ctx) => serializer && serializer.write(ctx, stack.pop()),
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
return { save: save, load: load };
|
|
36
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|