- Small (~ 1.1 KB)
- Minimal runtime overhead
- Static type inference
- Single-pass data validation
import { email, rangeLength } from "@the-minimal/validator";
import { encodeObject, encodeAscii8, encodeUint8, encodeTap } from "@the-minimal/protocol";
const encodeUserData = encodeObject([
{
key: "email",
type: encodeTap(
encodeAscii8,
email
)
},
{
key: "age",
type: encodeTap(
encodeUint8,
rangeValue(0, 120)
)
},
]);
const array = new Uint8Array(128);
const view = new DataView(array.buffer);
const state = {
a: array,
v: view,
o: 0
};
encodeUserLogin(state, {
email: "user@example.com",
age: 26
});
return array.subarray(0, state.o);
Every encoder and decoder accepts State
which looks like this:
type State = {
// array
a: Uint8Array;
// view
v: DataView;
// offset
o: number;
};
This library doesn't come with its own memory allocator.
It's up to you and your specific use-case what kind of memory allocator you use.
This library is basically just a tiny opinionated wrapper around State
.
We use either Uint8Array
or DataView
to modify or read buffer and then we bump the offset.
All functions are standalone encoders and decoders which take State
as a parameter.
This makes it very easy to extend the library to your liking and compose our encoders and decoders with your custom ones.
Encoded as Uint8
with values 0
or 1
.
encodeBool(state, true);
decodeBool(state);
encodeUint8(state, 64);
decodeUint8(state);
encodeUint16(state, 1024);
decodeUint16(state);
encodeUint32(state, 128_000);
decodeUint32(state);
encodeInt8(state, 64);
decodeInt8(state);
encodeInt16(state, 1024);
decodeInt16(state);
encodeInt32(state, 128_000);
decodeInt32(state);
encodeFloat32(state, 3.16);
decodeFloat32(state);
encodeFloat64(state, 420_000.69);
decodeFloat64(state);
ASCII string of maximum length of 256 bytes (256 characters).
encodeAscii8(state, "Hello, World!");
decodeAscii8(state);
ASCII string of maximum length of 65536 bytes (65536 characters).
encodeAscii16(state, "Lorem ipsum dolor sit amet, ..");
decodeAscii16(state);
Unicode string of maximum length of 256 bytes (64-128 characters).
encodeUnicode8(state, "Dobré ráno, světe!");
decodeUnicode8(state);
ASCII string of maximum length of 65536 bytes (16384-32768 characters).
encodeUnicode16(state, "Oprávněné aniž i odstoupil o snadno osoby ..");
decodeUnicode16(state);
Array of maximum length of 256.
encodeArray8(encodeUint8)(state, [1, 16, 4, 8, 7]);
decodeArray8(encodeUint8)(state);
Array of maximum length of 65536.
encodeArray16(encodeUint8)(state, [1, 16, 4, 8, 7, ..]);
decodeArray16(encodeUint8)(state);
All keys have to be defined, otherwise the buffer will be misaligned.
encodeObject([
{ key: "email", type: encodeAscii8 },
{ key: "password", type: encodeAscii8 },
])(state, {
email: "yamiteru@icloud.com",
password: "Test123456"
});
decodeObject([
{ key: "email", type: decodeAscii8 },
{ key: "password", type: decodeAscii8 },
])(state);
The maximum length of tuple is 256.
encodeTuple([
encodeUint8,
encodeUint8,
encodeAscii
])(state, [185, 90, "yamiteru"]);
decodeTuple([
decodeUint8,
decodeUint8,
decodeAscii
])(state);
Maximum length of enum options is 256. Options are represented as uint8 indexes.
encodeEnum(["ADMIN", "USER"])(state, "USER");
decodeEnum(["ADMIN", "USER"])(state);
Value in buffer is prefixed with uint8 0
if value is not null or 1
if value is null.
encodeNullable(encodeUint8)(state, 2);
decodeNullable(decodeUint8)(state);
This function is not encoded into buffer.
It's used for intercepting values.
Most notable use-case would be data validation while encoding or decoding.
The tap is executed before encoding and after decoding.
encodeTap(encodeUint8, () => { /* .. */ })(state, 2);
decodeTap(decodeUint8, () => { /* .. */ })(state);