Skip to content

Commit

Permalink
Fixed reading slices from a buffer.
Browse files Browse the repository at this point in the history
  • Loading branch information
iwoplaza committed Sep 8, 2024
1 parent ba0354c commit 227d6e1
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 81 deletions.
13 changes: 11 additions & 2 deletions packages/typed-binary/src/io/bufferReader.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { BufferIOBase } from './bufferIOBase';
import type { ISerialInput, MutableBufferView } from './types';
import { unwrapBuffer } from './unwrapBuffer';

export class BufferReader extends BufferIOBase implements ISerialInput {
private copyInputToHelper(bytes: number) {
Expand Down Expand Up @@ -50,8 +51,16 @@ export class BufferReader extends BufferIOBase implements ISerialInput {
readSlice(
bufferView: MutableBufferView,
offset: number,
length: number,
byteLength: number,
): void {
bufferView.set(this.uint8View.subarray(this.byteOffset, length), offset);
const unwrapped = unwrapBuffer(bufferView);
const destU8 = new Uint8Array(
unwrapped.buffer,
unwrapped.byteOffset + offset,
);

for (let i = 0; i < byteLength; ++i) {
destU8[i] = this.uint8View[this.byteOffset++];
}
}
}
196 changes: 124 additions & 72 deletions packages/typed-binary/src/io/bufferReaderWriter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,130 @@ import { getSystemEndianness } from '../util';
import { BufferReader } from './bufferReader';
import { BufferWriter } from './bufferWriter';

describe('BufferWriter', () => {
it('should encode a Uint8Array', () => {
const uint8s = new Uint8Array([0, 1, 1, 2, 3, 5, 8, 255]);

const buffer = Buffer.alloc(8);
const writer = new BufferWriter(buffer);
writer.writeSlice(uint8s);

const reader = new BufferReader(buffer);
expect(reader.readByte()).to.eq(0);
expect(reader.readByte()).to.eq(1);
expect(reader.readByte()).to.eq(1);
expect(reader.readByte()).to.eq(2);
expect(reader.readByte()).to.eq(3);
expect(reader.readByte()).to.eq(5);
expect(reader.readByte()).to.eq(8);
expect(reader.readByte()).to.eq(255);
});

it('should encode a Int32Array', () => {
const int32s = new Int32Array([
0,
1,
1,
2,
3,
5,
-2_147_483_648, // min signed 32-bit integer value
2_147_483_647, // max signed 32-bit integer value
]);

const buffer = Buffer.alloc(8 * 4);
const writer = new BufferWriter(buffer);
writer.writeSlice(int32s);

const reader = new BufferReader(buffer);
expect(reader.readInt32()).to.eq(0);
expect(reader.readInt32()).to.eq(1);
expect(reader.readInt32()).to.eq(1);
expect(reader.readInt32()).to.eq(2);
expect(reader.readInt32()).to.eq(3);
expect(reader.readInt32()).to.eq(5);
expect(reader.readInt32()).to.eq(-2_147_483_648);
expect(reader.readInt32()).to.eq(2_147_483_647);
});

it('should encode a Uint32Array', () => {
const uint32s = new Uint32Array([
0,
1,
1,
2,
3,
5,
8,
4_294_967_295, // max unsigned 32-bit integer value
]);

const buffer = Buffer.alloc(8 * 4);
const writer = new BufferWriter(buffer);
writer.writeSlice(uint32s);

const reader = new BufferReader(buffer);
expect(reader.readUint32()).to.eq(0);
expect(reader.readUint32()).to.eq(1);
expect(reader.readUint32()).to.eq(1);
expect(reader.readUint32()).to.eq(2);
expect(reader.readUint32()).to.eq(3);
expect(reader.readUint32()).to.eq(5);
expect(reader.readUint32()).to.eq(8);
expect(reader.readUint32()).to.eq(4_294_967_295);
});
});

describe('BufferReader', () => {
it('should decode a Uint8Array', () => {
const buffer = Buffer.alloc(4);
const writer = new BufferWriter(buffer);
writer.writeByte(0);
writer.writeByte(15);
writer.writeByte(64);
writer.writeByte(255);

const destBuffer = new ArrayBuffer(4);
const destU8 = new Uint8Array(destBuffer);
const reader = new BufferReader(buffer);
reader.readSlice(destU8, 0, 4);

expect([...destU8]).toEqual([0, 15, 64, 255]);
});

it('should decode a Uint32Array', () => {
const buffer = Buffer.alloc(4 * 4);
const writer = new BufferWriter(buffer);
writer.writeUint32(0);
writer.writeUint32(15);
writer.writeUint32(255);
writer.writeUint32(4_294_967_295);

const destBuffer = new ArrayBuffer(4 * 4);
const destU32 = new Uint32Array(destBuffer);
const reader = new BufferReader(buffer);
reader.readSlice(destU32, 0, destBuffer.byteLength);

expect([...destU32]).toEqual([0, 15, 255, 4_294_967_295]);
});

it('should decode a Int32Array', () => {
const buffer = Buffer.alloc(4 * 4);
const writer = new BufferWriter(buffer);
writer.writeInt32(0);
writer.writeInt32(15);
writer.writeInt32(-2_147_483_648);
writer.writeInt32(2_147_483_647);

const destBuffer = new ArrayBuffer(4 * 4);
const destI32 = new Int32Array(destBuffer);
const reader = new BufferReader(buffer);
reader.readSlice(destI32, 0, destBuffer.byteLength);

expect([...destI32]).toEqual([0, 15, -2_147_483_648, 2_147_483_647]);
});
});

describe('BufferWriter/BufferReader', () => {
it('parses options correctly', () => {
const buffer = Buffer.alloc(16);
Expand Down Expand Up @@ -80,76 +204,4 @@ describe('BufferWriter/BufferReader', () => {
expect(reader.readFloat32()).to.be.closeTo(floatList[i], 0.001);
}
});

it('should encode a Uint8Array', () => {
const uint8s = new Uint8Array([0, 1, 1, 2, 3, 5, 8, 255]);

const buffer = Buffer.alloc(8);
const writer = new BufferWriter(buffer);
writer.writeSlice(uint8s);

const reader = new BufferReader(buffer);
expect(reader.readByte()).to.eq(0);
expect(reader.readByte()).to.eq(1);
expect(reader.readByte()).to.eq(1);
expect(reader.readByte()).to.eq(2);
expect(reader.readByte()).to.eq(3);
expect(reader.readByte()).to.eq(5);
expect(reader.readByte()).to.eq(8);
expect(reader.readByte()).to.eq(255);
});

it('should encode a Int32Array', () => {
const int32s = new Int32Array([
0,
1,
1,
2,
3,
5,
-2_147_483_648, // min signed 32-bit integer value
2_147_483_647, // max signed 32-bit integer value
]);

const buffer = Buffer.alloc(8 * 4);
const writer = new BufferWriter(buffer);
writer.writeSlice(int32s);

const reader = new BufferReader(buffer);
expect(reader.readInt32()).to.eq(0);
expect(reader.readInt32()).to.eq(1);
expect(reader.readInt32()).to.eq(1);
expect(reader.readInt32()).to.eq(2);
expect(reader.readInt32()).to.eq(3);
expect(reader.readInt32()).to.eq(5);
expect(reader.readInt32()).to.eq(-2_147_483_648);
expect(reader.readInt32()).to.eq(2_147_483_647);
});

it('should encode a Uint32Array', () => {
const uint32s = new Uint32Array([
0,
1,
1,
2,
3,
5,
8,
4_294_967_295, // max unsigned 32-bit integer value
]);

const buffer = Buffer.alloc(8 * 4);
const writer = new BufferWriter(buffer);
writer.writeSlice(uint32s);

const reader = new BufferReader(buffer);
expect(reader.readUint32()).to.eq(0);
expect(reader.readUint32()).to.eq(1);
expect(reader.readUint32()).to.eq(1);
expect(reader.readUint32()).to.eq(2);
expect(reader.readUint32()).to.eq(3);
expect(reader.readUint32()).to.eq(5);
expect(reader.readUint32()).to.eq(8);
expect(reader.readUint32()).to.eq(4_294_967_295);
});
});
4 changes: 2 additions & 2 deletions packages/typed-binary/src/io/bufferWriter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ export class BufferWriter extends BufferIOBase implements ISerialOutput {
}

writeSlice(bufferView: ArrayLike<number> & ArrayBufferView): void {
const srcBuffer = unwrapBuffer(bufferView);
const srcU8 = new Uint8Array(srcBuffer.buffer, srcBuffer.byteOffset);
const unwrapped = unwrapBuffer(bufferView);
const srcU8 = new Uint8Array(unwrapped.buffer, unwrapped.byteOffset);
for (const srcByte of srcU8) {
this.uint8View[this.byteOffset++] = srcByte;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/typed-binary/src/io/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export interface ISerialInput {
readSlice(
bufferView: MutableBufferView,
offset: number,
length: number,
byteLength: number,
): void;
seekTo(offset: number): void;
skipBytes(bytes: number): void;
Expand Down
18 changes: 14 additions & 4 deletions packages/typed-binary/src/test/typedArray.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
import { describe, it, expect } from 'vitest';
import { u8Array } from '../describe';
import { i32Array, u32Array, u8Array } from '../describe';
import { encodeAndDecode } from './helpers/mock';

describe('u8Array', () => {
it('encodes and decodes a uint8 array', () => {
const schema = u8Array(4);

const value = new Uint8Array([0, 1, 15, 255]);

expect(encodeAndDecode(schema, value)).to.deep.equal(value);
expect([...encodeAndDecode(u8Array(4), value)]).toEqual([...value]);
});

it('encodes and decodes a uint32 array', () => {
const value = new Uint32Array([0, 1, 15, 4_294_967_295]);

expect([...encodeAndDecode(u32Array(4), value)]).toEqual([...value]);
});

it('encodes and decodes a int32 array', () => {
const value = new Int32Array([0, 1, -2_147_483_648, 2_147_483_647]);

expect([...encodeAndDecode(i32Array(4), value)]).toEqual([...value]);
});
});

0 comments on commit 227d6e1

Please sign in to comment.