Skip to content

Commit

Permalink
Changed size estimation api, added the ability to skip a number of by…
Browse files Browse the repository at this point in the history
…tes in IO.
  • Loading branch information
iwoplaza committed Nov 26, 2023
1 parent 28b195a commit c717064
Show file tree
Hide file tree
Showing 18 changed files with 264 additions and 111 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "typed-binary",
"version": "2.0.0",
"version": "2.1.0",
"description": "Describe binary structures with full TypeScript support. Encode and decode into pure JavaScript objects.",
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
Expand Down
4 changes: 4 additions & 0 deletions src/io/bufferReader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,8 @@ export class BufferReader extends BufferIOBase implements ISerialInput {

return contents;
}

skipBytes(bytes: number): void {
this.byteOffset += bytes;
}
}
4 changes: 4 additions & 0 deletions src/io/bufferWriter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,8 @@ export class BufferWriter extends BufferIOBase implements ISerialOutput {
// Extra null character
this.uint8View[this.byteOffset++] = 0;
}

skipBytes(bytes: number): void {
this.byteOffset += bytes;
}
}
5 changes: 3 additions & 2 deletions src/io/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { ISerialInput, ISerialOutput } from './types';
export { ISerialInput, ISerialOutput, IMeasurer } from './types';
export { BufferWriter } from './bufferWriter';
export { BufferReader } from './bufferReader';
export { isBigEndian } from '../util';
export { Measurer } from './measurer';
export { isBigEndian } from '../util';
34 changes: 34 additions & 0 deletions src/io/measurer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { IMeasurer } from './types';

class UnboundedMeasurer implements IMeasurer {
size = NaN;
unbounded: IMeasurer = this;
isUnbounded = true;

add(): IMeasurer {
return this;
}

fork(): IMeasurer {
return this;
}
}

const unboundedMeasurer = new UnboundedMeasurer();

export class Measurer implements IMeasurer {
size = 0;
unbounded: IMeasurer = unboundedMeasurer;
isUnbounded = false;

add(bytes: number): IMeasurer {
this.size += bytes;
return this;
}

fork() {
const forked = new Measurer();
forked.size = this.size;
return forked;
}
}
11 changes: 11 additions & 0 deletions src/io/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export interface ISerialInput {
readUint32(): number;
readFloat32(): number;
readString(): string;
skipBytes(bytes: number): void;
readonly currentByteOffset: number;
}

Expand All @@ -15,5 +16,15 @@ export interface ISerialOutput {
writeUint32(value: number): void;
writeFloat32(value: number): void;
writeString(value: string): void;
skipBytes(bytes: number): void;
readonly currentByteOffset: number;
}

export interface IMeasurer {
add(bytes: number): IMeasurer;
fork(): IMeasurer;
readonly unbounded: IMeasurer;

readonly size: number;
readonly isUnbounded: boolean;
}
27 changes: 18 additions & 9 deletions src/structure/array.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import type { ISerialInput, ISerialOutput } from '../io';
import { i32 } from './baseTypes';
import {
type ISerialInput,
type ISerialOutput,
type IMeasurer,
Measurer,
} from '../io';
import { u32 } from './baseTypes';
import {
IRefResolver,
ISchema,
Expand Down Expand Up @@ -43,19 +48,23 @@ export class ArraySchema<T> extends Schema<T[]> {
return array;
}

sizeOf(values: T[] | typeof MaxValue): number {
measure(
values: T[] | typeof MaxValue,
measurer: IMeasurer = new Measurer(),
): IMeasurer {
if (values === MaxValue) {
// arrays cannot be bound
return NaN;
return measurer.unbounded;
}

// Length encoding
let size = i32.sizeOf();
u32.measure(values.length, measurer);

// Values encoding
size += values
.map((v) => this.elementType.sizeOf(v))
.reduce((a, b) => a + b, 0);
for (const value of values) {
this.elementType.measure(value, measurer);
}

return size;
return measurer;
}
}
46 changes: 32 additions & 14 deletions src/structure/baseTypes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ISerialInput, ISerialOutput } from '../io';
import { ISerialInput, ISerialOutput, IMeasurer, Measurer } from '../io';
import { Schema, MaxValue } from './types';

////
Expand All @@ -18,8 +18,11 @@ export class BoolSchema extends Schema<boolean> {
output.writeBool(value);
}

sizeOf(): number {
return 1;
measure(
_: boolean | MaxValue,
measurer: IMeasurer = new Measurer(),
): IMeasurer {
return measurer.add(1);
}
}

Expand All @@ -42,12 +45,15 @@ export class StringSchema extends Schema<string> {
output.writeString(value);
}

sizeOf<T extends string>(value: T | typeof MaxValue): number {
measure(
value: string | typeof MaxValue,
measurer: IMeasurer = new Measurer(),
): IMeasurer {
if (value === MaxValue) {
// A string cannot be bound
return NaN;
return measurer.unbounded;
}
return value.length + 1;
return measurer.add(value.length + 1);
}
}

Expand All @@ -70,8 +76,11 @@ export class ByteSchema extends Schema<number> {
output.writeByte(value);
}

sizeOf(): number {
return 1;
measure(
_: number | MaxValue,
measurer: IMeasurer = new Measurer(),
): IMeasurer {
return measurer.add(1);
}
}

Expand All @@ -94,8 +103,11 @@ export class Int32Schema extends Schema<number> {
output.writeInt32(value);
}

sizeOf(): number {
return 4;
measure(
_: number | MaxValue,
measurer: IMeasurer = new Measurer(),
): IMeasurer {
return measurer.add(4);
}
}

Expand All @@ -118,8 +130,11 @@ export class Uint32Schema extends Schema<number> {
output.writeUint32(value);
}

sizeOf(): number {
return 4;
measure(
_: number | MaxValue,
measurer: IMeasurer = new Measurer(),
): IMeasurer {
return measurer.add(4);
}
}

Expand All @@ -142,8 +157,11 @@ export class Float32Schema extends Schema<number> {
output.writeFloat32(value);
}

sizeOf(): number {
return 4;
measure(
_: number | MaxValue,
measurer: IMeasurer = new Measurer(),
): IMeasurer {
return measurer.add(4);
}
}

Expand Down
50 changes: 27 additions & 23 deletions src/structure/chars.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,39 @@
import type { ISerialInput, ISerialOutput } from '../io';
import type { IMeasurer, ISerialInput, ISerialOutput } from '../io';
import { TypedBinaryError } from '../error';
import { Schema } from './types';

export class CharsSchema extends Schema<string> {
constructor(public readonly length: number) {
super();
}
constructor(public readonly length: number) {
super();
}

resolve(): void { /* Nothing to resolve */ }
resolve(): void {
/* Nothing to resolve */
}

write(output: ISerialOutput, value: string): void {
if (value.length !== this.length) {
throw new TypedBinaryError(`Expected char-string of length ${this.length}, got ${value.length}`);
}

for (let i = 0; i < value.length; ++i) {
output.writeByte(value.charCodeAt(i));
}
write(output: ISerialOutput, value: string): void {
if (value.length !== this.length) {
throw new TypedBinaryError(
`Expected char-string of length ${this.length}, got ${value.length}`,
);
}

read(input: ISerialInput): string {
let content = '';

for (let i = 0; i < this.length; ++i) {
content += String.fromCharCode(input.readByte());
}

return content;
for (let i = 0; i < value.length; ++i) {
output.writeByte(value.charCodeAt(i));
}
}

read(input: ISerialInput): string {
let content = '';

sizeOf(): number {
return this.length;
for (let i = 0; i < this.length; ++i) {
content += String.fromCharCode(input.readByte());
}

return content;
}

measure(_: string, measurer: IMeasurer): IMeasurer {
return measurer.add(this.length);
}
}
2 changes: 2 additions & 0 deletions src/structure/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export {
Ref,
IRefResolver,
Schema,
ISchema,
IStableSchema,
ISchemaWithProperties,
Keyed,
KeyedSchema,
Expand Down
13 changes: 8 additions & 5 deletions src/structure/keyed.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Parsed } from '..';
import { TypedBinaryError } from '../error';
import { ISerialInput, ISerialOutput } from '../io';
import { IMeasurer, ISerialInput, ISerialOutput, Measurer } from '../io';
import {
IRefResolver,
ISchema,
Expand Down Expand Up @@ -36,9 +36,9 @@ class RefSchema<K extends string> implements IStableSchema<Ref<K>> {
);
}

sizeOf(): number {
measure(): IMeasurer {
throw new TypedBinaryError(
`Tried to estimate size of a reference directly. Resolve it instead.`,
`Tried to measure size of a reference directly. Resolve it instead.`,
);
}
}
Expand Down Expand Up @@ -107,7 +107,10 @@ export class KeyedSchema<K extends string, S extends IStableSchema<unknown>>
this.innerType.write(output, value);
}

sizeOf(value: Parsed<S> | typeof MaxValue): number {
return this.innerType.sizeOf(value);
measure(
value: Parsed<S> | typeof MaxValue,
measurer: IMeasurer = new Measurer(),
): IMeasurer {
return this.innerType.measure(value, measurer);
}
}
Loading

0 comments on commit c717064

Please sign in to comment.