FateSchema

sealed interface FateSchema<T>

Describes how one type becomes bytes.

A schema is generic over the type it encodes, so the compiler rejects a value that doesn't belong on a channel. Every schema can also write a description of itself. The writer puts that description in the log ahead of the data, so a reader can decode a file without the classes that wrote it.

The schemas

Primitives

  • IntSchema: 32-bit signed integers

  • LongSchema: 64-bit signed integers

  • DoubleSchema: 64-bit floating point numbers

  • StringSchema: UTF-8 encoded strings with length prefix

  • BooleanSchema: Single-byte boolean values

There is no float type. Float widens to DoubleSchema, which is exact. Narrower primitives (Short, Byte, Char) have no encoding and are rejected when the schema is built.

Collections

  • ArraySchema<T>: arrays, and the wire format List/Set use too

  • DoubleArraySchema and friends: Kotlin's primitive arrays, same bytes without boxing

  • MapSchema<K, V>: maps with independently typed keys and values

  • EnumSchema<T>: enums, as a 4-byte ordinal

Optionals

  • OptionalSchema<T>: a nullable T?, as a presence byte then the value

  • JavaOptionalSchema<T>: java.util.Optional<T>, same tag and same bytes

  • OptionalIntSchema and friends: OptionalInt, OptionalLong, OptionalDouble

Classes

  • ReflectedClassSchema<T>: built by reflecting over public properties

  • TypedClassSchema<T>: the same, plus the class's AS_TYPE name in the log

  • CustomStructSchema<T>: components and an encoder you write yourself

Binary format

The schema, written once per channel:

[4 bytes: tag] [schema-specific metadata...]

An object, written once per logged value:

[variable: object data as defined by schema]

Example

// Automatic schema inference
val userSchema = FateSchema.schemaOfClass(User::class.java)

// Manual schema creation
val customSchema = CustomStructSchema<Person>(
type = "Person",
componentNames = listOf("name", "age"),
componentSchemas = listOf(StringSchema, IntSchema),
encoder = { person -> listOf(person.name, person.age) }
)

// Size calculation and encoding
val person = Person("Alice", 30)
val objSize = customSchema.objSize(person)
val buffer = ByteBuffer.allocate(objSize)
customSchema.encodeObject(buffer, person)

Parameters

T

The type of objects this schema can serialize and deserialize

Inheritors

Types

Link copied to clipboard
object Companion
Link copied to clipboard

The schema types FateWeaver knows, each with the integer tag it writes into the log.

Properties

Link copied to clipboard
open val schema: ByteArray

The schema definition as bytes, which the writer puts in the log.

Link copied to clipboard
abstract val schemaSize: Int

Number of bytes in this schema's definition.

Link copied to clipboard
abstract val tag: Int

The integer that identifies this schema's type in the log.

Functions

Link copied to clipboard
abstract fun encodeObject(buffer: ByteBuffer, obj: T)

Writes the given object into the buffer.

Link copied to clipboard
open fun encodeSchema(buffer: ByteBuffer)

Writes the whole schema definition, starting with the tag, into the buffer.

Link copied to clipboard
abstract fun objSize(obj: T): Int

Returns the number of bytes encodeObject writes for the given object.