Array Methods
Sia's array methods serialize and deserialize arrays of arbitrary types. You provide a serializer function (for writing) and a deserializer function (for reading), giving you full control over how each element is encoded. All methods are available as both class methods and standalone functions:
// Class API
import { Sia } from "@timeleap/sia";
// Functional API (tree-shakeable)
import { Buffer, addArray16, readArray16 } from "@timeleap/sia";
Serializer and Deserializer Functions
Array methods are generic and require callback functions to handle individual elements.
Serializer — called once per element when writing:
type Serializer<T> = (sia: Sia, item: T) => void;
Deserializer — called once per element when reading:
type Deserializer<T> = (sia: Sia) => T;
The serializer receives the Sia instance and the current item. It should call add* methods on the Sia instance to write the item's fields. The deserializer receives the Sia instance and should call read* methods to reconstruct the item, returning it.
Array Methods
addArray8(arr, fn) / readArray8(fn)
Writes or reads an array with an 8-bit (1 byte) length prefix. Maximum array length: 255 elements.
addArray8<T>(arr: T[], fn: (sia: Sia, item: T) => void): Sia
readArray8<T>(fn: (sia: Sia) => T): T[]
| Parameter | Type | Description |
|---|---|---|
arr | T[] | Array of items to serialize |
fn (write) | (sia: Sia, item: T) => void | Serializer for each element |
fn (read) | (sia: Sia) => T | Deserializer for each element |
const sia = new Sia();
const numbers = [1, 2, 3, 255];
sia.addArray8(numbers, (s, n) => s.addUInt8(n));
sia.seek(0);
const result = sia.readArray8((s) => s.readUInt8());
console.log(result); // [1, 2, 3, 255]
addArray16(arr, fn) / readArray16(fn)
Writes or reads an array with a 16-bit (2 byte) length prefix. Maximum array length: 65,535 elements.
addArray16<T>(arr: T[], fn: (sia: Sia, item: T) => void): Sia
readArray16<T>(fn: (sia: Sia) => T): T[]
| Parameter | Type | Description |
|---|---|---|
arr | T[] | Array of items to serialize |
fn (write) | (sia: Sia, item: T) => void | Serializer for each element |
fn (read) | (sia: Sia) => T | Deserializer for each element |
const sia = new Sia();
const values = [1000, 2000, 3000, 65535];
sia.addArray16(values, (s, n) => s.addUInt16(n));
sia.seek(0);
const result = sia.readArray16((s) => s.readUInt16());
console.log(result); // [1000, 2000, 3000, 65535]
addArray32(arr, fn) / readArray32(fn)
Writes or reads an array with a 32-bit (4 byte) length prefix. Maximum array length: ~4.29 billion elements.
addArray32<T>(arr: T[], fn: (sia: Sia, item: T) => void): Sia
readArray32<T>(fn: (sia: Sia) => T): T[]
| Parameter | Type | Description |
|---|---|---|
arr | T[] | Array of items to serialize |
fn (write) | (sia: Sia, item: T) => void | Serializer for each element |
fn (read) | (sia: Sia) => T | Deserializer for each element |
const sia = new Sia();
const values = [100000, 200000, 300000, 4294967295];
sia.addArray32(values, (s, n) => s.addUInt32(n));
sia.seek(0);
const result = sia.readArray32((s) => s.readUInt32());
console.log(result); // [100000, 200000, 300000, 4294967295]
addArray64(arr, fn) / readArray64(fn)
Writes or reads an array with a 64-bit (8 byte) length prefix.
addArray64<T>(arr: T[], fn: (sia: Sia, item: T) => void): Sia
readArray64<T>(fn: (sia: Sia) => T): T[]
| Parameter | Type | Description |
|---|---|---|
arr | T[] | Array of items to serialize |
fn (write) | (sia: Sia, item: T) => void | Serializer for each element |
fn (read) | (sia: Sia) => T | Deserializer for each element |
const sia = new Sia();
const values = [9007199254740991, 1234567890123456];
sia.addArray64(values, (s, n) => s.addUInt64(n));
sia.seek(0);
const result = sia.readArray64((s) => s.readUInt64());
console.log(result); // [9007199254740991, 1234567890123456]
TypeScript Generics
All array methods are generic over T. TypeScript infers the type from the array you pass in and the return type of your deserializer:
// T is inferred as `string`
sia.addArray8(["a", "b", "c"], (s, str) => s.addString8(str));
sia.seek(0);
// T is inferred as `string` from the return type of readString8
const strings = sia.readArray8((s) => s.readString8());
// strings: string[]
For complex types, you can explicitly specify the generic parameter:
interface Point {
x: number;
y: number;
}
const points = sia.readArray8<Point>((s) => ({
x: s.readInt32(),
y: s.readInt32(),
}));
Length Prefix Sizes
| Method | Prefix Size | Max Elements |
|---|---|---|
addArray8 | 1 byte | 255 |
addArray16 | 2 bytes | 65,535 |
addArray32 | 4 bytes | ~4.29 billion |
addArray64 | 8 bytes | ~2^53 |
addArray8 or addArray16 is sufficient and saves bytes on the
wire.Complete Example
Serializing and deserializing an array of structured log entries:
import { Sia } from "@timeleap/sia";
interface LogEntry {
timestamp: number;
level: string;
message: string;
errorCode: number;
}
// Define reusable serializer and deserializer
const serializeLog = (sia: Sia, entry: LogEntry): void => {
sia
.addUInt64(entry.timestamp)
.addAscii8(entry.level)
.addString16(entry.message)
.addUInt16(entry.errorCode);
};
const deserializeLog = (sia: Sia): LogEntry => ({
timestamp: sia.readUInt64(),
level: sia.readAscii8(),
message: sia.readString16(),
errorCode: sia.readUInt16(),
});
// Sample data
const logs: LogEntry[] = [
{
timestamp: 1709654400000,
level: "INFO",
message: "Service started successfully",
errorCode: 0,
},
{
timestamp: 1709654401000,
level: "WARN",
message: "High memory usage detected: 89%",
errorCode: 2001,
},
{
timestamp: 1709654402000,
level: "ERROR",
message: "Failed to connect to database",
errorCode: 5003,
},
];
// Serialize
const sia = new Sia();
sia.addArray8(logs, serializeLog);
const bytes = sia.toUint8Array();
console.log(`Serialized ${logs.length} log entries into ${bytes.length} bytes`);
// Deserialize
const reader = new Sia(bytes);
const decoded = reader.readArray8(deserializeLog);
console.log(decoded);
// [
// { timestamp: 1709654400000, level: "INFO", message: "Service started successfully", errorCode: 0 },
// { timestamp: 1709654401000, level: "WARN", message: "High memory usage detected: 89%", errorCode: 2001 },
// { timestamp: 1709654402000, level: "ERROR", message: "Failed to connect to database", errorCode: 5003 },
// ]