Skip to content

Commit

Permalink
added eslint rule to explicitly define a return type, added docs comm…
Browse files Browse the repository at this point in the history
…ents for all the source, modified readme
  • Loading branch information
SergiiSharpov committed Nov 25, 2024
1 parent de1ee91 commit f32d0c0
Show file tree
Hide file tree
Showing 14 changed files with 855 additions and 19 deletions.
94 changes: 91 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

**Byteform** is a lightweight and versatile TypeScript library designed for encoding and decoding binary data. It provides an intuitive API to work with binary structures, making it an excellent choice for developers dealing with low-level data operations in both browser and Node.js environments.

## Table of contents
1. [Why?](#why-byteform)
2. [Features](#features)
3. [Installation](#installation)
4. [Quick Start](#quick-start)
1. [Create a Binary Structure](#create-a-binary-structure)
2. [Encode data](#encode-data)
3. [Decode data](#decode-data)
5. [Contributing](#contributing)

## Why Byteform?

Byteform simplifies binary data handling by providing an intuitive API without sacrificing performance. Whether you're building network protocols, file parsers, or any other application requiring precise binary data manipulation, Byteform has you covered.
Expand All @@ -11,13 +21,91 @@ Byteform simplifies binary data handling by providing an intuitive API without s
- Encode and decode binary data with ease.
- Works seamlessly in both browser and Node.js environments.
- Built with performance and simplicity in mind.
- Typescript first.
- No dependencies.

## Installation (coming soon)
## Installation

Install Byteform via npm:
```bash
npm install byteform
```

Or via yarn:
```bash
yarn add byteform
```

## Quick Start

### Create a Binary Structure

```typescript
import { Struct, u8, u16, u32, f32, f64 } from 'byteform';

const vec3 = new Struct({
x: f32,
y: f32,
z: f32
});

const bullet = new Struct({
position: Vec3,
velocity: Vec3,
damage: u8
});

const Player = new Struct({
name: new Text(32),
level: u8,
position: vec3,
bullets: new List(bullet)
});
```

### Encode data

```typescript
import { BinaryEncoder } from 'byteform';

const encoder = new BinaryEncoder(1024); // 1KB buffer

// Encode a Player instance
encoder.encode(Player, {
name: 'Alice',
level: 10,
position: { x: 1.0, y: 2.0, z: 3.0 },
bullets: [
{
position: { x: 10.0, y: 20.0, z: 30.0 },
velocity: { x: 1.0, y: 0.0, z: 0.0 },
damage: 10
},
{
position: { x: 20.0, y: 30.0, z: 40.0 },
velocity: { x: 0.0, y: 1.0, z: 0.0 },
damage: 20
}
]
});

/**
* Get the encoded binary data
* Send the buffer over the network, save it to a file, etc.
*/
const buffer = encoder.commit();
```

### Decode data

```typescript
import { BinaryDecoder } from 'byteform';

## Usage (coming soon)
const decoder = BinaryDecoder.fromArrayBuffer(buffer);
const player = decoder.decode(Player);

## Documentation (coming soon)
console.log(player);
```

## Contributing
Contributions are welcome! Please open an issue or submit a pull request to get involved.
2 changes: 2 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export default tseslint.config({
"@typescript-eslint/consistent-type-imports": "error",
"@typescript-eslint/explicit-member-accessibility": "error",

"@typescript-eslint/explicit-function-return-type": "error",

semi: "error",
indent: ["error", 2]
},
Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
"main": "dist/cjs/index.cjs",
"module": "dist/esm/index.mjs",
"types": "dist/index.d.ts",
"files": [
"dist",
"LICENSE",
"README.md"
],
"scripts": {
"build": "rollup -c",
"test": "jest",
Expand Down
22 changes: 22 additions & 0 deletions src/binary-decoder.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,39 @@
import { BufferReader } from "./buffer-reader";
import type { BaseType, InferBaseType } from "./types";

/**
* A class that provides methods for decoding binary data.
* @group Decoding
*/
export class BinaryDecoder {
/**
* The buffer reader.
*/
public readonly reader: BufferReader;

/**
* Creates a new binary decoder.
* @param writer - The buffer reader
*/
public constructor(writer: BufferReader) {
this.reader = writer;
}

/**
* Creates a new binary decoder from an ArrayBuffer.
* @param buffer - The ArrayBuffer to decode
* @returns The new binary decoder instance
*/
public static fromArrayBuffer(buffer: ArrayBuffer): BinaryDecoder {
return new BinaryDecoder(new BufferReader(buffer));
}

/**
* Decodes a value from the buffer.
* @param schema - The schema of the value to decode
* @returns The decoded value
* @throws {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RangeError | RangeError} if the byte size of the readable schema is larger than the buffer size
*/
public decode<T extends BaseType>(schema: T): InferBaseType<T> {
return schema.read(this.reader) as InferBaseType<T>;
}
Expand Down
46 changes: 44 additions & 2 deletions src/binary-encoder.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,75 @@
import type { ResizeOptions } from "./buffer-writer";
import { BufferWriter } from "./buffer-writer";
import type { BaseType, InferBaseType } from "./types";

/**
* A class that provides methods for encoding binary data.
* @group Encoding
*/
export class BinaryEncoder {
/**
* The buffer writer.
*/
public readonly writer: BufferWriter;

/**
* Creates a new binary encoder.
* @param writer - The buffer writer
*/
public constructor(writer: BufferWriter) {
this.writer = writer;
}

public static create(...params: ConstructorParameters<typeof BufferWriter>): BinaryEncoder {
return new BinaryEncoder(new BufferWriter(...params));
/**
* Creates a new binary encoder from a buffer writer.
* @param byteLength - The initial byte length of the buffer
* @param options - {@link BufferWriter} options
* @returns The new binary encoder instance
* @throws {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RangeError | RangeError} if the initial buffer size is invalid or the maxByteLength is less than the initial buffer size
*/
public static create(byteLength: number, options: Partial<ResizeOptions> = {}): BinaryEncoder {
return new BinaryEncoder(new BufferWriter(byteLength, options));
}

/**
* Creates a new binary encoder from an ArrayBuffer.
* @param buffer - The ArrayBuffer to encode
* @returns The new binary encoder instance
*/
public reset(): void {
this.writer.reset();
}

/**
* Encodes a value to the buffer.
* @param schema - The schema of the value to encode
* @param value - The value to encode
* @throws {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RangeError | RangeError} if the value is invalid or the value size is larger than the buffer maximum size
*/
public encode<T extends BaseType>(schema: T, value: InferBaseType<T>): void {
schema.write(value, this.writer);
}

/**
* Commits the buffer.
* @returns The ArrayBuffer containing the encoded data
*/
public commit(): ArrayBuffer {
return this.writer.commit();
}

/**
* Commits the buffer as a Uint8Array.
* @returns The Uint8Array containing the encoded data
*/
public commitUint8Array(): Uint8Array {
return this.writer.commitUint8Array();
}

/**
* Converts the buffer to an Uint8Array.
* @returns The Uint8Array containing the encoded data
*/
public toUint8Array(): Uint8Array {
return this.writer.toUint8Array();
}
Expand Down
76 changes: 76 additions & 0 deletions src/buffer-reader.ts
Original file line number Diff line number Diff line change
@@ -1,62 +1,129 @@
import { BufferView } from "./buffer-view";

/**
* A class that provides methods to read data from a buffer.
* @group Decoding
*/
export class BufferReader extends BufferView {
/**
* Reads an unsigned 8-bit integer from the buffer.
* @returns Read value
* @throws {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RangeError | RangeError} if the buffer is out of bounds
*/
public readUint8(): number {
return this._view.getUint8(this._offset++);
}

/**
* Reads a signed 8-bit integer from the buffer.
* @returns Read value
* @throws {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RangeError | RangeError} if the buffer is out of bounds
*/
public readInt8(): number {
return this._view.getInt8(this._offset++);
}

/**
* Reads an unsigned 16-bit integer from the buffer.
* @param littleEndian - Whether the integer is little-endian
* @returns Read value
* @throws {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RangeError | RangeError} if the buffer is out of bounds
*/
public readUint16(littleEndian: boolean = false): number {
const value = this._view.getUint16(this._offset, littleEndian);
this._offset += 2;
return value;
}

/**
* Reads a signed 16-bit integer from the buffer.
* @param littleEndian - Whether the integer is little-endian
* @returns Read value
* @throws {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RangeError | RangeError} if the buffer is out of bounds
*/
public readInt16(littleEndian: boolean = false): number {
const value = this._view.getInt16(this._offset, littleEndian);
this._offset += 2;
return value;
}

/**
* Reads an unsigned 32-bit integer from the buffer.
* @param littleEndian - Whether the integer is little-endian
* @returns Read value
* @throws {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RangeError | RangeError} if the buffer is out of bounds
*/
public readUint32(littleEndian: boolean = false): number {
const value = this._view.getUint32(this._offset, littleEndian);
this._offset += 4;
return value;
}

/**
* Reads a signed 32-bit integer from the buffer.
* @param littleEndian - Whether the integer is little-endian
* @returns Read value
* @throws {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RangeError | RangeError} if the buffer is out of bounds
*/
public readInt32(littleEndian: boolean = false): number {
const value = this._view.getInt32(this._offset, littleEndian);
this._offset += 4;
return value;
}

/**
* Reads an unsigned 64-bit integer from the buffer.
* @param littleEndian - Whether the integer is little-endian
* @returns Read value
* @throws {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RangeError | RangeError} if the buffer is out of bounds
*/
public readInt64(littleEndian: boolean = false): bigint {
const value = this._view.getBigInt64(this._offset, littleEndian);
this._offset += 8;
return value;
}

/**
* Reads a signed 64-bit integer from the buffer.
* @param littleEndian - Whether the integer is little-endian
* @returns Read value
* @throws {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RangeError | RangeError} if the buffer is out of bounds
*/
public readUint64(littleEndian: boolean = false): bigint {
const value = this._view.getBigUint64(this._offset, littleEndian);
this._offset += 8;
return value;
}

/**
* Reads a 32-bit floating point number from the buffer.
* @param littleEndian - Whether the number is little-endian
* @returns Read value
* @throws {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RangeError | RangeError} if the buffer is out of bounds
*/
public readFloat32(littleEndian: boolean = false): number {
const value = this._view.getFloat32(this._offset, littleEndian);
this._offset += 4;
return value;
}

/**
* Reads a 64-bit floating point number from the buffer.
* @param littleEndian - Whether the number is little-endian
* @returns Read value
* @throws {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RangeError | RangeError} if the buffer is out of bounds
*/
public readFloat64(littleEndian: boolean = false): number {
const value = this._view.getFloat64(this._offset, littleEndian);
this._offset += 8;
return value;
}

/**
* Reads a set of bytes from the buffer.
* @returns An Uint8Array containing the read bytes
* @throws {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RangeError | RangeError} if the buffer is out of bounds
*/
public readBytes(byteLength: number): Uint8Array {
const value = new Uint8Array(byteLength);
for (let i = 0; i < byteLength; i++) {
Expand All @@ -65,6 +132,15 @@ export class BufferReader extends BufferView {
return value;
}

/**
* Reads a set of bytes from the buffer without copying.
* @returns An Uint8Array containing the read bytes
* @throws {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RangeError | RangeError} if the buffer is out of bounds
*
* @remarks
* The returned Uint8Array shares the same memory as the buffer.
* Use with caution, as modifying the Uint8Array will also modify the buffer.
*/
public readBytesUnsafe(byteLength: number): Uint8Array {
const value = new Uint8Array(this._buffer, this._offset, byteLength);
this._offset += byteLength;
Expand Down
Loading

0 comments on commit f32d0c0

Please sign in to comment.