From 227d6e11eee28182ed1a51017376f669e5b6d278 Mon Sep 17 00:00:00 2001 From: Iwo Plaza Date: Sun, 8 Sep 2024 23:53:44 +0200 Subject: [PATCH] Fixed reading slices from a buffer. --- packages/typed-binary/src/io/bufferReader.ts | 13 +- .../src/io/bufferReaderWriter.test.ts | 196 +++++++++++------- packages/typed-binary/src/io/bufferWriter.ts | 4 +- packages/typed-binary/src/io/types.ts | 2 +- .../typed-binary/src/test/typedArray.test.ts | 18 +- 5 files changed, 152 insertions(+), 81 deletions(-) diff --git a/packages/typed-binary/src/io/bufferReader.ts b/packages/typed-binary/src/io/bufferReader.ts index b8e26b1..c25a8f3 100644 --- a/packages/typed-binary/src/io/bufferReader.ts +++ b/packages/typed-binary/src/io/bufferReader.ts @@ -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) { @@ -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++]; + } } } diff --git a/packages/typed-binary/src/io/bufferReaderWriter.test.ts b/packages/typed-binary/src/io/bufferReaderWriter.test.ts index 6c5979b..1ab7f07 100644 --- a/packages/typed-binary/src/io/bufferReaderWriter.test.ts +++ b/packages/typed-binary/src/io/bufferReaderWriter.test.ts @@ -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); @@ -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); - }); }); diff --git a/packages/typed-binary/src/io/bufferWriter.ts b/packages/typed-binary/src/io/bufferWriter.ts index 628863c..21d0a9b 100644 --- a/packages/typed-binary/src/io/bufferWriter.ts +++ b/packages/typed-binary/src/io/bufferWriter.ts @@ -45,8 +45,8 @@ export class BufferWriter extends BufferIOBase implements ISerialOutput { } writeSlice(bufferView: ArrayLike & 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; } diff --git a/packages/typed-binary/src/io/types.ts b/packages/typed-binary/src/io/types.ts index 71622f6..ce98bda 100644 --- a/packages/typed-binary/src/io/types.ts +++ b/packages/typed-binary/src/io/types.ts @@ -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; diff --git a/packages/typed-binary/src/test/typedArray.test.ts b/packages/typed-binary/src/test/typedArray.test.ts index 551fd78..8f1f9d1 100644 --- a/packages/typed-binary/src/test/typedArray.test.ts +++ b/packages/typed-binary/src/test/typedArray.test.ts @@ -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]); }); });