nupp.serde

nupp.serde separates logical data from its physical representation.

Schema is an immutable logical graph. Binding<T> joins that graph to a Nupp record, fixed-layout struct, or indexed dynamic value. JSON is the first prepared codec; the same schema remains available to XML, CBOR, and custom codecs.

@derive(nupp.derive.Serde)
local record User
    id: uint32
    name: string?
end

local binding = nupp.serde.of(User)
local prepared = nupp.serde.json():prepare(binding)
local text = prepared:encode(new User(id = 41))
local restored = assert(prepared:decode(text))
assert(restored.id == 41)

Run-time clients build the same immutable graph and use dense dynamic slots:

const serde = nupp.serde
local builder = new serde.SchemaBuilder()
builder:structure("example.User")
builder:required("id", nupp.serde.uint32)
builder:optional("name", nupp.serde.string)
local binding = nupp.serde.dynamic(builder:freeze())
local value = binding:bind{id = 41, name = "Ada"}

Module contents

Types

TypeKindDescription
BindinginterfaceA checked physical representation of a schema as T.
DynamicBindinginterfaceA binding that constructs dense run-time values.
DynamicValuerecordAn indexed value owned by a dynamic binding.
JsonCodecrecordA JSON codec that lazily prepares bindings.
JsonProfilerecordImmutable JSON wire-policy identity.
Kindtype
MemberrecordOne structure member with a stable dense index.
MetadataKeyinterfaceA typed identity for format-neutral schema metadata.
PreparedinterfaceA prepared JSON traversal for one binding and profile.
PreparedDebuginterfaceA prepared schema-driven Debug formatter.
SchemarecordOne immutable logical schema node.
SchemaBuilderrecordIncrementally constructs and then freezes a run-time structure schema.
SerializableinterfaceMarker claimed by @derive(nupp.derive.Serde).

Functions

FunctionKindDescription
bindingOffunctionRetrieves the binding registered by @derive(nupp.derive.Serde).
dynamicfunctionCreates the indexed dynamic binding for a frozen schema.
jsonfunctionCreates an immutable-profile JSON codec.
keyfunctionDeclares a named key whose value type is fixed by the binding that persists it.
listfunctionCreates an immutable list node.
loadStorefunctionDecodes plain values written by saveStore back into a store.
mapfunctionCreates an immutable map node.
metadataKeyfunctionCreates a typed schema metadata identity.
offunction
optionalfunctionCreates an immutable optional node.
prepareDebugfunctionPrepares and memoizes Debug formatting for a binding.
saveStorefunctionEncodes every occupied key of a store into plain values under its name.

Values

ValueKindDescription
booleanvariable
debugRedactvariable
debugSkipvariableStandard Debug policy metadata shared by derived and dynamic schemas.
documentvariable
int16variable
int32variable
int8variable
integervariable
nullvariable
numbervariable
stringvariable
uint16variable
uint32variable
uint8variable
unitvariableFormat-neutral scalar schema singletons.

Types#

Bindinginterface#

sealed interface Binding<T>
    schema: function(self): Schema
    extension: function(self, key: any): any
end

A checked physical representation of a schema as T.

Type parameters

NameDescription
T

Methods

schema#
schema: function(self): Schema
Arguments
NameTypeDescription
?self
Returns
TypeDescription
Schema
extension#
extension: function(self, key: any): any
Arguments
NameTypeDescription
?self
keyany
Returns
TypeDescription
any

DynamicBindinginterface#

sealed interface DynamicBinding is Binding<DynamicValue>
    bind: function(self, value: {[string]: any}): DynamicValue
    newValue: function(self): DynamicValue
end

A binding that constructs dense run-time values.

Methods

bind#
bind: function(self, value: {[string]: any}): DynamicValue
Arguments
NameTypeDescription
?self
value{[string]: any}
Returns
TypeDescription
DynamicValue
newValue#
newValue: function(self): DynamicValue
Arguments
NameTypeDescription
?self
Returns
TypeDescription
DynamicValue

DynamicValuerecord#

record DynamicValue
    function get(self, member: Member): any end

    function get(self, name: string): any end

    function set(self, member: Member, value: any): nil end
end

An indexed value owned by a dynamic binding.

Methods

get#
get: function get(self, member: Member): any

Reads a resolved member.

Arguments
NameTypeDescription
selfany
memberMember
Returns
TypeDescription
any
Raises
  • when the member belongs to another schema

get#
get: function get(self, name: string): any

Reads a member by logical name.

Arguments
NameTypeDescription
selfany
namestring
Returns
TypeDescription
any
set#
set: function set(self, member: Member, value: any): nil

Sets a resolved member after checking its schema identity.

Arguments
NameTypeDescription
selfany
memberMember
valueany
Returns
TypeDescription
nil
Raises
  • when the member belongs to another schema

JsonCodecrecord#

record JsonCodec
    readonly profile: JsonProfile
    function prepare<T>(self, binding: Binding<T>): Prepared<T> end

    function encode<T>(self, binding: Binding<T>, value: T): string end

    function write<T>(self, binding: Binding<T>, value: T, exclusive out: Buffer): nil end

    function write<T>(self, binding: Binding<T>, value: T, exclusive out: Writer): nil end

    function decode<T>(self, binding: Binding<T>, text: string): (T?, string?) end

    function decodeBuffer<T>(self, binding: Binding<T>, exclusive input: Buffer): (T?, string?) end
end

A JSON codec that lazily prepares bindings.

Methods

prepare#
prepare: function prepare<T>(self, binding: Binding<T>): Prepared<T>

Prepares and memoizes a fused traversal.

Arguments
NameTypeDescription
selfany
bindingBinding<T>
Returns
TypeDescription
Prepared<T>
encode#
encode: function encode<T>(self, binding: Binding<T>, value: T): string
Arguments
NameTypeDescription
selfany
bindingBinding<T>
valueT
Returns
TypeDescription
string
write#
write: function write<T>(self, binding: Binding<T>, value: T, exclusive out: Buffer): nil

Appends one complete encoded root to caller-owned storage in one chunk.

Arguments
NameTypeDescription
selfany
bindingBinding<T>
valueT
exclusive outBuffer
Returns
TypeDescription
nil
write#
write: function write<T>(self, binding: Binding<T>, value: T, exclusive out: Writer): nil

Streams one prepared value at the writer's current value position.

Arguments
NameTypeDescription
selfany
bindingBinding<T>
valueT
exclusive outWriter
Returns
TypeDescription
nil
decode#
decode: function decode<T>(self, binding: Binding<T>, text: string): T?, string?
Arguments
NameTypeDescription
selfany
bindingBinding<T>
textstring
Returns
TypeDescription
T?
string?
decodeBuffer#
decodeBuffer: function decodeBuffer<T>(self, binding: Binding<T>, exclusive input: Buffer): T?, string?

Decodes from caller-owned storage without materializing a final string.

Arguments
NameTypeDescription
selfany
bindingBinding<T>
exclusive inputBuffer
Returns
TypeDescription
T?
string?

Fields

JsonProfilerecord#

record JsonProfile
    readonly unknownMembers: "reject" | "ignore"
end

Immutable JSON wire-policy identity.

Fields

unknownMembers#
unknownMembers: "reject" | "ignore"

Kindtype#

type Kind = "unit"
| "null"
| "boolean"
| "integer"
| "unsigned"
| "number"
| "decimal"
| "string"
| "bytes"
| "timestamp"
| "optional"
| "list"
| "map"
| "structure"
| "tuple"
| "union"
| "stringEnum"
| "integerEnum"
| "document"

Memberrecord#

record Member
    readonly index: integer
    readonly name: string
    readonly target: any
    readonly required: boolean
    readonly hasDefault: boolean
    function metadata<T>(self, key: MetadataKey<T>): T? end
end

One structure member with a stable dense index.

Methods

metadata#
metadata: function metadata<T>(self, key: MetadataKey<T>): T?

Answers typed metadata attached to this member.

Arguments
NameTypeDescription
selfany
keyMetadataKey<T>
Returns
TypeDescription
T?

Fields

index#
index: integer
name#
target#
target: any
required#
required: boolean
hasDefault#
hasDefault: boolean

MetadataKeyinterface#

interface MetadataKey<T>
    readonly id: integer
    readonly name: string?
end

A typed identity for format-neutral schema metadata.

It is a nupp.store.Key: its id is process-local, so applications retain the key, never its number, and may use the same key with static and run-time schemas.

Type parameters

NameDescription
T

Fields

name#

Preparedinterface#

sealed interface Prepared<T>
    encode: function(self, value: T): string
    write: function(self, value: T, exclusive out: Buffer): nil & function(self, value: T, exclusive out: Writer): nil

    decode: function(self, text: string): (T?, string?)
    decodeBuffer: function(self, exclusive input: Buffer): (T?, string?)
end

A prepared JSON traversal for one binding and profile.

The recursive prepared traversal handles structures, lists, string-keyed maps, optionals, scalar constraints, defaults, literals, and document members.

Type parameters

NameDescription
T

Methods

encode#
encode: function(self, value: T): string
Arguments
NameTypeDescription
?self
valueT
Returns
TypeDescription
string
write#
write: function(self, value: T, exclusive out: Buffer): nil & function(self, value: T, exclusive out: Writer): nil

Appends one encoded root through reserved caller-owned storage.

The prepared traversal writes one complete encoded value.

Arguments
NameTypeDescription
?self
valueT
exclusive outBuffer
Returns
TypeDescription
nil
decode#
decode: function(self, text: string): (T?, string?)
Arguments
NameTypeDescription
?self
textstring
Returns
TypeDescription
T?
string?
decodeBuffer#
decodeBuffer: function(self, exclusive input: Buffer): (T?, string?)

Decodes a value held in caller-owned storage.

Arguments
NameTypeDescription
?self
exclusive inputBuffer
Returns
TypeDescription
T?
string?

PreparedDebuginterface#

sealed interface PreparedDebug<T>
    format: function(self, value: T): string
    write: function(self, value: T, exclusive out: Buffer): nil
end

A prepared schema-driven Debug formatter.

Type parameters

NameDescription
T

Methods

format#
format: function(self, value: T): string
Arguments
NameTypeDescription
?self
valueT
Returns
TypeDescription
string
write#
write: function(self, value: T, exclusive out: Buffer): nil
Arguments
NameTypeDescription
?self
valueT
exclusive outBuffer
Returns
TypeDescription
nil

Schemarecord#

record Schema
    readonly kind: Kind
    readonly name: string?
    readonly members: {Member}
    function extension<T>(self, key: nupp.reflect.ExtensionKey<T>): T end

    function metadata<T>(self, key: MetadataKey<T>): T? end

    function member(self, name: string): Member? end

    function element(self): Schema? end

    function key(self): Schema? end

    function value(self): Schema? end

    function expectMember(self, name: string): Member end
end

One immutable logical schema node.

Methods

extension#
extension: function extension<T>(self, key: nupp.reflect.ExtensionKey<T>): T

Answers a lazily computed typed extension.

Arguments
NameTypeDescription
selfany
keynupp.reflect.ExtensionKey<T>
Returns
TypeDescription
T
metadata#
metadata: function metadata<T>(self, key: MetadataKey<T>): T?

Answers typed metadata attached to this schema node.

Arguments
NameTypeDescription
selfany
keyMetadataKey<T>
Returns
TypeDescription
T?
member#
member: function member(self, name: string): Member?

Finds a structure member by its logical name.

Arguments
NameTypeDescription
selfany
namestring
Returns
TypeDescription
Member?
element#
element: function element(self): Schema?

Answers the element schema of an optional or list node.

Arguments
NameTypeDescription
selfany
Returns
TypeDescription
Schema?
key#
key: function key(self): Schema?

Answers the key schema of a map node.

Arguments
NameTypeDescription
selfany
Returns
TypeDescription
Schema?
value#
value: function value(self): Schema?

Answers the value schema of a map node.

Arguments
NameTypeDescription
selfany
Returns
TypeDescription
Schema?
expectMember#
expectMember: function expectMember(self, name: string): Member

Finds a member or raises when it is absent.

Arguments
NameTypeDescription
selfany
namestring
Returns
TypeDescription
Member
Raises
  • when the structure has no member with this name

Fields

kind#
kind: Kind
name#
members#
members: {Member}

SchemaBuilderrecord#

record SchemaBuilder

    constructor(self) end

    function structure(self, name: string): SchemaBuilder end

    function required(self, name: string, target: Schema): SchemaBuilder end

    function optional(self, name: string, target: Schema): SchemaBuilder end

    function defaulted(self, name: string, target: Schema, value: any): SchemaBuilder end

    function metadata<T>(self, key: MetadataKey<T>, value: T): SchemaBuilder end

    function memberMetadata<T>(self, name: string, key: MetadataKey<T>, value: T): SchemaBuilder end

    function freeze(self): Schema end
end

Incrementally constructs and then freezes a run-time structure schema.

Methods

constructor#
constructor: function constructor(self)
Arguments
NameTypeDescription
selfany
structure#
structure: function structure(self, name: string): SchemaBuilder

Starts a named structure.

Arguments
NameTypeDescription
selfany
namestring
Returns
TypeDescription
SchemaBuilder
Raises
  • when a root was already selected

required#
required: function required(self, name: string, target: Schema): SchemaBuilder

Adds a required member.

Arguments
NameTypeDescription
selfany
namestring
targetSchema
Returns
TypeDescription
SchemaBuilder
optional#
optional: function optional(self, name: string, target: Schema): SchemaBuilder

Adds an optional member.

Arguments
NameTypeDescription
selfany
namestring
targetSchema
Returns
TypeDescription
SchemaBuilder
defaulted#
defaulted: function defaulted(self, name: string, target: Schema, value: any): SchemaBuilder

Adds a member with a default.

Arguments
NameTypeDescription
selfany
namestring
targetSchema
valueany
Returns
TypeDescription
SchemaBuilder
metadata#
metadata: function metadata<T>(self, key: MetadataKey<T>, value: T): SchemaBuilder

Attaches typed metadata to the root schema.

Arguments
NameTypeDescription
selfany
keyMetadataKey<T>
valueT
Returns
TypeDescription
SchemaBuilder
memberMetadata#
memberMetadata: function memberMetadata<T>(self, name: string, key: MetadataKey<T>, value: T): SchemaBuilder

Attaches typed metadata to a named structure member.

Arguments
NameTypeDescription
selfany
namestring
keyMetadataKey<T>
valueT
Returns
TypeDescription
SchemaBuilder
Raises
  • when the member is absent

freeze#
freeze: function freeze(self): Schema

Freezes and answers the immutable schema.

Arguments
NameTypeDescription
selfany
Returns
TypeDescription
Schema
Raises
  • when the builder has no root

Serializableinterface#

interface Serializable
end

Marker claimed by @derive(nupp.derive.Serde).

Serialization remains a property of a Binding<T>, not an instance method. The empty contract lets derive advertise checked participation without making values carry a codec API.

Functions#

bindingOffunction#

local function bindingOf(type: any): any

Retrieves the binding registered by @derive(nupp.derive.Serde).

Arguments

NameTypeDescription
typeany

Returns

TypeDescription
any

Raises

  • when the type did not derive Serde

dynamicfunction#

function dynamic(schema: Schema): DynamicBinding

Creates the indexed dynamic binding for a frozen schema.

Arguments

NameTypeDescription
schemaSchema

Returns

TypeDescription
DynamicBinding

Raises

  • when the schema is not a structure

jsonfunction#

function json(options: any?): JsonCodec

Creates an immutable-profile JSON codec.

fieldNames, when supplied, runs only during preparation. The fused traversal sees the resulting immutable wire names.

Arguments

NameTypeDescription
optionsany?

Returns

TypeDescription
JsonCodec

Raises

  • when unknownMembers is not reject or ignore

keyfunction#

function key<T>(name: string, binding: Binding<T>): store.Key<T>

Declares a named key whose value type is fixed by the binding that persists it.

The key is registered as nupp.store.newKey registers one, so the name is opaque and unique, and the binding is retained so saveStore and loadStore can carry the value under that name.

Type parameters

NameDescription
T

Arguments

NameTypeDescription
namestring

the opaque name to register

bindingBinding<T>

the binding that encodes and decodes the value

Returns

TypeDescription
store.Key<T>

the key

Raises

  • when the name is empty or already registered

listfunction#

function list(target: Schema): Schema

Creates an immutable list node.

Arguments

NameTypeDescription
targetSchema

Returns

TypeDescription
Schema

loadStorefunction#

function loadStore(exclusive value: store.Store, saved: {[string]: any}): nil

Decodes plain values written by saveStore back into a store.

Each name is looked up in this runtime state's registry and its value is decoded through the binding that key was declared with, so a value is checked against the schema this program gave the name. Keys the saved table does not mention are left as they are.

Arguments

NameTypeDescription
exclusive valuestore.Store

the store to write

saved{[string]: any}

the table saveStore returned, or one decoded from a document

Returns

TypeDescription
nil

nothing

Raises

  • when a name is not registered, its key has no binding, or a value does not fit

mapfunction#

function map(key: Schema, value: Schema): Schema

Creates an immutable map node.

Arguments

NameTypeDescription
keySchema
valueSchema

Returns

TypeDescription
Schema

Raises

  • when the key schema is not string-valued: document keys are strings, and the codec can neither emit nor read back any other kind

metadataKeyfunction#

function metadataKey<T>(): MetadataKey<T>

Creates a typed schema metadata identity.

Type parameters

NameDescription
T

Returns

TypeDescription
MetadataKey<T>

the key

offunction#

function of<T>(type: Type<T>): Binding<T>

Type parameters

NameDescription
T

Arguments

NameTypeDescription
typeType<T>

Returns

TypeDescription
Binding<T>

optionalfunction#

function optional(target: Schema): Schema

Creates an immutable optional node.

Arguments

NameTypeDescription
targetSchema

Returns

TypeDescription
Schema

prepareDebugfunction#

function prepareDebug<T>(binding: Binding<T>): PreparedDebug<T>

Prepares and memoizes Debug formatting for a binding.

Type parameters

NameDescription
T

Arguments

NameTypeDescription
bindingBinding<T>

Returns

TypeDescription
PreparedDebug<T>

saveStorefunction#

function saveStore(borrows value: store.Store): {[string]: any}

Encodes every occupied key of a store into plain values under its name.

The values are the documents a JSON codec with default field names writes, so a saved store rides inside whatever document the application encodes.

Arguments

NameTypeDescription
borrows valuestore.Store

the store to save

Returns

TypeDescription
{[string]: any}

a fresh table from name to plain value

Raises

  • when an occupied key is anonymous or was declared without a binding

Values#

booleanvariable#

const boolean

debugRedactvariable#

debugSkipvariable#

Standard Debug policy metadata shared by derived and dynamic schemas.

documentvariable#

const document

int16variable#

const int16

int32variable#

const int32

int8variable#

const int8

integervariable#

const integer

nullvariable#

const null

numbervariable#

const number

stringvariable#

const string

uint16variable#

const uint16

uint32variable#

const uint32

uint8variable#

const uint8

unitvariable#

const unit

Format-neutral scalar schema singletons.