Skip to content

Commit 2f8cc7f

Browse files
committed
Initial implementation of TypedArray support.
1 parent dcf50eb commit 2f8cc7f

File tree

5 files changed

+104
-4
lines changed

5 files changed

+104
-4
lines changed

src/describe/index.ts

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,19 @@ import {
44
SubTypeKey,
55
TupleSchema,
66
} from '../structure';
7-
import { DynamicArraySchema } from '../structure/dynamicArray';
7+
import { ArraySchema } from '../structure/array';
8+
import { KeyedSchema } from '../structure/keyed';
89
import { OptionalSchema } from '../structure/optional';
10+
import { TypedArraySchema } from '../structure/typedArray';
11+
import { DynamicArraySchema } from '../structure/dynamicArray';
912
import { AnyObjectSchema, GenericObjectSchema } from '../structure/object';
10-
import { ArraySchema } from '../structure/array';
1113
import {
1214
ISchema,
1315
Ref,
1416
AnySchema,
1517
Unwrap,
1618
AnySchemaWithProperties,
1719
} from '../structure/types';
18-
import { KeyedSchema } from '../structure/keyed';
1920
import { MergeRecordUnion } from '../utilityTypes';
2021

2122
export const chars = <T extends number>(length: T) => new CharsSchema(length);
@@ -56,6 +57,33 @@ export const tupleOf = <TSchema extends [AnySchema, ...AnySchema[]]>(
5657
schemas: TSchema,
5758
) => new TupleSchema(schemas);
5859

60+
export const u8Array = (length: number) =>
61+
new TypedArraySchema(length, Uint8Array);
62+
63+
export const u8ClampedArray = (length: number) =>
64+
new TypedArraySchema(length, Uint8ClampedArray);
65+
66+
export const u16Array = (length: number) =>
67+
new TypedArraySchema(length, Uint16Array);
68+
69+
export const u32Array = (length: number) =>
70+
new TypedArraySchema(length, Uint32Array);
71+
72+
export const i8Array = (length: number) =>
73+
new TypedArraySchema(length, Int8Array);
74+
75+
export const i16Array = (length: number) =>
76+
new TypedArraySchema(length, Int16Array);
77+
78+
export const i32Array = (length: number) =>
79+
new TypedArraySchema(length, Int32Array);
80+
81+
export const f32Array = (length: number) =>
82+
new TypedArraySchema(length, Float32Array);
83+
84+
export const f64Array = (length: number) =>
85+
new TypedArraySchema(length, Float64Array);
86+
5987
export const optional = <TSchema extends AnySchema>(innerType: TSchema) =>
6088
new OptionalSchema(innerType);
6189

src/io/bufferReader.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { BufferIOBase, BufferIOOptions } from './bufferIOBase';
2-
import { ISerialInput } from './types';
2+
import { ISerialInput, MutableBufferView } from './types';
33

44
export class BufferReader extends BufferIOBase implements ISerialInput {
55
constructor(buffer: ArrayBufferLike, options?: BufferIOOptions) {
@@ -50,4 +50,12 @@ export class BufferReader extends BufferIOBase implements ISerialInput {
5050

5151
return contents;
5252
}
53+
54+
readSlice(
55+
bufferView: MutableBufferView,
56+
offset: number,
57+
length: number,
58+
): void {
59+
bufferView.set(this.uint8View.subarray(this.byteOffset, length), offset);
60+
}
5361
}

src/io/bufferWriter.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,9 @@ export class BufferWriter extends BufferIOBase implements ISerialOutput {
4646
// Extra null character
4747
this.uint8View[this.byteOffset++] = 0;
4848
}
49+
50+
writeSlice(bufferView: ArrayLike<number> & ArrayBufferView): void {
51+
this.uint8View.set(bufferView, this.byteOffset);
52+
this.byteOffset += bufferView.byteLength;
53+
}
4954
}

src/io/types.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,23 @@
11
export type Endianness = 'big' | 'little';
22

3+
export type ImmutableBufferView = ArrayLike<number> & ArrayBufferView;
4+
5+
export type MutableBufferView = ImmutableBufferView & {
6+
set(array: ArrayLike<number>, offset?: number): void;
7+
};
8+
39
export interface ISerialInput {
410
readBool(): boolean;
511
readByte(): number;
612
readInt32(): number;
713
readUint32(): number;
814
readFloat32(): number;
915
readString(): string;
16+
readSlice(
17+
bufferView: MutableBufferView,
18+
offset: number,
19+
length: number,
20+
): void;
1021
seekTo(offset: number): void;
1122
skipBytes(bytes: number): void;
1223
readonly endianness: Endianness;
@@ -20,6 +31,7 @@ export interface ISerialOutput {
2031
writeUint32(value: number): void;
2132
writeFloat32(value: number): void;
2233
writeString(value: string): void;
34+
writeSlice(bufferView: ImmutableBufferView): void;
2335
seekTo(offset: number): void;
2436
skipBytes(bytes: number): void;
2537
readonly endianness: Endianness;

src/structure/typedArray.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import {
2+
type ISerialInput,
3+
type ISerialOutput,
4+
type IMeasurer,
5+
Measurer,
6+
} from '../io';
7+
import { MutableBufferView } from '../io/types';
8+
import { Parsed } from '../utilityTypes';
9+
import { Schema, MaxValue } from './types';
10+
11+
type TypedArrayConstructor<T> = {
12+
readonly BYTES_PER_ELEMENT: number;
13+
new (buffer: ArrayBufferLike, offset?: number, length?: number): T;
14+
};
15+
16+
export class TypedArraySchema<
17+
TTypedArray extends MutableBufferView,
18+
> extends Schema<TTypedArray> {
19+
public readonly byteLength: number;
20+
21+
constructor(
22+
public readonly length: number,
23+
private readonly _arrayConstructor: TypedArrayConstructor<TTypedArray>,
24+
) {
25+
super();
26+
27+
this.byteLength = length * _arrayConstructor.BYTES_PER_ELEMENT;
28+
}
29+
30+
write(output: ISerialOutput, value: Parsed<TTypedArray>): void {
31+
output.writeSlice(value);
32+
}
33+
34+
read(input: ISerialInput): Parsed<TTypedArray> {
35+
const buffer = new ArrayBuffer(this.byteLength);
36+
const view = new this._arrayConstructor(buffer, 0, this.length);
37+
input.readSlice(view, 0, this.byteLength);
38+
return view as Parsed<TTypedArray>;
39+
}
40+
41+
measure(
42+
_value: Parsed<TTypedArray> | typeof MaxValue,
43+
measurer: IMeasurer = new Measurer(),
44+
): IMeasurer {
45+
return measurer.add(this.byteLength);
46+
}
47+
}

0 commit comments

Comments
 (0)