Skip to content

Commit 0661ff0

Browse files
authored
feat(types): Max size attribute. (#58)
1 parent 942d829 commit 0661ff0

39 files changed

+211
-31
lines changed

src/array/array.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import { type Options, UnsizedType } from "../types/mod.ts";
22

33
export class ArrayType<T> extends UnsizedType<T[]> {
4+
override readonly maxSize: number | null;
5+
46
constructor(readonly type: UnsizedType<T>, readonly length: number) {
57
super(type.byteAlignment);
8+
this.maxSize = type.maxSize ? type.maxSize * length : null;
69
}
710

811
readPacked(dt: DataView, options: Options = { byteOffset: 0 }): T[] {

src/array/array_buffer_test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ Deno.test({
99
dt.setUint16(0, 0xFF);
1010

1111
const type = new ArrayBufferType(2);
12+
13+
await t.step("estimated size", () => {
14+
assertEquals(type.maxSize, 2);
15+
});
16+
1217
await t.step("Read", () => {
1318
const newAb = type.read(dt);
1419
assertEquals(new Uint8Array(newAb), new Uint8Array(ab));

src/array/array_test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ Deno.test({
99
const dt = new DataView(ab);
1010
const type = new ArrayType(u8, 2);
1111

12+
await t.step("estimated size", () => {
13+
assertEquals(type.maxSize, 2);
14+
});
15+
1216
await t.step("Read", () => {
1317
dt.setUint16(0, 0xFFFF);
1418
const result = type.read(dt);

src/array/typed_array.ts

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
11
import { type Options, SizedType } from "../types/mod.ts";
22

33
type TypedArrays =
4-
| Uint8Array
5-
| Uint8ClampedArray
6-
| Int8Array
7-
| Uint16Array
8-
| Int16Array
9-
| Uint32Array
10-
| Int32Array
11-
| Float32Array
12-
| Float64Array
13-
| BigUint64Array
14-
| BigInt64Array;
4+
| Uint8Array<ArrayBufferLike>
5+
| Uint8ClampedArray<ArrayBufferLike>
6+
| Int8Array<ArrayBufferLike>
7+
| Uint16Array<ArrayBufferLike>
8+
| Int16Array<ArrayBufferLike>
9+
| Uint32Array<ArrayBufferLike>
10+
| Int32Array<ArrayBufferLike>
11+
| Float32Array<ArrayBufferLike>
12+
| Float64Array<ArrayBufferLike>
13+
| BigUint64Array<ArrayBufferLike>
14+
| BigInt64Array<ArrayBufferLike>;
1515

16-
type TypedConstructors<T extends TypedArrays> = T extends Uint8Array
17-
? Uint8ArrayConstructor
18-
: T extends Uint8ClampedArray ? Uint8ClampedArrayConstructor
19-
: T extends Int8Array ? Int8ArrayConstructor
20-
: T extends Uint16Array ? Uint16ArrayConstructor
21-
: T extends Int16Array ? Int16ArrayConstructor
22-
: T extends Uint32Array ? Uint32ArrayConstructor
23-
: T extends Int32Array ? Int32ArrayConstructor
24-
: T extends Float32Array ? Float32ArrayConstructor
25-
: T extends Float64Array ? Float64ArrayConstructor
26-
: T extends BigUint64Array ? BigUint64ArrayConstructor
27-
: T extends BigInt64Array ? BigInt64ArrayConstructor
16+
type TypedConstructors<T extends TypedArrays> = T extends
17+
Uint8Array<ArrayBufferLike> ? Uint8ArrayConstructor
18+
: T extends Uint8ClampedArray<ArrayBufferLike> ? Uint8ClampedArrayConstructor
19+
: T extends Int8Array<ArrayBufferLike> ? Int8ArrayConstructor
20+
: T extends Uint16Array<ArrayBufferLike> ? Uint16ArrayConstructor
21+
: T extends Int16Array<ArrayBufferLike> ? Int16ArrayConstructor
22+
: T extends Uint32Array<ArrayBufferLike> ? Uint32ArrayConstructor
23+
: T extends Int32Array<ArrayBufferLike> ? Int32ArrayConstructor
24+
: T extends Float32Array<ArrayBufferLike> ? Float32ArrayConstructor
25+
: T extends Float64Array<ArrayBufferLike> ? Float64ArrayConstructor
26+
: T extends BigUint64Array<ArrayBufferLike> ? BigUint64ArrayConstructor
27+
: T extends BigInt64Array<ArrayBufferLike> ? BigInt64ArrayConstructor
2828
: never;
2929

3030
export class TypedArray<T extends TypedArrays> extends SizedType<T> {
@@ -40,8 +40,8 @@ export class TypedArray<T extends TypedArrays> extends SizedType<T> {
4040

4141
readPacked(dt: DataView, options: Options = { byteOffset: 0 }): T {
4242
const value = new this.arrayConstructor(
43-
dt.buffer,
4443
// @ts-expect-error:
44+
dt.buffer,
4545
dt.byteOffset + options.byteOffset,
4646
this.length,
4747
).slice() as T;
@@ -56,8 +56,8 @@ export class TypedArray<T extends TypedArrays> extends SizedType<T> {
5656
options: Options = { byteOffset: 0 },
5757
): void {
5858
const view = new this.arrayConstructor(
59-
dt.buffer,
6059
// @ts-expect-error:
60+
dt.buffer,
6161
dt.byteOffset + options.byteOffset,
6262
this.length,
6363
);

src/array/typed_array_test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ Deno.test({
99
const dt = new DataView(ab);
1010
const type = new Uint16ArrayType(1);
1111

12+
await t.step("estimated size", () => {
13+
assertEquals(type.maxSize, 2);
14+
});
15+
1216
await t.step("Read", () => {
1317
dt.setUint16(0, 0xFFFF);
1418
const result = type.read(dt);

src/bitflags/bitflags16_test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ Deno.test({
1111
two: 2,
1212
});
1313

14+
await t.step("estimated size", () => {
15+
assertEquals(type.maxSize, 2);
16+
});
17+
1418
await t.step("Read", () => {
1519
dt.setUint8(1, 0b01);
1620
const result = type.read(dt);

src/bitflags/bitflags32_test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ Deno.test({
1111
two: 2,
1212
});
1313

14+
await t.step("estimated size", () => {
15+
assertEquals(type.maxSize, 4);
16+
});
17+
1418
await t.step("Read", () => {
1519
dt.setUint8(3, 0b01);
1620
const result = type.read(dt);

src/bitflags/bitflags64_test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ Deno.test({
1111
two: 2n,
1212
});
1313

14+
await t.step("estimated size", () => {
15+
assertEquals(type.maxSize, 8);
16+
});
17+
1418
await t.step("Read", () => {
1519
dt.setUint8(7, 0b01);
1620
const result = type.read(dt);

src/bitflags/bitflags8_test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ Deno.test({
1111
two: 2,
1212
});
1313

14+
await t.step("estimated size", () => {
15+
assertEquals(type.maxSize, 1);
16+
});
17+
1418
await t.step("Read", () => {
1519
dt.setUint8(0, 0b01);
1620
const result = type.read(dt);

src/compound/sized_struct_test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ Deno.test({
99
const dt = new DataView(ab);
1010
const type = new SizedStruct({ byte: u8, word: u32le });
1111

12+
await t.step("estimated size", () => {
13+
assertEquals(type.maxSize, 8);
14+
});
15+
1216
await t.step("Read", () => {
1317
dt.setUint8(0, 127);
1418
dt.setUint32(4, 255, true);

src/compound/struct.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { type InnerType, type Options, UnsizedType } from "../types/mod.ts";
2-
import { alignmentOf } from "../util.ts";
2+
import { align, alignmentOf } from "../util.ts";
33

44
export class Struct<
55
T extends Record<string, UnsizedType<unknown>>,
@@ -8,10 +8,17 @@ export class Struct<
88
},
99
> extends UnsizedType<V> {
1010
#record: Array<[string, UnsizedType<unknown>]>;
11+
override readonly maxSize: number | null;
1112

1213
constructor(input: T) {
1314
super(alignmentOf(input));
1415
this.#record = Object.entries(input);
16+
this.maxSize = this.#record.every(([_, a]) => a.maxSize !== null)
17+
? this.#record.reduce(
18+
(acc, [_, x]) => acc + align(Number(x.maxSize), this.byteAlignment),
19+
0,
20+
)
21+
: null;
1522
}
1623

1724
readPacked(dt: DataView, options: Options = { byteOffset: 0 }): V {

src/compound/struct_test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ Deno.test({
99
const dt = new DataView(ab);
1010
const type = new Struct({ byte: u8, word: u32le });
1111

12+
await t.step("estimated size", () => {
13+
assertEquals(type.maxSize, 8);
14+
});
15+
1216
await t.step("Read", () => {
1317
dt.setUint8(0, 127);
1418
dt.setUint32(4, 255, true);

src/compound/tagged_union.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
UnsizedType,
66
type ValueOf,
77
} from "../types/mod.ts";
8-
import { alignmentOf } from "../util.ts";
8+
import { align, alignmentOf } from "../util.ts";
99

1010
type FindDiscriminant<V, D extends number | string> = (variant: V) => D;
1111

@@ -22,6 +22,8 @@ export class TaggedUnion<
2222
#variantFinder: FindDiscriminant<V, Keys<T>>;
2323
#discriminant: UnsizedType<string | number>;
2424

25+
override maxSize: number | null;
26+
2527
constructor(
2628
input: T,
2729
variantFinder: FindDiscriminant<V, Keys<T>>,
@@ -43,6 +45,13 @@ export class TaggedUnion<
4345
this.#record = input;
4446
this.#variantFinder = variantFinder;
4547
this.#discriminant = discriminant;
48+
this.maxSize = Object.values(input).some((x) => x.maxSize === null)
49+
? null
50+
: Object.values(input).reduce(
51+
(acc: number, x) =>
52+
Math.max(acc, align(x.maxSize as number, this.byteAlignment)),
53+
0,
54+
);
4655
}
4756

4857
readPacked(dt: DataView, options: Options = { byteOffset: 0 }): V {

src/compound/tagged_union_test.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { TaggedUnion } from "./tagged_union.ts";
2-
import { u32le, u8 } from "../mod.ts";
2+
import { cstring, u32le, u8 } from "../mod.ts";
33
import { assertEquals, assertThrows } from "../../test_deps.ts";
44

55
Deno.test({
@@ -13,6 +13,21 @@ Deno.test({
1313
2: u8,
1414
}, (a) => a === 32 ? 0 : 1);
1515

16+
await t.step("estimate size", () => {
17+
const type = new TaggedUnion({
18+
0: u32le,
19+
1: u8,
20+
2: u8,
21+
}, (a) => a === 32 ? 0 : 1);
22+
assertEquals(type.maxSize, 4);
23+
24+
const unknownSizedType = new TaggedUnion({
25+
0: cstring,
26+
}, () => 0);
27+
28+
assertEquals(unknownSizedType.maxSize, null);
29+
});
30+
1631
await t.step("Read", () => {
1732
dt.setUint8(0, 1);
1833
dt.setUint8(1, 11);

src/compound/tuple.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
11
import { type InnerType, type Options, UnsizedType } from "../types/mod.ts";
2-
import { alignmentOf } from "../util.ts";
2+
import { align, alignmentOf } from "../util.ts";
33

44
export class Tuple<
55
T extends [...UnsizedType<unknown>[]],
66
V extends [...unknown[]] = { [I in keyof T]: InnerType<T[I]> },
77
> extends UnsizedType<V> {
88
#tupleTypes: T;
99
#length: number;
10+
override maxSize: number | null;
11+
1012
constructor(types: T) {
1113
super(alignmentOf(types));
1214
this.#tupleTypes = types;
1315
this.#length = types.length;
16+
17+
this.maxSize = types.every((a) => a.maxSize !== null)
18+
? types.reduce(
19+
(acc, x) => acc + align(Number(x.maxSize), this.byteAlignment),
20+
0,
21+
)
22+
: null;
1423
}
1524

1625
readPacked(dt: DataView, options: Options = { byteOffset: 0 }): V {

src/compound/tuple_test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ Deno.test({
99
const dt = new DataView(ab);
1010
const type = new Tuple([u8, u32le]);
1111

12+
await t.step("estimated size", () => {
13+
assertEquals(type.maxSize, 8);
14+
});
15+
1216
await t.step("Read", () => {
1317
dt.setUint32(0, 127, true);
1418
dt.setUint32(4, 255, true);

src/compound/union.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
UnsizedType,
66
type ValueOf,
77
} from "../types/mod.ts";
8-
import { alignmentOf } from "../util.ts";
8+
import { align, alignmentOf } from "../util.ts";
99

1010
type FindDiscriminant<V, D extends number> = (variant: V) => D;
1111

@@ -20,13 +20,23 @@ export class Union<
2020
#variantFinder: FindDiscriminant<V, Keys<T>>;
2121
#discriminant = u8;
2222

23+
override maxSize: number | null;
24+
2325
constructor(
2426
input: T,
2527
variantFinder: FindDiscriminant<V, Keys<T>>,
2628
) {
2729
super(alignmentOf(input));
2830
this.#record = input;
2931
this.#variantFinder = variantFinder;
32+
33+
this.maxSize = Object.values(input).some((x) => x.maxSize === null)
34+
? null
35+
: Object.values(input).reduce(
36+
(acc: number, x) =>
37+
Math.max(acc, align(x.maxSize as number, this.byteAlignment)),
38+
0,
39+
);
3040
}
3141

3242
readPacked(dt: DataView, options: Options = { byteOffset: 0 }): V {

src/compound/union_test.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { u32le, u8 } from "../mod.ts";
1+
import { cstring, u32le, u8 } from "../mod.ts";
22
import { assertEquals, assertThrows } from "../../test_deps.ts";
33
import { Union } from "./union.ts";
44

@@ -13,6 +13,21 @@ Deno.test({
1313
2: u8,
1414
}, (a) => a === 32 ? 0 : 1);
1515

16+
await t.step("estimate size", () => {
17+
const type = new Union({
18+
0: u32le,
19+
1: u8,
20+
2: u8,
21+
}, (a) => a === 32 ? 0 : 1);
22+
assertEquals(type.maxSize, 4);
23+
24+
const unknownSizedType = new Union({
25+
0: cstring,
26+
}, () => 0);
27+
28+
assertEquals(unknownSizedType.maxSize, null);
29+
});
30+
1631
await t.step("Read", () => {
1732
dt.setUint8(0, 1);
1833
dt.setUint8(1, 11);

src/meta_types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ import type { Options } from "./mod.ts";
22
import { SizedType } from "./types/mod.ts";
33

44
export class Offset extends SizedType<null> {
5+
override readonly maxSize: number | null;
6+
57
constructor(byteSize: number) {
68
// Magic trick for flooring
79
super(byteSize | 0, 1);
10+
this.maxSize = 0;
811
}
912

1013
override readPacked(

0 commit comments

Comments
 (0)