Skip to content

Commit

Permalink
feat: use enums where possible
Browse files Browse the repository at this point in the history
  • Loading branch information
yamiteru committed May 5, 2024
1 parent 48e0de3 commit 78690e8
Show file tree
Hide file tree
Showing 18 changed files with 351 additions and 244 deletions.
82 changes: 41 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ Encodes JS data into `ArrayBuffer` based on `Type`.

```ts
const arrayBuffer = encode({
type: "object",
name: Name.Object,
value: [
{ key: "name", type: "string" },
{ key: "age", type: "int" }
{ key: "name", name: Name.String },
{ key: "age", name: Name.Int }
]
}, {
name: "Yamiteru",
Expand All @@ -60,10 +60,10 @@ Decodes `ArrayBuffer` into JS data based on `Type`.

```ts
const data = decode({
type: "object",
name: Name.Object,
value: [
{ key: "name", type: "string" },
{ key: "age", type: "int" }
{ key: "name", name: Name.String },
{ key: "age", name: Name.Int }
]
}, arrayBuffer);
```
Expand All @@ -77,10 +77,10 @@ const {
bytes, // 66
chunks // 9
} = estimate({
type: "object",
name: Name.Object,
value: [
{ key: "email", type: "string", maxLength: 64 },
{ key: "age", type: "int" }
{ key: "email", name: Name.String, maxLength: 64 },
{ key: "age", name: Name.Int }
]
}, {
MAX_POOL_SIZE: 256,
Expand All @@ -97,10 +97,10 @@ Once you create a `Type` you can easily infer it with `Infer`.

```ts
const user = {
type: "object",
name: Name.Object,
value: [
{ key: "name", type: "string" },
{ key: "age", type: "int" }
{ key: "name", name: Name.String },
{ key: "age", name: Name.Int }
]
} as const;

Expand All @@ -127,25 +127,25 @@ Choose number of chunks based on your expected size of the data wisely since if

```ts
{
type: "boolean";
name: Name.Boolean;
}
```

### Int

| size | signed | min | max | bytes |
|:-----|:-------|:------------|:-----------|:------|
| 8 | false | 0 | 255 | 1 |
| 8 | true | -127 | 128 | 1 |
| 16 | false | 0 | 65535 | 2 |
| 16 | true | -32768 | 32767 | 2 |
| 32 | false | 0 | 65535 | 4 |
| 32 | true | -2147483648 | 2147483647 | 4 |
| 1 | false | 0 | 255 | 1 |
| 1 | true | -127 | 128 | 1 |
| 2 | false | 0 | 65535 | 2 |
| 2 | true | -32768 | 32767 | 2 |
| 4 | false | 0 | 65535 | 4 |
| 4 | true | -2147483648 | 2147483647 | 4 |

```ts
{
type: "int";
size?: 8 | 16 | 32; // default: 8
name: Name.Int;
size?: 1 | 2 | 4; // default: 1
signed?: boolean; // default: false
}
```
Expand All @@ -154,60 +154,60 @@ Choose number of chunks based on your expected size of the data wisely since if

| size | min | max | bytes |
|:-----|:-------------------------|:------------------------|:------|
| 32 | -3.402823e+38 | 3.402823e+38 | 4 |
| 64 | -1.7976931348623157e+308 | 1.7976931348623157e+308 | 8 |
| 4 | -3.402823e+38 | 3.402823e+38 | 4 |
| 8 | -1.7976931348623157e+308 | 1.7976931348623157e+308 | 8 |

```ts
{
type: "float";
size?: 32 | 64; // default: 32
name: Name.Float;
size?: 4 | 8; // default: 4
}
```

### String

| size | string length (bytes) |
|:-----|:----------------------|
| 8 | 256 |
| 16 | 65536 |
| size | max length (bytes) |
|:-----|:-------------------|
| 1 | 256 |
| 2 | 65536 |

```ts
{
type: "string";
kind?: "ascii" | "utf8" | "utf16"; // default: "ascii"
size?: 8 | 16; // default: 8
name: Name.String;
kind?: Kind.Ascii | Kind.Utf8; // default: Kind.Ascii
size?: 1 | 2; // default: 1
}
```

### Object

```ts
{
type: "object";
name: Name.Object;
value: (Type.Any & Required<Type.Keyable>)[];
}
```

### Array

| size | array length (bytes) |
|:-----|:---------------------|
| 8 | 256 |
| 16 | 65536 |
| size | max length (bytes) |
|:-----|:-------------------|
| 1 | 256 |
| 2 | 65536 |

```ts
{
type: "array";
name: Name.Array;
value: Type.Any;
size?: 8 | 16; // default: 8
size?: 1 | 2; // default: 1
}
```

### Tuple

```ts
{
type: "array";
name: Name.Tuple;
value: Type.Any[];
}
```
Expand All @@ -216,7 +216,7 @@ Choose number of chunks based on your expected size of the data wisely since if

```ts
{
type: "enum";
name: Name.Enum;
value: unknown[];
}
```
Expand Down
3 changes: 2 additions & 1 deletion biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"noExplicitAny": "off"
},
"style": {
"noParameterAssign": "off"
"noParameterAssign": "off",
"useEnumInitializers": "off"
}
}
},
Expand Down
71 changes: 43 additions & 28 deletions src/decode.ts
Original file line number Diff line number Diff line change
@@ -1,49 +1,59 @@
import type { Infer, State, Type } from "./types";
import type { Decoder, Decoders, Infer, State, Type } from "./types";
import { Kind } from "./types";

const utf8 = new TextDecoder("utf-8");
const ascii = new TextDecoder("ascii");

const TYPES = {
boolean: (state: State, _: Type.Boolean) => {
const TYPES = [
// Boolean
(state: State, _: Type.Boolean) => {
return state.view.getUint8(state.offset) === 1;
},
int: (state: State, type: Type.Int) => {
type.size ??= 8;
// Int
(state: State, type: Type.Int) => {
type.size ??= 1;

const result = state.view[`get${type.signed ? "Int" : "Uint"}${type.size}`](
state.offset,
);
const result = state.view[
`get${type.signed ? "Int" : "Uint"}${(type.size * 8) as 8 | 16 | 32}`
](state.offset);

state.offset += type.size / 8;
state.offset += type.size;

return result;
},
float: (state: State, type: Type.Float) => {
type.size ??= 32;
// Float
(state: State, type: Type.Float) => {
type.size ??= 4;

const result = state.view[`getFloat${type.size}`](state.offset);
const result = state.view[`getFloat${(type.size * 8) as 32 | 64}`](
state.offset,
);

state.offset += type.size / 8;
state.offset += type.size;

return result;
},
string: (state: State, type: Type.String) => {
type.size ??= 8;
type.kind ??= "ascii";
// String
(state: State, type: Type.String) => {
type.size ??= 1;
type.kind ??= Kind.Ascii;

const length = state.view[`getUint${type.size}`](state.offset);
const length = state.view[`getUint${(type.size * 8) as 8 | 16}`](
state.offset,
);

state.offset += type.size / 8;
state.offset += type.size;

const result = (type.kind === "ascii" ? ascii : utf8).decode(
const result = (type.kind === Kind.Ascii ? ascii : utf8).decode(
new Uint8Array(state.buffer, state.offset, length),
);

state.offset += length;

return result;
},
object: (state: State, type: Type.Object) => {
// Object
(state: State, type: Type.Object) => {
const result: Record<string, unknown> = {};

for (let i = 0; i < type.value.length; ++i) {
Expand All @@ -52,12 +62,15 @@ const TYPES = {

return result;
},
array: (state: State, type: Type.Array) => {
type.size ??= 8;
// Array
(state: State, type: Type.Array) => {
type.size ??= 1;

const length = state.view[`getUint${type.size}`](state.offset);
const length = state.view[`getUint${(type.size * 8) as 8 | 16}`](
state.offset,
);

state.offset += type.size / 8;
state.offset += type.size;

const result: unknown[] = [];

Expand All @@ -67,10 +80,12 @@ const TYPES = {

return result;
},
enum: (state: State, type: Type.Enum) => {
// Enum
(state: State, type: Type.Enum) => {
return type.value[state.view.getUint8(state.offset++)];
},
tuple: (state: State, type: Type.Tuple) => {
// Tuple
(state: State, type: Type.Tuple) => {
const result: unknown[] = [];

for (let i = 0; i < type.value.length; ++i) {
Expand All @@ -79,7 +94,7 @@ const TYPES = {

return result;
},
};
] satisfies Decoders;

const run = (state: State, type: Type.Any) => {
if (type.nullable) {
Expand All @@ -91,7 +106,7 @@ const run = (state: State, type: Type.Any) => {
}
}

const result = (TYPES as any)[type.type](state, type);
const result = (TYPES[type.name] as Decoder)(state, type);

type.assert?.(result);

Expand Down
Loading

0 comments on commit 78690e8

Please sign in to comment.