-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
541 additions
and
157 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
40 changes: 40 additions & 0 deletions
40
apps/typed-binary-docs/src/content/docs/guides/arrays-and-tuples.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
--- | ||
title: Arrays and Tuples | ||
description: A guide on how arrays and tuples can be represented in Typed Binary | ||
--- | ||
|
||
## Arrays | ||
|
||
The items are encoded right next to each other. No need to store length information, as that is constant (built into the schema). | ||
|
||
```ts | ||
import { f32, arrayOf } from 'typed-binary'; | ||
|
||
const Vector2 = arrayOf(f32, 2); | ||
const Vector3 = arrayOf(f32, 3); | ||
const Vector4 = arrayOf(f32, 4); | ||
``` | ||
|
||
## Dynamic Arrays | ||
|
||
First 4 bytes of encoding are the length of the array, then its items next to one another. | ||
|
||
```ts | ||
import { i32, dynamicArrayOf } from 'typed-binary'; | ||
|
||
const IntArray = dynamicArrayOf(i32); | ||
``` | ||
|
||
## Tuple | ||
|
||
Encodes an ordered set of schemas, one next to another. | ||
|
||
```ts | ||
import { f32, string, tupleOf } from 'typed-binary'; | ||
|
||
const Vec3f = tupleOf([f32, f32, f32]); | ||
type Vec3f = Parsed<typeof Vec3f>; // [number, number, number] | ||
|
||
const RecordEntry = tupleOf([string, Vec3f]); | ||
type RecordEntry = Parsed<typeof RecordEntry>; // [string, [number, number, number]] | ||
``` |
51 changes: 51 additions & 0 deletions
51
apps/typed-binary-docs/src/content/docs/guides/custom-schema-types.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
--- | ||
title: Custom Schema Types | ||
description: A guide on how to create custom schema types in Typed Binary | ||
--- | ||
|
||
Custom schema types can be defined. They are, under the hood, classes that extend the `Schema<T>` base class. The generic `T` type represents what kind of data this schema serializes from and deserializes into. | ||
|
||
```ts | ||
import { | ||
ISerialInput, | ||
ISerialOutput, | ||
Schema, | ||
IRefResolver, | ||
} from 'typed-binary'; | ||
|
||
/** | ||
* A schema storing radians with 2 bytes of precision. | ||
*/ | ||
class RadiansSchema extends Schema<number> { | ||
read(input: ISerialInput): number { | ||
const low = input.readByte(); | ||
const high = input.readByte(); | ||
|
||
const discrete = (high << 8) | low; | ||
return (discrete / 65535) * Math.PI; | ||
} | ||
|
||
write(output: ISerialOutput, value: number): void { | ||
// The value will be wrapped to be in range of [0, Math.PI) | ||
const wrapped = ((value % Math.PI) + Math.PI) % Math.PI; | ||
// Quantizing the value to range of [0, 65535] | ||
const discrete = Math.min(Math.floor((wrapped / Math.PI) * 65535), 65535); | ||
|
||
const low = discrete & 0xff; | ||
const high = (discrete >> 8) & 0xff; | ||
|
||
output.writeByte(low); | ||
output.writeByte(high); | ||
} | ||
|
||
measure(_: number, measurer: IMeasurer = new Measurer()): IMeasurer { | ||
// The size of the data serialized by this schema | ||
// doesn't depend on the actual value. It's always 2 bytes. | ||
return measurer.add(2); | ||
} | ||
} | ||
|
||
// Creating a singleton instance of the schema, | ||
// since it has no configuration properties. | ||
export const radians = new RadiansSchema(); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
146 changes: 146 additions & 0 deletions
146
apps/typed-binary-docs/src/content/docs/guides/objects.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
--- | ||
title: Objects | ||
description: Objects store their properties in key-ascending-alphabetical order, one next to another. | ||
--- | ||
|
||
Primitive values in JavaScript can be composed into *Plain-Old-JavaScript-Objects*. This can be | ||
easily represented using the `object()` schema constructor function. | ||
|
||
## Simple objects | ||
|
||
```ts | ||
import { i32, string, object } from 'typed-binary'; | ||
|
||
// Simple object schema | ||
const Person = object({ | ||
firstName: string, | ||
lastName: string, | ||
age: i32, | ||
}); | ||
|
||
// Writing a Person | ||
Person.write(writer, { | ||
firstName: 'John', | ||
lastName: 'Doe', | ||
age: 43, | ||
}); | ||
|
||
console.log(JSON.stringify(Person.read(reader))); // { "firstName": "John", ... } | ||
``` | ||
|
||
:::note | ||
Objects store their properties in the order they are defined in the record passed into the `object()` constructor function. | ||
::: | ||
|
||
## Generic objects | ||
|
||
This feature allows for the parsing of a type that contains different fields depending on its previous values. For example, if you want to store an animal description, certain animal types might have differing features from one another. | ||
|
||
### Keyed by strings | ||
|
||
```ts | ||
import { | ||
i32, | ||
string, | ||
bool, | ||
generic, | ||
object, | ||
} from 'typed-binary'; | ||
|
||
// Generic object schema | ||
const Animal = generic( | ||
{ | ||
nickname: string, | ||
age: i32, | ||
}, | ||
{ | ||
dog: object({ | ||
// Animal can be a dog | ||
breed: string, | ||
}), | ||
cat: object({ | ||
// Animal can be a cat | ||
striped: bool, | ||
}), | ||
} | ||
); | ||
|
||
// Writing an Animal | ||
Animal.write(writer, { | ||
type: 'cat', // We're specyfing which concrete type we want this object to be. | ||
|
||
// Base properties | ||
nickname: 'James', | ||
age: 5, | ||
|
||
// Concrete type specific properties | ||
striped: true, | ||
}); | ||
|
||
// Deserializing the animal | ||
const animal = Animal.read(reader); | ||
console.log(JSON.stringify(animal)); // { "age": 5, "striped": true ... } | ||
|
||
// -- Type checking works here! -- | ||
// animal.type => 'cat' | 'dog' | ||
if (animal.type === 'cat') { | ||
// animal.type => 'cat' | ||
console.log("It's a cat!"); | ||
// animal.striped => bool | ||
console.log(animal.striped ? 'Striped' : 'Not striped'); | ||
} else { | ||
// animal.type => 'dog' | ||
console.log("It's a dog!"); | ||
// animal.breed => string | ||
console.log(`More specifically, a ${animal.breed}`); | ||
|
||
// This would result in a type error (Static typing FTW!) | ||
// console.log(`Striped: ${animal.striped}`); | ||
} | ||
``` | ||
|
||
### Keyed by an enum (byte) | ||
|
||
```ts | ||
import { BufferWriter, BufferReader, i32, string, genericEnum, object } from 'typed-binary'; | ||
|
||
enum AnimalType = { | ||
DOG = 0, | ||
CAT = 1, | ||
}; | ||
|
||
// Generic (enum) object schema | ||
const Animal = genericEnum({ | ||
nickname: string, | ||
age: i32, | ||
}, { | ||
[AnimalType.DOG]: object({ // Animal can be a dog | ||
breed: string, | ||
}), | ||
[AnimalType.CAT]: object({ // Animal can be a cat | ||
striped: bool, | ||
}), | ||
}); | ||
|
||
// ... | ||
// Same as for the string keyed case | ||
// ... | ||
|
||
// -- Type checking works here! -- | ||
// animal.type => AnimalType | ||
if (animal.type === AnimalType.CAT) { | ||
// animal.type => AnimalType.CAT | ||
console.log("It's a cat!"); | ||
// animal.striped => bool | ||
console.log(animal.striped ? "Striped" : "Not striped"); | ||
} | ||
else { | ||
// animal.type => AnimalType.DOG | ||
console.log("It's a dog!"); | ||
// animal.breed => string | ||
console.log(`More specifically, a ${animal.breed}`); | ||
|
||
// This would result in a type error (Static typing FTW!) | ||
// console.log(`Striped: ${animal.striped}`); | ||
} | ||
``` |
63 changes: 63 additions & 0 deletions
63
apps/typed-binary-docs/src/content/docs/guides/optionals.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
--- | ||
title: Optionals | ||
description: A guide on how optionals can be used to create variable-length schemas. | ||
--- | ||
|
||
Optionals are a good way of ensuring that no excessive data is stored as binary. | ||
|
||
They are encoded as: | ||
|
||
- `0` given `value === undefined`. | ||
- `1 encoded(value)` given `value !== undefined`. | ||
|
||
```ts | ||
import { | ||
BufferWriter, | ||
BufferReader, | ||
i32, | ||
string, | ||
object, | ||
optional, | ||
} from 'typed-binary'; | ||
|
||
const buffer = Buffer.alloc(16); | ||
const writer = new BufferWriter(buffer); | ||
const reader = new BufferReader(buffer); | ||
|
||
// Simple object schema | ||
const Address = object({ | ||
city: string, | ||
street: string, | ||
postalCode: string, | ||
}); | ||
|
||
// Simple object schema (with optional field) | ||
const Person = object({ | ||
firstName: string, | ||
lastName: string, | ||
age: i32, | ||
address: optional(Address), | ||
}); | ||
|
||
// Writing a Person (no address) | ||
Person.write(writer, { | ||
firstName: 'John', | ||
lastName: 'Doe', | ||
age: 43, | ||
}); | ||
|
||
// Writing a Person (with an address) | ||
Person.write(writer, { | ||
firstName: 'Jesse', | ||
lastName: 'Doe', | ||
age: 38, | ||
address: { | ||
city: 'New York', | ||
street: 'Binary St.', | ||
postalCode: '11-111', | ||
}, | ||
}); | ||
|
||
console.log(JSON.stringify(Person.read(reader).address)); // undefined | ||
console.log(JSON.stringify(Person.read(reader).address)); // { "city": "New York", ... } | ||
``` |
Oops, something went wrong.