From 78690e8cf2b45861b2470d8ba66d36b2d7b2f73f Mon Sep 17 00:00:00 2001 From: Yamiteru Date: Sun, 5 May 2024 19:15:57 +0200 Subject: [PATCH] feat: use enums where possible --- README.md | 82 ++++++++++++------------ biome.json | 3 +- src/decode.ts | 71 ++++++++++++--------- src/encode.ts | 80 ++++++++++++++---------- src/estimate.ts | 51 ++++++++------- src/types.ts | 139 +++++++++++++++++++++++++++++++---------- tests/array.test.ts | 20 +++--- tests/assert.test.ts | 10 +-- tests/boolean.test.ts | 4 +- tests/enum.test.ts | 8 +-- tests/estimate.test.ts | 60 +++++++++--------- tests/float.test.ts | 8 +-- tests/int.test.ts | 16 ++--- tests/nullable.test.ts | 8 +-- tests/object.test.ts | 10 +-- tests/string.test.ts | 11 ++-- tests/tuple.test.ts | 10 +-- tsconfig.json | 4 +- 18 files changed, 351 insertions(+), 244 deletions(-) diff --git a/README.md b/README.md index 79066ca..dd26b41 100644 --- a/README.md +++ b/README.md @@ -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", @@ -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); ``` @@ -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, @@ -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; @@ -127,7 +127,7 @@ Choose number of chunks based on your expected size of the data wisely since if ```ts { - type: "boolean"; + name: Name.Boolean; } ``` @@ -135,17 +135,17 @@ Choose number of chunks based on your expected size of the data wisely since if | 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 } ``` @@ -154,28 +154,28 @@ 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 } ``` @@ -183,23 +183,23 @@ Choose number of chunks based on your expected size of the data wisely since if ```ts { - type: "object"; + name: Name.Object; value: (Type.Any & Required)[]; } ``` ### 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 } ``` @@ -207,7 +207,7 @@ Choose number of chunks based on your expected size of the data wisely since if ```ts { - type: "array"; + name: Name.Tuple; value: Type.Any[]; } ``` @@ -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[]; } ``` diff --git a/biome.json b/biome.json index f4aed26..8d2fbfd 100644 --- a/biome.json +++ b/biome.json @@ -13,7 +13,8 @@ "noExplicitAny": "off" }, "style": { - "noParameterAssign": "off" + "noParameterAssign": "off", + "useEnumInitializers": "off" } } }, diff --git a/src/decode.ts b/src/decode.ts index a4b433a..36ce4e4 100644 --- a/src/decode.ts +++ b/src/decode.ts @@ -1,41 +1,50 @@ -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), ); @@ -43,7 +52,8 @@ const TYPES = { return result; }, - object: (state: State, type: Type.Object) => { + // Object + (state: State, type: Type.Object) => { const result: Record = {}; for (let i = 0; i < type.value.length; ++i) { @@ -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[] = []; @@ -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) { @@ -79,7 +94,7 @@ const TYPES = { return result; }, -}; +] satisfies Decoders; const run = (state: State, type: Type.Any) => { if (type.nullable) { @@ -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); diff --git a/src/encode.ts b/src/encode.ts index d6e5432..108ddd6 100644 --- a/src/encode.ts +++ b/src/encode.ts @@ -1,37 +1,44 @@ -import type { Infer, State, Type } from "./types"; +import type { Encoder, Encoders, Infer, State, Type } from "./types"; +import { Kind } from "./types"; import { alloc, free } from "./utils"; const encoder = new TextEncoder(); -const TYPES = { - boolean: (state: State, _: Type.Boolean, value: boolean) => { +const TYPES = [ + // Boolean + (state: State, _: Type.Boolean, value: boolean) => { state.view.setUint8(state.offset++, +value); }, - int: (state: State, type: Type.Int, value: number) => { - type.size ??= 8; + // Int + (state: State, type: Type.Int, value: number) => { + type.size ??= 1; - state.view[`set${type.signed ? "Int" : "Uint"}${type.size}`]( - state.offset, - value, - ); + state.view[ + `set${type.signed ? "Int" : "Uint"}${(type.size * 8) as 8 | 16 | 32}` + ](state.offset, value); - state.offset += type.size / 8; + state.offset += type.size; }, - float: (state: State, type: Type.Float, value: number) => { - type.size ??= 32; + // Float + (state: State, type: Type.Float, value: number) => { + type.size ??= 4; - state.view[`setFloat${type.size}`](state.offset, value); + state.view[`setFloat${(type.size * 8) as 32 | 64}`](state.offset, value); - state.offset += type.size / 8; + state.offset += type.size; }, - string: (state: State, type: Type.String, value: string) => { - type.size ??= 8; - type.kind ??= "ascii"; + // String + (state: State, type: Type.String, value: string) => { + type.size ??= 1; + type.kind ??= Kind.Ascii; - if (type.kind === "ascii") { - state.view[`setUint${type.size}`](state.offset, value.length); + if (type.kind === Kind.Ascii) { + state.view[`setUint${(type.size * 8) as 8 | 16}`]( + state.offset, + value.length, + ); - state.offset += type.size / 8; + state.offset += type.size; for (let i = 0; i < value.length; ++i) { state.view.setUint8(state.offset++, value.charCodeAt(i)); @@ -39,38 +46,45 @@ const TYPES = { } else { const written = encoder.encodeInto( value, - new Uint8Array(state.buffer, state.offset + type.size / 8), + new Uint8Array(state.buffer, state.offset + type.size), ).written; - state.view[`setUint${type.size}`](state.offset, written); - state.offset += type.size / 8 + written; + state.view[`setUint${(type.size * 8) as 8 | 16}`](state.offset, written); + state.offset += type.size + written; } }, - object: (state: State, type: Type.Object, value: Record) => { + // Object + (state: State, type: Type.Object, value: Record) => { for (let i = 0; i < type.value.length; ++i) { run(state, type.value[i], value[type.value[i].key]); } }, - array: (state: State, type: Type.Array, value: unknown[]) => { - type.size ??= 8; + // Array + (state: State, type: Type.Array, value: unknown[]) => { + type.size ??= 1; - state.view[`setUint${type.size}`](state.offset, value.length); + state.view[`setUint${(type.size * 8) as 8 | 16}`]( + state.offset, + value.length, + ); - state.offset += type.size / 8; + state.offset += type.size; for (let i = 0; i < value.length; ++i) { run(state, type.value, value[i]); } }, - enum: (state: State, type: Type.Enum, value: string) => { + // Enum + (state: State, type: Type.Enum, value: string) => { state.view.setUint8(state.offset++, type.value.indexOf(value)); }, - tuple: (state: State, type: Type.Tuple, value: unknown[]) => { + // Tuple + (state: State, type: Type.Tuple, value: unknown[]) => { for (let i = 0; i < type.value.length; ++i) { run(state, type.value[i], value[i]); } }, -}; +] satisfies Encoders; const run = (state: State, type: Type.Any, value: unknown) => { if (type.nullable) { @@ -85,10 +99,10 @@ const run = (state: State, type: Type.Any, value: unknown) => { type.assert?.(value); - (TYPES as any)[type.type](state, type, value); + (TYPES[type.name] as Encoder)(state, type, value); }; -export const encode = <$Type extends Type.Any>( +export const encode = ( type: $Type, value: Infer<$Type>, chunks = 1, diff --git a/src/estimate.ts b/src/estimate.ts index ebfcd9f..b75e2a2 100644 --- a/src/estimate.ts +++ b/src/estimate.ts @@ -1,4 +1,5 @@ -import type { Settings, Type } from "./types"; +import type { Estimate, Estimates, Settings, Type } from "./types"; +import { Kind } from "./types"; import { SETTINGS } from "./utils"; type MaxLength = { @@ -6,33 +7,39 @@ type MaxLength = { }; const STRING = { - ascii: 1, - utf8: 3, + [Kind.Ascii]: 1, + [Kind.Utf8]: 3, }; const ARRAY = { - 8: 256, - 16: 65_536, + 1: 256, + 2: 65_536, }; -const TYPES = { - boolean: (_: Type.Boolean) => 1, - int: (type: Type.Int) => (type.size ?? 8) / 8, - float: (type: Type.Float) => (type.size ?? 32) / 8, - string: (type: Type.String & MaxLength) => - (type.size ?? 8) / 8 + - (type.maxLength ?? ARRAY[type.size ?? 8]) * STRING[type.kind ?? "ascii"], - object: (type: Type.Object) => - type.value.reduce((acc, curr) => acc + run(curr), 0), - array: (type: Type.Array & MaxLength) => - (type.size ?? 8) / 8 + - (type.maxLength ?? ARRAY[type.size ?? 8]) * run(type.value), - enum: (_: Type.Enum) => 1, - tuple: (type: Type.Tuple) => - type.value.reduce((acc, curr) => acc + run(curr), 0), -}; +const TYPES = [ + // Boolean + (_: Type.Boolean) => 1, + // Int + (type: Type.Int) => type.size ?? 1, + // Float + (type: Type.Float) => type.size ?? 4, + // String + (type: Type.String & MaxLength) => + (type.size ?? 1) + + (type.maxLength ?? ARRAY[type.size ?? 1]) * STRING[type.kind ?? Kind.Ascii], + // Object + (type: Type.Object) => type.value.reduce((acc, curr) => acc + run(curr), 0), + // Array + (type: Type.Array & MaxLength) => + (type.size ?? 1) + + (type.maxLength ?? ARRAY[type.size ?? 1]) * run(type.value), + // Enum + (_: Type.Enum) => 1, + // Tuple + (type: Type.Tuple) => type.value.reduce((acc, curr) => acc + run(curr), 0), +] satisfies Estimates; -const run = (type: Type.Any) => (TYPES as any)[type.type](type) as number; +const run = (type: Type.Any): number => (TYPES[type.name] as Estimate)(type); export const estimate = (type: Type.Any, settings: Settings = SETTINGS) => { const bytes = run(type); diff --git a/src/types.ts b/src/types.ts index 6b76423..f1e908d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,5 +1,43 @@ type New<$Type extends Type.Any> = $Type & Type.Nullable & Type.Assertable & Type.Keyable; +export enum Name { + Boolean, + Int, + Float, + String, + Object, + Array, + Enum, + Tuple +} + +export enum Kind { + Ascii, + Utf8 +} + +export type NameTypeMap = { + [Name.Boolean]: Type.Boolean; + [Name.Int]: Type.Int; + [Name.Float]: Type.Float; + [Name.String]: Type.String; + [Name.Object]: Type.Object; + [Name.Array]: Type.Array; + [Name.Enum]: Type.Enum; + [Name.Tuple]: Type.Tuple; +}; + +export type NameValueMap = { + [Name.Boolean]: boolean; + [Name.Int]: number; + [Name.Float]: number; + [Name.String]: string; + [Name.Object]: Record; + [Name.Array]: unknown[]; + [Name.Enum]: string; + [Name.Tuple]: unknown[]; +}; + export namespace Type { export type Nullable = { nullable?: boolean; @@ -13,62 +51,70 @@ export namespace Type { key?: string; }; - export type Any = New<{ type: string }> & Record; - - export type Object = New<{ - type: "object"; - value: (Any & Required)[]; - }>; - - export type Array = New<{ - type: "array"; - value: Any; - size?: 8 | 16; - }>; - export type Boolean = New<{ - type: "boolean"; + name: Name.Boolean; }>; export type Int = New<{ - type: "int"; + name: Name.Int; signed?: boolean; - size?: 8 | 16 | 32; + size?: 1 | 2 | 4; }>; export type Float = New<{ - type: "float"; - size?: 32 | 64; + name: Name.Float; + size?: 4 | 8; }>; export type String = New<{ - type: "string"; - kind?: "ascii" | "utf8"; - size?: 8 | 16; + name: Name.String; + kind?: Kind; + size?: 1 | 2; + }>; + + export type Object = New<{ + name: Name.Object; + value: readonly (Any & Required)[]; + }>; + + export type Array = New<{ + name: Name.Array; + value: Any; + size?: 1 | 2; }>; export type Enum = New<{ - type: "enum"; - value: string[]; + name: Name.Enum; + value: readonly string[]; }>; export type Tuple = New<{ - type: "tuple"; - value: Any[]; + name: Name.Tuple; + value: readonly Any[]; }>; + + export type Any = + | Boolean + | Int + | Float + | String + | Object + | Array + | Enum + | Tuple; } type Primitive = { - int: number; - float: number; - boolean: boolean; - string: string; + [Name.Boolean]: boolean; + [Name.Int]: number; + [Name.Float]: number; + [Name.String]: string; }; -type PrimitiveKey = keyof Primitive; +type PrimitiveKey = Name.Boolean | Name.Int | Name.Float | Name.String; -type InferTuple<$Tuple extends unknown[]> = $Tuple extends Type.Any[] - ? $Tuple extends [infer $Head, ...infer $Tail] +type InferTuple<$Tuple extends readonly unknown[]> = $Tuple extends readonly Type.Any[] + ? $Tuple extends readonly [infer $Head, ...infer $Tail] ? [Infer<$Head>, ...InferTuple<$Tail>] : [] : []; @@ -77,7 +123,7 @@ type Nullable<$Boolean extends boolean, $Type> = $Boolean extends true ? $Type | null : $Type; -type InferName<$Type> = $Type extends Type.Any ? $Type["type"]: never; +type InferName<$Type> = $Type extends Type.Any ? $Type["name"]: never; type InferNullable<$Type> = $Type extends Required ? $Type["nullable"] @@ -89,7 +135,7 @@ type InferObject<$Type extends Type.Object> = { export type Infer< $Type, - $Name extends string = InferName<$Type>, + $Name extends Name = InferName<$Type>, $Nullable extends boolean = InferNullable<$Type> > = $Type extends Type.Any ? $Name extends PrimitiveKey @@ -118,3 +164,28 @@ export type Settings = { MAX_POOL_SIZE: number; DEFAULT_CHUNK_SIZE: number; }; + +export type Encoders = { + [$Key in Name]: ( + state: State, + type: NameTypeMap[$Key], + value: NameValueMap[$Key] + ) => void; +}; + +export type Encoder = (state: State, type: Type.Any, value: unknown) => void; + +export type Decoders = { + [$Key in Name]: ( + state: State, + type: NameTypeMap[$Key] + ) => unknown; +}; + +export type Decoder = (state: State, type: Type.Any) => unknown; + +export type Estimates = { + [$Key in Name]: (type: NameTypeMap[$Key]) => number; +}; + +export type Estimate = (type: Type.Any) => number diff --git a/tests/array.test.ts b/tests/array.test.ts index ce4c8de..45b9626 100644 --- a/tests/array.test.ts +++ b/tests/array.test.ts @@ -1,6 +1,6 @@ import {fc, test} from "@fast-check/vitest"; import {beforeEach, describe, expect} from "vitest"; -import {decode, encode, init, Type} from "../src"; +import {decode, encode, init, Name} from "../src"; import {UINT16, UINT8} from "./shared"; describe("array", () => { @@ -8,10 +8,10 @@ describe("array", () => { test.prop([fc.array(fc.integer(UINT8), { maxLength: UINT8.max })])("8", (value) => { const type = { - type: "array", - size: 8, - value: {type: "int", size: 8} - } satisfies Type.Array; + name: Name.Array, + size: 1, + value: {name: Name.Int, size: 1} + } as const; const encoded = encode(type, value); const decoded = decode(type, encoded); @@ -21,14 +21,14 @@ describe("array", () => { test.prop([fc.array(fc.integer(UINT8), { maxLength: UINT16.max })])("8", (value) => { const type = { - type: "array", - size: 16, - value: {type: "int", size: 8} - } satisfies Type.Array; + name: Name.Array, + size: 2, + value: {name: Name.Int, size: 1} + } as const; const encoded = encode(type, value); const decoded = decode(type, encoded); expect(decoded).toEqual(value); }); -}); \ No newline at end of file +}); diff --git a/tests/assert.test.ts b/tests/assert.test.ts index ea360fe..2e09588 100644 --- a/tests/assert.test.ts +++ b/tests/assert.test.ts @@ -1,6 +1,6 @@ import {fc, test} from "@fast-check/vitest"; import {beforeEach, describe, expect} from "vitest"; -import {decode, encode, init, Type} from "../src"; +import {decode, encode, init, Name, Type} from "../src"; import {UINT8} from "./shared"; describe("assert", () => { @@ -15,7 +15,7 @@ describe("assert", () => { }; test.prop([fc.integer({ min: 1, max: UINT8.max})])("passes", (value) => { - const type = { type: "int", size: 8, assert } satisfies Type.Int; + const type = { name: Name.Int, size: 1, assert } satisfies Type.Int; const encoded = encode(type, value); const decoded = decode(type, encoded); @@ -24,8 +24,8 @@ describe("assert", () => { }); test.prop([fc.constant(0)])("throws", (value) => { - const throwType = { type: "int", size: 8, assert } satisfies Type.Int; - const passType = { type: "int", size: 8 } satisfies Type.Int; + const throwType = { name: Name.Int, size: 1, assert } satisfies Type.Int; + const passType = { name: Name.Int, size: 1 } satisfies Type.Int; expect(() => encode(throwType, value)).toThrow("zero"); @@ -33,4 +33,4 @@ describe("assert", () => { expect(() => decode(throwType, encoded)).toThrow("zero"); }); -}); \ No newline at end of file +}); diff --git a/tests/boolean.test.ts b/tests/boolean.test.ts index 8082778..4e3a440 100644 --- a/tests/boolean.test.ts +++ b/tests/boolean.test.ts @@ -1,12 +1,12 @@ import {fc, test} from "@fast-check/vitest"; import {beforeEach, expect} from "vitest"; -import {decode, encode, init, Type} from "../src"; +import {decode, encode, init, Name, Type} from "../src"; beforeEach(() => init()); test.prop([fc.boolean()])("boolean", (value) => { const type = { - type: "boolean", + name: Name.Boolean, } satisfies Type.Boolean; const encoded = encode(type, value); diff --git a/tests/enum.test.ts b/tests/enum.test.ts index 6ae3781..d54c7e1 100644 --- a/tests/enum.test.ts +++ b/tests/enum.test.ts @@ -1,16 +1,16 @@ import {fc, test} from "@fast-check/vitest"; import {beforeEach, expect} from "vitest"; -import {decode, encode, init, Type} from "../src"; +import {decode, encode, init, Name} from "../src"; beforeEach(() => init()); test.prop([fc.oneof(fc.constant("ADMIN"), fc.constant("USER"))])("enum", (value) => { const type = { - type: "enum", + name: Name.Enum, value: ["ADMIN", "USER"] - } satisfies Type.Enum; + } as const; - const encoded = encode(type, value); + const encoded = encode(type, value as "ADMIN" | "USER"); const decoded = decode(type, encoded); expect(decoded).toEqual(value); diff --git a/tests/estimate.test.ts b/tests/estimate.test.ts index 1eaeab8..e874926 100644 --- a/tests/estimate.test.ts +++ b/tests/estimate.test.ts @@ -1,6 +1,6 @@ import {describe, expect} from "vitest"; import {test} from "@fast-check/vitest"; -import {estimate, Settings} from "../src"; +import {estimate, Kind, Name, Settings} from "../src"; const SETTINGS = { MAX_POOL_SIZE: 256, @@ -10,36 +10,36 @@ const SETTINGS = { describe("estimate", () => { test("boolean", () => { - expect(estimate({ type: "boolean" }, SETTINGS)).toEqual({ + expect(estimate({ name: Name.Boolean }, SETTINGS)).toEqual({ bytes: 1, chunks: 1 }); }); test("int", () => { - expect(estimate({ type: "int", size: 8 }, SETTINGS)).toEqual({ + expect(estimate({ name: Name.Int, size: 1 }, SETTINGS)).toEqual({ bytes: 1, chunks: 1 }); - expect(estimate({ type: "int", size: 16 }, SETTINGS)).toEqual({ + expect(estimate({ name: Name.Int, size: 2 }, SETTINGS)).toEqual({ bytes: 2, chunks: 1 }); - expect(estimate({ type: "int", size: 32 }, SETTINGS)).toEqual({ + expect(estimate({ name: Name.Int, size: 4 }, SETTINGS)).toEqual({ bytes: 4, chunks: 1 }); }); test("float", () => { - expect(estimate({ type: "float", size: 32 }, SETTINGS)).toEqual({ + expect(estimate({ name: Name.Float, size: 4 }, SETTINGS)).toEqual({ bytes: 4, chunks: 1 }); - expect(estimate({ type: "float", size: 64 }, SETTINGS)).toEqual({ + expect(estimate({ name: Name.Float, size: 8 }, SETTINGS)).toEqual({ bytes: 8, chunks: 1 }); @@ -47,22 +47,22 @@ describe("estimate", () => { test("string", () => { - expect(estimate({ type: "string", kind: "ascii", size: 8 }, SETTINGS)).toEqual({ + expect(estimate({ name: Name.String, kind: Kind.Ascii, size: 1 }, SETTINGS)).toEqual({ bytes: 257, chunks: 33 }); - expect(estimate({ type: "string", kind: "ascii", size: 8, maxLength: 16 }, SETTINGS)).toEqual({ + expect(estimate({ name: Name.String, kind: Kind.Ascii, size: 1, maxLength: 16 }, SETTINGS)).toEqual({ bytes: 17, chunks: 3 }); - expect(estimate({ type: "string", kind: "utf8", size: 8 }, SETTINGS)).toEqual({ + expect(estimate({ name: Name.String, kind: Kind.Utf8, size: 1 }, SETTINGS)).toEqual({ bytes: 769, chunks: 97 }); - expect(estimate({ type: "string", kind: "utf8", size: 8, maxLength: 16 }, SETTINGS)).toEqual({ + expect(estimate({ name: Name.String, kind: Kind.Utf8, size: 1, maxLength: 16 }, SETTINGS)).toEqual({ bytes: 49, chunks: 7 }); @@ -71,10 +71,10 @@ describe("estimate", () => { test("object", () => { expect(estimate({ - type: "object", + name: Name.Object, value: [ - {key: "email", type: "string"}, - {key: "age", type: "int"}, + {key: "email", name: Name.String}, + {key: "age", name: Name.Int}, ] }, SETTINGS)).toEqual({ bytes: 258, @@ -82,10 +82,10 @@ describe("estimate", () => { }); expect(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}, ] }, SETTINGS)).toEqual({ bytes: 66, @@ -95,16 +95,16 @@ describe("estimate", () => { test("array", () => { expect(estimate({ - type: "array", - value: {type: "string"}, + name: Name.Array, + value: {name: Name.String}, }, SETTINGS)).toEqual({ bytes: 65793, chunks: 8225 }); expect(estimate({ - type: "array", - value: {type: "string"}, + name: Name.Array, + value: {name: Name.String}, maxLength: 16 }, SETTINGS)).toEqual({ bytes: 4113, @@ -112,8 +112,8 @@ describe("estimate", () => { }); expect(estimate({ - type: "array", - value: {type: "string", maxLength: 16}, + name: Name.Array, + value: {name: Name.String, maxLength: 16}, maxLength: 16 }, SETTINGS)).toEqual({ bytes: 273, @@ -122,7 +122,7 @@ describe("estimate", () => { }); test("enum", () => { - expect(estimate({ type: "enum", value: ["ADMIN", "USER"] }, SETTINGS)).toEqual({ + expect(estimate({ name: Name.Enum, value: ["ADMIN", "USER"] }, SETTINGS)).toEqual({ bytes: 1, chunks: 1 }); @@ -130,10 +130,10 @@ describe("estimate", () => { test("tuple", () => { expect(estimate({ - type: "tuple", + name: Name.Tuple, value: [ - {type: "string"}, - {type: "int"}, + {name: Name.String}, + {name: Name.Int}, ] }, SETTINGS)).toEqual({ bytes: 258, @@ -141,10 +141,10 @@ describe("estimate", () => { }); expect(estimate({ - type: "tuple", + name: Name.Tuple, value: [ - {type: "string", maxLength: 16}, - {type: "int"}, + {name: Name.String, maxLength: 16}, + {name: Name.Int}, ] }, SETTINGS)).toEqual({ bytes: 18, diff --git a/tests/float.test.ts b/tests/float.test.ts index 2e12130..546c527 100644 --- a/tests/float.test.ts +++ b/tests/float.test.ts @@ -1,12 +1,12 @@ import {fc, test} from "@fast-check/vitest"; import {beforeEach, describe, expect} from "vitest"; -import {decode, encode, init, Type} from "../src"; +import {decode, encode, init, Name} from "../src"; describe("float", () => { beforeEach(() => init()); test.prop([fc.float()])("float32", (value) => { - const type = { type: "float", size: 32 } satisfies Type.Float; + const type = { name: Name.Float, size: 4 } as const; const encoded = encode(type, value); const decoded = decode(type, encoded); @@ -15,11 +15,11 @@ describe("float", () => { }); test.prop([fc.integer()])("float64", (value) => { - const type = { type: "float", size: 64 } satisfies Type.Float; + const type = { name: Name.Float, size: 8 } as const; const encoded = encode(type, value); const decoded = decode(type, encoded); expect(decoded).toBe(value); }); -}); \ No newline at end of file +}); diff --git a/tests/int.test.ts b/tests/int.test.ts index 34bc0f2..7b668be 100644 --- a/tests/int.test.ts +++ b/tests/int.test.ts @@ -1,13 +1,13 @@ import {fc, test} from "@fast-check/vitest"; import {beforeEach, describe, expect} from "vitest"; -import {decode, encode, init, Type} from "../src"; +import {decode, encode, init, Name } from "../src"; import {INT16, INT32, INT8, UINT16, UINT32, UINT8} from "./shared"; describe("int", () => { beforeEach(() => init()); test.prop([fc.integer(UINT8)])("uint8", (value) => { - const type = { type: "int", size: 8, signed: false } satisfies Type.Int; + const type = { name: Name.Int, size: 1, signed: false } as const; const encoded = encode(type, value); const decoded = decode(type, encoded); @@ -16,7 +16,7 @@ describe("int", () => { }); test.prop([fc.integer(UINT16)])("uint16", (value) => { - const type = { type: "int", size: 16, signed: false } satisfies Type.Int; + const type = { name: Name.Int, size: 2, signed: false } as const; const encoded = encode(type, value); const decoded = decode(type, encoded); @@ -25,7 +25,7 @@ describe("int", () => { }); test.prop([fc.integer(UINT32)])("uint32", (value) => { - const type = { type: "int", size: 32, signed: false } satisfies Type.Int; + const type = { name: Name.Int, size: 4, signed: false } as const; const encoded = encode(type, value); const decoded = decode(type, encoded); @@ -34,7 +34,7 @@ describe("int", () => { }); test.prop([fc.integer(INT8)])("int8", (value) => { - const type = { type: "int", size: 8, signed: true } satisfies Type.Int; + const type = { name: Name.Int, size: 1, signed: true } as const; const encoded = encode(type, value); const decoded = decode(type, encoded); @@ -43,7 +43,7 @@ describe("int", () => { }); test.prop([fc.integer(INT16)])("int16", (value) => { - const type = { type: "int", size: 16, signed: true } satisfies Type.Int; + const type = { name: Name.Int, size: 2, signed: true } as const; const encoded = encode(type, value); const decoded = decode(type, encoded); @@ -52,11 +52,11 @@ describe("int", () => { }); test.prop([fc.integer(INT32)])("int32", (value) => { - const type = { type: "int", size: 32, signed: true } satisfies Type.Int; + const type = { name: Name.Int, size: 4, signed: true } as const; const encoded = encode(type, value); const decoded = decode(type, encoded); expect(decoded).toBe(value); }); -}); \ No newline at end of file +}); diff --git a/tests/nullable.test.ts b/tests/nullable.test.ts index 06f9a05..6ba71f3 100644 --- a/tests/nullable.test.ts +++ b/tests/nullable.test.ts @@ -1,13 +1,13 @@ import {fc, test} from "@fast-check/vitest"; import {beforeEach, describe, expect} from "vitest"; -import {decode, encode, init, Type} from "../src"; +import {decode, encode, init, Name, Type} from "../src"; import {UINT8} from "./shared"; describe("nullable", () => { beforeEach(() => init()); test.prop([fc.oneof(fc.integer(UINT8), fc.constant(null))])("true", (value) => { - const type = { type: "int", size: 8, nullable: true } satisfies Type.Int; + const type = { name: Name.Int, size: 1, nullable: true } satisfies Type.Int; const encoded = encode(type, value); const decoded = decode(type, encoded); @@ -16,11 +16,11 @@ describe("nullable", () => { }); test.prop([fc.integer(UINT8)])("false", (value) => { - const type = { type: "int", size: 8, nullable: false } satisfies Type.Int; + const type = { name: Name.Int, size: 1, nullable: false } satisfies Type.Int; const encoded = encode(type, value); const decoded = decode(type, encoded); expect(decoded).toBe(value); }); -}); \ No newline at end of file +}); diff --git a/tests/object.test.ts b/tests/object.test.ts index 1e52ae3..8c495f9 100644 --- a/tests/object.test.ts +++ b/tests/object.test.ts @@ -1,6 +1,6 @@ import {fc, test} from "@fast-check/vitest"; import {beforeEach, expect} from "vitest"; -import {decode, encode, init, Type} from "../src"; +import {decode, encode, init, Kind, Name} from "../src"; beforeEach(() => init()); @@ -9,12 +9,12 @@ test.prop([fc.record({ age: fc.integer({min: 0, max: 150}), })])("object", (value) => { const type = { - type: "object", + name: Name.Object, value: [ - {key: "name", type: "string", kind: "ascii", size: 8}, - {key: "age", type: "int", size: 8}, + {key: "name", name: Name.String, kind: Kind.Ascii, size: 1}, + {key: "age", name: Name.Int, size: 1}, ] - } satisfies Type.Object; + } as const; const encoded = encode(type, value); const decoded = decode(type, encoded); diff --git a/tests/string.test.ts b/tests/string.test.ts index 5c63170..8c2f185 100644 --- a/tests/string.test.ts +++ b/tests/string.test.ts @@ -1,6 +1,6 @@ import {fc, test} from "@fast-check/vitest"; import {beforeEach, describe, expect} from "vitest"; -import {decode, encode, init, Type} from "../src"; +import {decode, encode, init, Kind, Name} from "../src"; import {UINT16, UINT8} from "./shared"; describe("string", () => { @@ -8,7 +8,7 @@ describe("string", () => { describe("ascii", () => { test.prop([fc.string({ maxLength: UINT8.max })])("8", (value) => { - const type = { type: "string", kind: "ascii", size: 8 } satisfies Type.String; + const type = { name: Name.String, kind: Kind.Ascii, size: 1 } as const; const encoded = encode(type, value); const decoded = decode(type, encoded); @@ -17,7 +17,7 @@ describe("string", () => { }); test.prop([fc.string({ maxLength: UINT16.max })])("16", (value) => { - const type = { type: "string", kind: "ascii", size: 16 } satisfies Type.String; + const type = { name: Name.String, kind: Kind.Ascii, size: 2 } as const; const encoded = encode(type, value); const decoded = decode(type, encoded); @@ -28,7 +28,7 @@ describe("string", () => { describe("utf8", () => { test("8", () => { - const type = { type: "string", kind: "utf8", size: 8 } satisfies Type.String; + const type = { name: Name.String, kind: Kind.Utf8, size: 1 } as const; const value = "ᥞH놀tDҚKh~Ӷ牅򞿫Ⱥ򐻗*񩳾䷂Q🚂֔񴕈̾彷񩺞%ޮ􀯥򲰕沤礓ͷ񏴶"; const encoded = encode(type, value); @@ -38,7 +38,7 @@ describe("string", () => { }); test("16", () => { - const type = { type: "string", kind: "utf8", size: 16 } satisfies Type.String; + const type = { name: Name.String, kind: Kind.Utf8, size: 2 } as const; const value = "ᥞH놀tDҚKh~Ӷ牅򞿫Ⱥ򐻗*񩳾䷂Q🚂֔񴕈̾彷񩺞%ޮ􀯥򲰕沤礓ͷ񏴶"; const encoded = encode(type, value); @@ -47,5 +47,4 @@ describe("string", () => { expect(decoded).toBe(value); }); }); - }); diff --git a/tests/tuple.test.ts b/tests/tuple.test.ts index 88992eb..951e431 100644 --- a/tests/tuple.test.ts +++ b/tests/tuple.test.ts @@ -1,18 +1,18 @@ import {fc, test} from "@fast-check/vitest"; import {beforeEach, expect} from "vitest"; -import {decode, encode, init, Type} from "../src"; +import {decode, encode, init, Kind, Name} from "../src"; import {UINT8} from "./shared"; beforeEach(() => init()); test.prop([fc.tuple(fc.integer(UINT8), fc.string())])("tuple", (value) => { const type = { - type: "tuple", + name: Name.Tuple, value: [ - {type: "int", size: 8}, - {type: "string", kind: "ascii", size: 8}, + {name: Name.Int, size: 1}, + {name: Name.String, kind: Kind.Ascii, size: 1}, ] - } satisfies Type.Tuple; + } as const; const encoded = encode(type, value); const decoded = decode(type, encoded); diff --git a/tsconfig.json b/tsconfig.json index 1f08968..13d1798 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,6 +10,6 @@ "isolatedModules": true, "strict": true }, - "include": ["src", "tests","index.ts"], - "exclude": ["node_modules"] + "include": ["src", "tests", "scripts","index.ts"], + "exclude": ["node_modules", "dist", "coverage", "docs"] }