nupp.serde

A binding selects how a value is read and constructed, separately from the codec that chooses its wire representation. See Serialization bindings for the guide to bindings, codecs, and documents.

local serde = require("nupp.serde")
local json = require("nupp.serde.json")
local record User
    id: integer
    name: string
end
local users = serde.binding(User)
local bytes = json.encode(users, new User(id = 7, name = "Ada"))
assert(bytes == '{"id":7,"name":"Ada"}')
assert(json.decode(users, bytes).name == "Ada")

A Binding is chosen at the call site and passed to a codec, so one record can have several: the binding a save file uses can differ from the one a web service uses. binding builds one from a record or struct declaration with no derive, and Options renames, filters, or reinterprets its fields.

The package splits by audience:

This module holds the contracts all of them share. A model library implements Adapter over its own Member type and wraps it in Bound; a codec implements Writer and Reader. Neither imports the other, and the erased Binding is the only thing a caller passes between them.

Failures are raised as an Error carrying the logical path to the value, the byte offset when a decoder has one, and the original cause.

Submodules

ModuleDescription
nupp.serde.adaptersThese builders give a model library that owns its schema adapters over its own nupp.serde.Member type.
nupp.serde.codecA new codec uses these helpers to apply the number, timestamp, error-path, and context rules the built-in codecs share.
nupp.serde.debugDebug rendering turns any bound value into readable text for logs, assertions, and error messages.
nupp.serde.documentA document is a value without a schema, which any codec reads and writes.
nupp.serde.jsonThis codec writes and reads JSON text through any nupp.serde.Binding.
nupp.serde.nativeThe native codec saves values as a compact binary frame on a native LuaJIT host.

Module contents

Types

TypeKindDescription
AccessrecordA declaration's fields and constructor, as an external model sees them.
AdapterinterfaceReads and writes one type of value against a model's members.
AtominterfaceA model-defined scalar a codec passes through without interpreting, such as an enum member or an XML qualified name.
BindinginterfaceSelects how a value of type T is written and constructed.
BoundrecordErases an Adapter's member type into a Binding for a Copyable value.
ChildinterfaceOne member of a described structure, union, list, or map.
ConsumerinterfaceApplies an adapter to state, recovering the member type a Binding erased.
ContextinterfaceTyped values a codec attaches to what it reads, such as the schema a document came from.
DecimalrecordAn exact decimal: coefficient times ten to the exponent.
DescriptioninterfaceThe shape of an adapter's value for one direction, which a codec plans against before it reads or writes anything.
DirectiontypeWhether a description is for writing or for reading.
DiscardinterfaceDisposes a value a codec has to give up.
DocumentAdapterinterfaceReads and writes a document type as its logical contents.
DocumentElementinterfaceReceives one document list element.
DocumentEntryinterfaceReceives one document map entry.
DocumentMemberinterfaceReceives one document structure member.
DocumentReaderinterfaceReads one document value without a schema.
ElementConsumerinterfaceReceives one list or tuple element while reading.
EntryConsumerinterfaceReceives one map entry while reading.
ErrorrecordA serialization failure.
ErrorCodetypeWhat kind of failure an Error is: malformed input, an exceeded limit, a value the codec cannot represent, a model's...
FieldOptionsrecordMapping for one field of a declaration binding.
FieldViewinterfaceChooses an adapter in place of the one a declared type implies.
FloatrecordA floating-point value with the width it was written at.
IntegerrecordAn integer of a declared width, carried as its decimal text so 64-bit values survive targets without an exact carrier.
IntoConsumerinterfaceA Consumer that also writes into an exclusive output.
KindtypeThe broad shape of a value: a scalar kind, or a structure, union, list, tuple, map, or opaque value.
MemberinterfaceA field, list element, or other position in a model's schema.
MemberConsumerinterfaceReceives one structure or union member while reading.
MembersinterfaceEmits a structure's members, a list's elements, or a map's entries.
OptionsrecordField mapping for binding.
OwnedBoundrecordErases an Adapter for a value that owns resources.
PresencetypeWhether a member was absent, explicitly null, or present.
ReaderinterfaceWhat a codec reads a value from.
ScalarKindtypeThe scalar kinds a Writer and Reader carry.
TimestamprecordAn instant as whole seconds since the Unix epoch, in decimal text, and nanoseconds within that second.
UnknownConsumerinterfaceReceives a wire field the model does not declare.
UnknownReaderinterfaceSkips or captures an undeclared wire field's value.
WireFieldinterfaceA wire field a decoder met that the model does not declare.
WriterinterfaceWhat a codec emits a value into.

Functions

FunctionKindDescription
accessfunctionReturns the Access for a declaration, cached on the declaration.
bindingfunctionBuilds a binding from a record or struct declaration.

Values

ValueKindDescription
iso8601SecondsvariableThe representation that writes an integer field of epoch seconds as an RFC 3339 timestamp, and reads one back.

Types#

Accessrecord#

record Access<T is nupp.Copyable> ...

A declaration's fields and constructor, as an external model sees them.

access returns one for a model library that maps a Nupp record onto its own schema, so it reads fields and constructs values exactly as binding does without depending on that binding.

Type parameters

NameDescription
T

Members

NameKindDescription
infofieldThe reflection graph the declaration was read from.
typeIndexfieldThe position of the declaration in info.types.
fieldsfieldThe declaration's stored, readable fields, in declaration order.
parametersfieldThe constructor's parameters, in call order.
ownerfield
targetfield
defaultsfield
constructorconstructor
constructionProblemfield
accessiblefield
nestedCachefield
getmethodReads a field of a value, borrowed from it.
beginmethodStarts constructing a value.
constructionErrormethodReturns why the declaration cannot be constructed through this access.
nestedmethodReturns the access for a record or struct the declaration's storage reaches.
finishmethodConstructs the value from a builder and drops the builder.

infofield#

@readonly

The reflection graph the declaration was read from.

typeIndexfield#

typeIndex: integer
@readonly

The position of the declaration in info.types.

fieldsfield#

fields: const{Field}
@readonly

The declaration's stored, readable fields, in declaration order.

parametersfield#

parameters: const{Parameter}
@readonly

The constructor's parameters, in call order.

The list is empty when the declaration owns resources, is generic, or needs a factory; constructionError then says why.

ownerfield#

owner: table
@private@readonly

targetfield#

target: Type<T>
@private@readonly

defaultsfield#

defaults: {[string]: unknown}
@private@readonly

constructorconstructor#

constructor: integer?
@private@readonly

constructionProblemfield#

constructionProblem: string?
@private@readonly

accessiblefield#

accessible: {[integer]: boolean}
@private@readonly

nestedCachefield#

nestedCache: {[integer]: Access<unknown>}
@private@readonly

getmethod#

get: function get(self, borrows value: T, field: const Field): unknown

Reads a field of a value, borrowed from it.

Arguments
NameTypeDescription
selfany
borrows valueT

the value to read

fieldconst Field

one of this access's fields

Returns
TypeDescription
unknown

the field's value

Raises
TypeCondition
string

when the field belongs to another access

beginmethod#

begin: function begin(self): Builder<T>

Starts constructing a value.

The builder is an owner: pass it to finish, or drop it to discard the arguments.

Arguments
NameTypeDescription
selfany
Returns
TypeDescription
Builder<T>

the builder

Raises
TypeCondition
string

when the declaration cannot be constructed; the message is the one constructionError returns

constructionErrormethod#

constructionError: function constructionError(self): string?

Returns why the declaration cannot be constructed through this access.

The reported problems are an owning or generic declaration, a constructor that needs a factory, a parameter that is not plain or whose type cannot be checked at runtime, and metadata built by a compiler that predates ownership attestation. Each needs a construction adapter of its own, except the last, which needs a rebuild.

Arguments
NameTypeDescription
selfany
Returns
TypeDescription
string?

the problem, or nil when begin succeeds

nestedmethod#

nested: function nested(self, index: integer): Access<unknown>

Returns the access for a record or struct the declaration's storage reaches.

The access is cached, so asking twice for an index returns the same one.

Arguments
NameTypeDescription
selfany
indexinteger

the nested declaration's position in info.types

Returns
TypeDescription
Access<unknown>

the nested declaration's access

Raises
TypeCondition
string

when the type is not reachable through readable storage, is not a record or struct, or has no runtime declaration

finishmethod#

finish: function finish(self, takes builder: Builder<T>): T

Constructs the value from a builder and drops the builder.

An unset optional parameter takes a copy of the field's default, if any, when the declaration has no constructor of its own, and nil when it does. The constructed value is checked against the declaration before it is returned.

Arguments
NameTypeDescription
selfany
takes builderBuilder<T>

the builder from begin, transferred

Returns
TypeDescription
T

the value

Raises
TypeCondition
string

when the builder is closed or belongs to another access, a required parameter is unset, or an argument or the result does not fit its declared type

Adapterinterface#

interface Adapter<T, M is Member> ...

Reads and writes one type of value against a model's members.

describe returns the shape a codec plans against, write emits a value through a Writer, and read constructs one from a Reader. The builders in nupp.serde.adapters cover scalars, structures, and lists.

Type parameters

NameDescription
T
M

Members

NameKindDescription
describemethodDescribes the value's shape for a direction.
writemethodWrites value to writer as exactly one value.
readmethodConstructs a value by consuming exactly one value from reader.

describemethod#

describe: function(self, direction: Direction): Description<M>

Describes the value's shape for a direction.

Arguments
NameTypeDescription
?self
directionDirection
Returns
TypeDescription
Description<M>

writemethod#

write: function(self, borrows value: T, exclusive writer: Writer<M>): nil

Writes value to writer as exactly one value.

Arguments
NameTypeDescription
?self
borrows valueT
exclusive writerWriter<M>
Returns
TypeDescription
nil

readmethod#

read: function(self, exclusive reader: Reader<M>): T

Constructs a value by consuming exactly one value from reader.

Arguments
NameTypeDescription
?self
exclusive readerReader<M>
Returns
TypeDescription
T

Atominterface#

interface Atom ...

A model-defined scalar a codec passes through without interpreting, such as an enum member or an XML qualified name.

Members

NameKindDescription
familyfieldA table identifying the model that defined the atom, which a codec compares to recognize atoms it can render.
snapshotmethodCopies the atom into a value a document can keep after the original is gone.

familyfield#

family: table
@readonly

A table identifying the model that defined the atom, which a codec compares to recognize atoms it can render.

snapshotmethod#

snapshot: function(borrows self: Atom): Atom

Copies the atom into a value a document can keep after the original is gone.

Arguments
NameTypeDescription
borrows selfAtom
Returns
TypeDescription
Atom

Bindinginterface#

interface Binding<T> is Discard<T> ...

Selects how a value of type T is written and constructed.

A binding is opaque: it hides the model's Member type and is invariant in T, so a binding for one record cannot be passed where another is expected. Make one with binding, or with Bound or OwnedBound over an Adapter.

Type parameters

NameDescription
T

Members

NameKindDescription
acceptmethodPasses the erased adapter and state to consumer, recovering the member type.
acceptIntomethodPasses the erased adapter, state, and output to consumer, recovering the member type.

acceptmethod#

accept: function<S, R>(self, consumer: Consumer<T, S, R>, borrows state: S): R

Passes the erased adapter and state to consumer, recovering the member type.

Arguments
NameTypeDescription
?self
consumerConsumer<T, S, R>
borrows stateS
Returns
TypeDescription
R

acceptIntomethod#

acceptInto: function<S, O, R>(self, consumer: IntoConsumer<T, S, O, R>, borrows state: S, exclusive output: O): R

Passes the erased adapter, state, and output to consumer, recovering the member type.

Arguments
NameTypeDescription
?self
consumerIntoConsumer<T, S, O, R>
borrows stateS
exclusive outputO
Returns
TypeDescription
R

Boundrecord#

record Bound<T is nupp.Copyable, M is Member> is Binding<T> ...

Erases an Adapter's member type into a Binding for a Copyable value.

A codec still has to be told how the model's members are named: see nupp.serde.json.memberNamePolicy.

local serde = require("nupp.serde")
local adapters = require("nupp.serde.adapters")
local json = require("nupp.serde.json")
local record Member is serde.Member
    @readonly name: string
    @readonly index: integer?
end
local title: serde.Binding<string> = new serde.Bound<string, Member>(
    adapter = adapters.text(new Member(name = "title"))
)
assert(json.codec(json.memberNamePolicy):encode(title, "Dune") == '"Dune"')

Type parameters

NameDescription
T
M

Members

NameKindDescription
adapterfieldThe adapter the binding erases.
discardmethodDiscards a value.
acceptmethodPasses adapter and state to consumer.
acceptIntomethodPasses adapter, state, and output to consumer.

adapterfield#

@readonly

The adapter the binding erases.

discardmethod#

discard: function discard(self, takes value: T): nil

Discards a value. A Copyable value carries no cleanup obligation, so only its transfer ends here.

Arguments
NameTypeDescription
selfany
takes valueT
Returns
TypeDescription
nil

acceptmethod#

accept: function accept<S, R>(self, consumer: Consumer<T, S, R>, borrows state: S): R

Passes adapter and state to consumer.

Arguments
NameTypeDescription
selfany
consumerConsumer<T, S, R>
borrows stateS
Returns
TypeDescription
R

acceptIntomethod#

acceptInto: function acceptInto<S, O, R>(self, consumer: IntoConsumer<T, S, O, R>, borrows state: S, exclusive output: O): R

Passes adapter, state, and output to consumer.

Arguments
NameTypeDescription
selfany
consumerIntoConsumer<T, S, O, R>
borrows stateS
exclusive outputO
Returns
TypeDescription
R

Childinterface#

interface Child<M is Member> ...

One member of a described structure, union, list, or map.

Type parameters

NameDescription
M

Members

NameKindDescription
memberfieldThe member the child's value sits at.
requiredfieldWhether reading needs the member present.
hasDefaultfieldWhether construction supplies a value when the member is absent.
describemethodDescribes the child's value for a direction.

memberfield#

@readonly

The member the child's value sits at.

requiredfield#

required: boolean
@readonly

Whether reading needs the member present.

hasDefaultfield#

hasDefault: boolean
@readonly

Whether construction supplies a value when the member is absent.

describemethod#

describe: function(self, direction: Direction): Description<M>

Describes the child's value for a direction.

Arguments
NameTypeDescription
?self
directionDirection
Returns
TypeDescription
Description<M>

Consumerinterface#

interface Consumer<T, S, R> ...

Applies an adapter to state, recovering the member type a Binding erased. A codec passes one to Binding:accept.

Type parameters

NameDescription
T
S
R

Members

NameKindDescription
applymethodApplies the adapter a binding erased to borrowed state.

applymethod#

apply: function<M is Member>(self, adapter: Adapter<T, M>, borrows state: S): R

Applies the adapter a binding erased to borrowed state.

Arguments
NameTypeDescription
?self
adapterAdapter<T, M>
borrows stateS
Returns
TypeDescription
R

Contextinterface#

interface Context ...

Typed values a codec attaches to what it reads, such as the schema a document came from. Keys are nupp.util.Keys; a context returns its own value for a key, then its parent's.

Members

NameKindDescription
codecfieldThe identity of the codec that read the value.
profilefieldThe codec configuration the value was read under.
parentfieldThe context this one extends, or nil.
getmethodReturns the value held under a key, falling back to the parent's.

codecfield#

codec: table
@readonly

The identity of the codec that read the value.

profilefield#

@readonly

The codec configuration the value was read under. A JSON writer replays a captured value only under the same profile.

parentfield#

parent: Context?
@readonly

The context this one extends, or nil.

getmethod#

get: function<V is nupp.Copyable>(self, key: store.Key<V>): V?

Returns the value held under a key, falling back to the parent's.

Arguments
NameTypeDescription
?self
keystore.Key<V>
Returns
TypeDescription
V?

Decimalrecord#

record Decimal ...

An exact decimal: coefficient times ten to the exponent.

Members

NameKindDescription
coefficientfieldThe digits as decimal integer text, with a leading - when negative.
exponentfieldThe power of ten the coefficient is scaled by.

coefficientfield#

coefficient: string
@readonly

The digits as decimal integer text, with a leading - when negative.

exponentfield#

exponent: integer
@readonly

The power of ten the coefficient is scaled by.

Descriptioninterface#

interface Description<M is Member> ...

The shape of an adapter's value for one direction, which a codec plans against before it reads or writes anything.

Type parameters

NameDescription
M

Members

NameKindDescription
kindfieldThe value's broad shape.
memberfieldThe member the value sits at.
nullablefieldWhether the value may be an explicit null.
widthfieldThe width in bits of an integer or float, or nil for other kinds.
signedfieldWhether an integer is signed, or nil for other kinds.
canReadfieldWhether the adapter can construct a value when reading.
childrenfieldThe members of a structure or union, a list's one element, a tuple's slots in order, or a map's key and then its value.

kindfield#

kind: Kind
@readonly

The value's broad shape.

memberfield#

@readonly

The member the value sits at.

nullablefield#

nullable: boolean
@readonly

Whether the value may be an explicit null.

widthfield#

width: integer?
@readonly

The width in bits of an integer or float, or nil for other kinds.

signedfield#

signed: boolean?
@readonly

Whether an integer is signed, or nil for other kinds.

canReadfield#

canRead: boolean
@readonly

Whether the adapter can construct a value when reading. A codec refuses to plan a read of a value that cannot be constructed.

childrenfield#

children: const{Child<M>}
@readonly

The members of a structure or union, a list's one element, a tuple's slots in order, or a map's key and then its value.

Directiontype#

type Direction = "write" | "read"

Whether a description is for writing or for reading.

Discardinterface#

interface Discard<T> ...

Disposes a value a codec has to give up.

Type parameters

NameDescription
T

Members

NameKindDescription
discardmethodDrops a value the codec cannot hand back, such as one an adapter built before a later check on the input failed.

discardmethod#

discard: function(self, takes value: T): nil

Drops a value the codec cannot hand back, such as one an adapter built before a later check on the input failed.

Arguments
NameTypeDescription
?self
takes valueT
Returns
TypeDescription
nil

DocumentAdapterinterface#

interface DocumentAdapter<D> is Discard<D> ...

Reads and writes a document type as its logical contents. See nupp.serde.document.

Type parameters

NameDescription
D

Members

NameKindDescription
contextmethodReturns the context a document carries, or nil when it has none.
contentsmethodReturns the binding that writes a document's contents as an ordinary value.
readContentsmethodConstructs a document by reading its contents from reader.

contextmethod#

context: function(self, borrows document: D): Context?

Returns the context a document carries, or nil when it has none.

Arguments
NameTypeDescription
?self
borrows documentD
Returns
TypeDescription
Context?

contentsmethod#

contents: function(self): Binding<D>

Returns the binding that writes a document's contents as an ordinary value.

Arguments
NameTypeDescription
?self
Returns
TypeDescription
Binding<D>

readContentsmethod#

readContents: function(self, exclusive reader: DocumentReader): D

Constructs a document by reading its contents from reader.

Arguments
NameTypeDescription
?self
exclusive readerDocumentReader
Returns
TypeDescription
D

DocumentElementinterface#

interface DocumentElement<S> ...

Receives one document list element.

Type parameters

NameDescription
S

Members

NameKindDescription
applymethodReads the element at a 1-based index into state, consuming value.

applymethod#

apply: function(self, exclusive state: S, index: integer, exclusive value: DocumentReader): nil

Reads the element at a 1-based index into state, consuming value.

Arguments
NameTypeDescription
?self
exclusive stateS
indexinteger
exclusive valueDocumentReader
Returns
TypeDescription
nil

DocumentEntryinterface#

interface DocumentEntry<S> ...

Receives one document map entry.

Type parameters

NameDescription
S

Members

NameKindDescription
applymethodReads one entry into state, consuming both key and value.

applymethod#

apply: function(self, exclusive state: S, exclusive key: DocumentReader, exclusive value: DocumentReader): nil

Reads one entry into state, consuming both key and value.

Arguments
NameTypeDescription
?self
exclusive stateS
exclusive keyDocumentReader
exclusive valueDocumentReader
Returns
TypeDescription
nil

DocumentMemberinterface#

interface DocumentMember<S> ...

Receives one document structure member.

Type parameters

NameDescription
S

Members

NameKindDescription
applymethodReads the member called name into state, consuming value.

applymethod#

apply: function(self, exclusive state: S, name: string, exclusive value: DocumentReader): nil

Reads the member called name into state, consuming value.

Arguments
NameTypeDescription
?self
exclusive stateS
namestring
exclusive valueDocumentReader
Returns
TypeDescription
nil

DocumentReaderinterface#

interface DocumentReader ...

Reads one document value without a schema. See nupp.serde.document.

Members

NameKindDescription
contextmethodReturns the context the value came with, or nil.
kindmethodReturns the kind of the value without consuming it.
readNullmethodReads an explicit null.
readBooleanmethodReads a boolean.
readNumberTokenmethodReads a number as its unparsed text.
readStringmethodReads a string.
readBytesmethodReads a byte string.
readTimestampmethodReads a timestamp.
readIntegermethodReads an integer with the width it was written at.
readDecimalmethodReads an exact decimal.
readFloatmethodReads a floating-point value with the width it was written at.
readBigIntegermethodReads an integer of any size as decimal text.
readAtommethodReads a model-defined atom.
readDocumentmethodReads a nested document through adapter.
readListmethodReads a list, passing each element to consume in order.
readTuplemethodReads a tuple, passing each slot to consume in order.
readStructmethodReads a structure, passing each member to consume with its name.
readUnionmethodReads a union, passing its one alternative to consume with its name.
readMapmethodReads a map, passing each entry's key and value to consume.

contextmethod#

context: function(self): Context?

Returns the context the value came with, or nil.

Arguments
NameTypeDescription
?self
Returns
TypeDescription
Context?

kindmethod#

kind: function(self): Kind

Returns the kind of the value without consuming it.

Arguments
NameTypeDescription
?self
Returns
TypeDescription
Kind

readNullmethod#

readNull: function(exclusive self: DocumentReader): nil

Reads an explicit null.

Arguments
NameTypeDescription
exclusive selfDocumentReader
Returns
TypeDescription
nil

readBooleanmethod#

readBoolean: function(exclusive self: DocumentReader): boolean

Reads a boolean.

Arguments
NameTypeDescription
exclusive selfDocumentReader
Returns
TypeDescription
boolean

readNumberTokenmethod#

readNumberToken: function(exclusive self: DocumentReader): string

Reads a number as its unparsed text.

Arguments
NameTypeDescription
exclusive selfDocumentReader
Returns
TypeDescription
string

readStringmethod#

readString: function(exclusive self: DocumentReader): string

Reads a string.

Arguments
NameTypeDescription
exclusive selfDocumentReader
Returns
TypeDescription
string

readBytesmethod#

readBytes: function(exclusive self: DocumentReader): string

Reads a byte string.

Arguments
NameTypeDescription
exclusive selfDocumentReader
Returns
TypeDescription
string

readTimestampmethod#

readTimestamp: function(exclusive self: DocumentReader): Timestamp

Reads a timestamp.

Arguments
NameTypeDescription
exclusive selfDocumentReader
Returns
TypeDescription
Timestamp

readIntegermethod#

readInteger: function(exclusive self: DocumentReader): Integer

Reads an integer with the width it was written at.

Arguments
NameTypeDescription
exclusive selfDocumentReader
Returns
TypeDescription
Integer

readDecimalmethod#

readDecimal: function(exclusive self: DocumentReader): Decimal

Reads an exact decimal.

Arguments
NameTypeDescription
exclusive selfDocumentReader
Returns
TypeDescription
Decimal

readFloatmethod#

readFloat: function(exclusive self: DocumentReader): Float

Reads a floating-point value with the width it was written at.

Arguments
NameTypeDescription
exclusive selfDocumentReader
Returns
TypeDescription
Float

readBigIntegermethod#

readBigInteger: function(exclusive self: DocumentReader): string

Reads an integer of any size as decimal text.

Arguments
NameTypeDescription
exclusive selfDocumentReader
Returns
TypeDescription
string

readAtommethod#

readAtom: function(exclusive self: DocumentReader): Atom

Reads a model-defined atom.

Arguments
NameTypeDescription
exclusive selfDocumentReader
Returns
TypeDescription
Atom

readDocumentmethod#

readDocument: function<D>(exclusive self: DocumentReader, adapter: DocumentAdapter<D>): D

Reads a nested document through adapter.

Arguments
NameTypeDescription
exclusive selfDocumentReader
adapterDocumentAdapter<D>
Returns
TypeDescription
D

readListmethod#

readList: function<S>(exclusive self: DocumentReader, exclusive state: S, consume: DocumentElement<S>): nil

Reads a list, passing each element to consume in order.

Arguments
NameTypeDescription
exclusive selfDocumentReader
exclusive stateS
consumeDocumentElement<S>
Returns
TypeDescription
nil

readTuplemethod#

readTuple: function<S>(exclusive self: DocumentReader, exclusive state: S, consume: DocumentElement<S>): nil

Reads a tuple, passing each slot to consume in order.

Arguments
NameTypeDescription
exclusive selfDocumentReader
exclusive stateS
consumeDocumentElement<S>
Returns
TypeDescription
nil

readStructmethod#

readStruct: function<S>(exclusive self: DocumentReader, exclusive state: S, consume: DocumentMember<S>): nil

Reads a structure, passing each member to consume with its name.

Arguments
NameTypeDescription
exclusive selfDocumentReader
exclusive stateS
consumeDocumentMember<S>
Returns
TypeDescription
nil

readUnionmethod#

readUnion: function<S>(exclusive self: DocumentReader, exclusive state: S, consume: DocumentMember<S>): nil

Reads a union, passing its one alternative to consume with its name.

Arguments
NameTypeDescription
exclusive selfDocumentReader
exclusive stateS
consumeDocumentMember<S>
Returns
TypeDescription
nil

readMapmethod#

readMap: function<S>(exclusive self: DocumentReader, exclusive state: S, consume: DocumentEntry<S>): nil

Reads a map, passing each entry's key and value to consume.

Arguments
NameTypeDescription
exclusive selfDocumentReader
exclusive stateS
consumeDocumentEntry<S>
Returns
TypeDescription
nil

ElementConsumerinterface#

interface ElementConsumer<M is Member, S> ...

Receives one list or tuple element while reading.

Type parameters

NameDescription
M
S

Members

NameKindDescription
applymethodReads the element at a 1-based index into state, consuming exactly one value from reader.

applymethod#

apply: function(self, exclusive state: S, index: integer, exclusive reader: Reader<M>): nil

Reads the element at a 1-based index into state, consuming exactly one value from reader.

Arguments
NameTypeDescription
?self
exclusive stateS
indexinteger
exclusive readerReader<M>
Returns
TypeDescription
nil

EntryConsumerinterface#

interface EntryConsumer<M is Member, S> ...

Receives one map entry while reading.

Type parameters

NameDescription
M
S

Members

NameKindDescription
applymethodReads one entry into state, consuming one value from each of key and value.

applymethod#

apply: function(self, exclusive state: S, exclusive key: Reader<M>, exclusive value: Reader<M>): nil

Reads one entry into state, consuming one value from each of key and value.

Arguments
NameTypeDescription
?self
exclusive stateS
exclusive keyReader<M>
exclusive valueReader<M>
Returns
TypeDescription
nil

Errorrecord#

record Error ...

A serialization failure.

path is the logical path to the value, such as $["users"][2]["name"]; byte is the input offset when a decoder knows it. cause is the original problem, and suppressed collects failures raised while cleaning up after it.

local serde = require("nupp.serde")
local json = require("nupp.serde.json")
local record User
    id: integer
end
local ok, problem = pcall(json.decode, serde.binding(User), '{"id":"seven"}')
assert(not ok)
local failure = problem as serde.Error
assert(failure.path == '$["id"]')

Members

NameKindDescription
codefieldThe kind of failure.
messagefieldA description of the failure.
pathfieldThe logical path to the value, such as $["users"][2]["name"].
bytefieldThe input byte offset, when a decoder knows it.
causefieldThe original problem, such as the value an adapter raised.
suppressedfieldFailures raised while handling this one, such as a discard that failed after it.
__tostringmetamethodRenders the code, the path, the byte offset when known, and the message, as in model $["id"] at byte 7: expected an...

codefield#

code: Code
@readonly

The kind of failure.

messagefield#

message: string
@readonly

A description of the failure.

pathfield#

path: string
@readonly

The logical path to the value, such as $["users"][2]["name"].

bytefield#

byte: integer?
@readonly

The input byte offset, when a decoder knows it.

causefield#

cause: unknown
@readonly

The original problem, such as the value an adapter raised.

suppressedfield#

suppressed: const{unknown}
@readonly

Failures raised while handling this one, such as a discard that failed after it.

__tostringmetamethod#

__tostring: function(self): string

Renders the code, the path, the byte offset when known, and the message, as in model $["id"] at byte 7: expected an integer.

Arguments
NameTypeDescription
?self
Returns
TypeDescription
string

ErrorCodetype#

type ErrorCode = "syntax" | "limit" | "unsupported" | "model" | "contract"

What kind of failure an Error is: malformed input, an exceeded limit, a value the codec cannot represent, a model's own failure, or a broken adapter contract.

FieldOptionsrecord#

record FieldOptions ...

Mapping for one field of a declaration binding.

name replaces the wire name, overriding Options's naming. omitEmpty leaves an empty field out instead of writing it: nil, false, "", or an empty table. representation reinterprets the field's carrier; iso8601Seconds is the one supplied.

Members

NameKindDescription
omitEmptyfieldWhether encoding leaves the field out when it is empty.
representationfieldReinterprets the field's carrier, or nil to keep it.
namefieldThe field's wire name, overriding the options' naming, or nil to derive it.

omitEmptyfield#

omitEmpty: boolean
@readonly

Whether encoding leaves the field out when it is empty.

Empty is nil, false, the empty string, or a table with no entries. Decoding is unchanged.

representationfield#

representation: "iso8601Seconds"?
@readonly

Reinterprets the field's carrier, or nil to keep it.

"iso8601Seconds" writes epoch seconds as an RFC 3339 string and reads one back. The binding raises when the field's carrier is not integer or a sized integer narrower than 64 bits.

namefield#

name: string?
@readonly

The field's wire name, overriding the options' naming, or nil to derive it.

FieldViewinterface#

interface FieldView ...

Chooses an adapter in place of the one a declared type implies.

Set as Options's view. resolve is asked once for every type at every member the binding reaches: the root, each field, list and tuple elements, map keys and values, and both an optional type and the type inside it. It returns nil to keep the default, and an adapter it returns takes precedence over a field's representation.

Members

NameKindDescription
resolvemethodReturns the adapter for a type where it sits, or nil to keep the default.

resolvemethod#

resolve: function<M is core.Member>(
    self,
    info: nupp.reflect.Info,
    index: integer,
    member: M
): core.Adapter<unknown, M>?

Returns the adapter for a type where it sits, or nil to keep the default.

The binding asks once for each type at each member it reaches, from the root declaration down through fields, list and tuple elements, and map keys and values. An optional or const type is asked about before the type it wraps. A returned adapter replaces the default adapter outright, a field's representation included.

Arguments
NameTypeDescription
?self
infonupp.reflect.Info

the reflection graph of the declaration being bound

indexinteger

the type's position in info.types

memberM

the member the type sits at

Returns
TypeDescription
core.Adapter<unknown, M>?

the adapter, or nil for the default

Floatrecord#

record Float ...

A floating-point value with the width it was written at.

Members

NameKindDescription
valuefieldThe value as a Lua number.
widthfieldThe width in bits the value was written at.

valuefield#

value: number
@readonly

The value as a Lua number.

widthfield#

width: 32 | 64
@readonly

The width in bits the value was written at.

Integerrecord#

record Integer ...

An integer of a declared width, carried as its decimal text so 64-bit values survive targets without an exact carrier.

Members

NameKindDescription
decimalfieldThe value as decimal text, with a leading - when negative.
widthfieldThe width in bits the value must fit.
signedfieldWhether the value is signed; an unsigned value is never negative.

decimalfield#

decimal: string
@readonly

The value as decimal text, with a leading - when negative.

widthfield#

width: 8 | 16 | 32 | 64
@readonly

The width in bits the value must fit.

signedfield#

signed: boolean
@readonly

Whether the value is signed; an unsigned value is never negative.

IntoConsumerinterface#

interface IntoConsumer<T, S, O, R> ...

A Consumer that also writes into an exclusive output.

Type parameters

NameDescription
T
S
O
R

Members

NameKindDescription
applymethodApplies the adapter a binding erased to borrowed state, writing into output.

applymethod#

apply: function<M is Member>(self, adapter: Adapter<T, M>, borrows state: S, exclusive output: O): R

Applies the adapter a binding erased to borrowed state, writing into output.

Arguments
NameTypeDescription
?self
adapterAdapter<T, M>
borrows stateS
exclusive outputO
Returns
TypeDescription
R

Kindtype#

type Kind = ScalarKind | "dynamic" | "opaque" | "structure" | "union" | "list" | "tuple" | "map"

The broad shape of a value: a scalar kind, or a structure, union, list, tuple, map, or opaque value.

Memberinterface#

interface Member ...

A field, list element, or other position in a model's schema.

A model library implements this with whatever its schema needs, such as a shape identifier or numbered binary field, and its codec policy interprets it. Codecs see only name and, for positional formats, index.

Members

NameKindDescription
namefieldThe member's logical name, which a codec's policy maps to a wire name.
indexfieldThe member's position, for a format that numbers its fields, or nil.

namefield#

name: string
@readonly

The member's logical name, which a codec's policy maps to a wire name.

indexfield#

index: integer?
@readonly

The member's position, for a format that numbers its fields, or nil.

MemberConsumerinterface#

interface MemberConsumer<M is Member, S> ...

Receives one structure or union member while reading.

Type parameters

NameDescription
M
S

Members

NameKindDescription
applymethodReads a declared member's value into state, consuming exactly one value from reader.

applymethod#

apply: function(self, exclusive state: S, member: M, exclusive reader: Reader<M>): nil

Reads a declared member's value into state, consuming exactly one value from reader.

Arguments
NameTypeDescription
?self
exclusive stateS
memberM
exclusive readerReader<M>
Returns
TypeDescription
nil

Membersinterface#

interface Members<M is Member, S> ...

Emits a structure's members, a list's elements, or a map's entries.

Type parameters

NameDescription
M
S

Members

NameKindDescription
applymethodWrites the members, elements, or entries of source to writer.

applymethod#

apply: function(self, borrows source: S, exclusive writer: Writer<M>): nil

Writes the members, elements, or entries of source to writer.

Arguments
NameTypeDescription
?self
borrows sourceS
exclusive writerWriter<M>
Returns
TypeDescription
nil

Optionsrecord#

record Options ...

Field mapping for binding.

naming and unknownMembers apply to every record the binding reaches. fields maps the root declaration's fields one by one, and when it is present it is a whitelist, so a field it does not mention is neither written nor read.

local serde = require("nupp.serde")
local json = require("nupp.serde.json")
local record Account
    displayName: string
    passwordHash: string?
end
local public = serde.binding(Account, new serde.Options(
    naming = "snakeCase",
    fields = {displayName = new serde.FieldOptions()},
    unknownMembers = "ignore"
))
assert(json.encode(public, new Account(displayName = "Ada", passwordHash = "x")) == '{"display_name":"Ada"}')
assert(json.decode(public, '{"display_name":"Ada","admin":true}').passwordHash == nil)

A field left out of the whitelist must have a default for decoding to be selected; an encode-only binding can leave out required fields.

Members

NameKindDescription
fieldsfieldOptions for the root declaration's fields, keyed by declared name.
namingfieldHow declared field names become wire names, for every record and shape the binding reaches.
unknownMembersfieldWhat decoding does with a wire member no field declares, for every record and shape the binding reaches.
viewfieldChooses adapters in place of the defaults, or nil to keep every default.

fieldsfield#

fields: const{[string]: FieldOptions}?
@readonly

Options for the root declaration's fields, keyed by declared name.

When present it is a whitelist: a field it does not name is neither written nor read. It reaches the root declaration only, so a nested record keeps every field. The binding copies it, and raises when it names a field the declaration does not have.

namingfield#

naming: "identity" | "snakeCase" | "camelCase"
@readonly

How declared field names become wire names, for every record and shape the binding reaches.

"identity" keeps the name, "snakeCase" turns displayName into display_name, and "camelCase" turns display_name into displayName.

unknownMembersfield#

unknownMembers: "reject" | "ignore"
@readonly

What decoding does with a wire member no field declares, for every record and shape the binding reaches.

"reject" raises at the member and "ignore" skips its value.

viewfield#

@readonly

Chooses adapters in place of the defaults, or nil to keep every default.

OwnedBoundrecord#

record OwnedBound<T, M is Member> is Binding<T> ...

Erases an Adapter for a value that owns resources.

drop takes a decoded value the codec has to discard, such as one whose adapter returned without consuming its input, and drops it, so a failed decode does not leak what it built.

Type parameters

NameDescription
T
M

Members

NameKindDescription
adapterfieldThe adapter the binding erases.
dropmethodDrops a value the codec has to discard.
discardmethodDiscards a value by passing it to drop.
acceptmethodPasses adapter and state to consumer.
acceptIntomethodPasses adapter, state, and output to consumer.

adapterfield#

@readonly

The adapter the binding erases.

dropmethod#

drop: function(takes value: T): nil
@readonly

Drops a value the codec has to discard.

Arguments
NameTypeDescription
takes valueT
Returns
TypeDescription
nil

discardmethod#

discard: function discard(self, takes value: T): nil

Discards a value by passing it to drop.

Arguments
NameTypeDescription
selfany
takes valueT
Returns
TypeDescription
nil

acceptmethod#

accept: function accept<S, R>(self, consumer: Consumer<T, S, R>, borrows state: S): R

Passes adapter and state to consumer.

Arguments
NameTypeDescription
selfany
consumerConsumer<T, S, R>
borrows stateS
Returns
TypeDescription
R

acceptIntomethod#

acceptInto: function acceptInto<S, O, R>(self, consumer: IntoConsumer<T, S, O, R>, borrows state: S, exclusive output: O): R

Passes adapter, state, and output to consumer.

Arguments
NameTypeDescription
selfany
consumerIntoConsumer<T, S, O, R>
borrows stateS
exclusive outputO
Returns
TypeDescription
R

Presencetype#

type Presence = "absent" | "null" | "value"

Whether a member was absent, explicitly null, or present.

Readerinterface#

interface Reader<M is Member> ...

What a codec reads a value from. Adapters call it; codecs implement it.

Type parameters

NameDescription
M

Members

NameKindDescription
contextmethodReturns the context the codec attached to this read, or nil.
isNullmethodReturns whether the next value is an explicit null, without consuming it.
readNullmethodReads an explicit null at a member, raising when the member's description does not admit null.
readBooleanmethodReads a boolean at a member.
readIntegermethodReads an integer at a member, raising when it does not fit width and signed.
readFloatmethodReads a floating-point value at a member, narrowed to width bits.
readBigIntegermethodReads an integer of any size at a member, as decimal text.
readDecimalmethodReads an exact decimal at a member.
readNumberTokenmethodReads a number at a member as its unparsed text.
readStringmethodReads a string at a member.
readBytesmethodReads a byte string at a member.
readTimestampmethodReads a timestamp at a member.
readAtommethodReads a model-defined atom at a member.
readDocumentmethodReads a document at a member, through adapter.
readStructmethodReads a structure at a member.
readUnionmethodReads a union at a member, raising unless it holds exactly one alternative.
readListmethodReads a list at a member, passing each element to consume in order.
readTuplemethodReads a tuple of size slots at a member, passing each to consume in order.
readMapmethodReads a map at a member, passing each entry's key and value to consume.
containerSizemethodReturns the member, element, or entry count of the next value when the format knows it before reading, or nil.

contextmethod#

context: function(self): Context?

Returns the context the codec attached to this read, or nil.

Arguments
NameTypeDescription
?self
Returns
TypeDescription
Context?

isNullmethod#

isNull: function(self): boolean

Returns whether the next value is an explicit null, without consuming it.

Arguments
NameTypeDescription
?self
Returns
TypeDescription
boolean

readNullmethod#

readNull: function(exclusive self: Reader<M>, member: M): nil

Reads an explicit null at a member, raising when the member's description does not admit null.

Arguments
NameTypeDescription
exclusive selfReader<M>
memberM
Returns
TypeDescription
nil

readBooleanmethod#

readBoolean: function(exclusive self: Reader<M>, member: M): boolean

Reads a boolean at a member.

Arguments
NameTypeDescription
exclusive selfReader<M>
memberM
Returns
TypeDescription
boolean

readIntegermethod#

readInteger: function(exclusive self: Reader<M>, member: M, width: 8 | 16 | 32 | 64, signed: boolean): Integer

Reads an integer at a member, raising when it does not fit width and signed.

Arguments
NameTypeDescription
exclusive selfReader<M>
memberM
width8 | 16 | 32 | 64
signedboolean
Returns
TypeDescription
Integer

readFloatmethod#

readFloat: function(exclusive self: Reader<M>, member: M, width: 32 | 64): number

Reads a floating-point value at a member, narrowed to width bits.

Arguments
NameTypeDescription
exclusive selfReader<M>
memberM
width32 | 64
Returns
TypeDescription
number

readBigIntegermethod#

readBigInteger: function(exclusive self: Reader<M>, member: M): string

Reads an integer of any size at a member, as decimal text.

Arguments
NameTypeDescription
exclusive selfReader<M>
memberM
Returns
TypeDescription
string

readDecimalmethod#

readDecimal: function(exclusive self: Reader<M>, member: M): Decimal

Reads an exact decimal at a member.

Arguments
NameTypeDescription
exclusive selfReader<M>
memberM
Returns
TypeDescription
Decimal

readNumberTokenmethod#

readNumberToken: function(exclusive self: Reader<M>, member: M): string

Reads a number at a member as its unparsed text.

Arguments
NameTypeDescription
exclusive selfReader<M>
memberM
Returns
TypeDescription
string

readStringmethod#

readString: function(exclusive self: Reader<M>, member: M): string

Reads a string at a member.

Arguments
NameTypeDescription
exclusive selfReader<M>
memberM
Returns
TypeDescription
string

readBytesmethod#

readBytes: function(exclusive self: Reader<M>, member: M): string

Reads a byte string at a member.

Arguments
NameTypeDescription
exclusive selfReader<M>
memberM
Returns
TypeDescription
string

readTimestampmethod#

readTimestamp: function(exclusive self: Reader<M>, member: M): Timestamp

Reads a timestamp at a member.

Arguments
NameTypeDescription
exclusive selfReader<M>
memberM
Returns
TypeDescription
Timestamp

readAtommethod#

readAtom: function(exclusive self: Reader<M>, member: M): Atom

Reads a model-defined atom at a member. A codec that cannot represent atoms raises.

Arguments
NameTypeDescription
exclusive selfReader<M>
memberM
Returns
TypeDescription
Atom

readDocumentmethod#

readDocument: function<D>(exclusive self: Reader<M>, member: M, adapter: DocumentAdapter<D>): D

Reads a document at a member, through adapter.

Arguments
NameTypeDescription
exclusive selfReader<M>
memberM
adapterDocumentAdapter<D>
Returns
TypeDescription
D

readStructmethod#

readStruct: function<S>(
    exclusive self: Reader<M>,
    member: M,
    exclusive state: S,
    consume: MemberConsumer<M, S>,
    unknown: UnknownConsumer<S>
): nil

Reads a structure at a member.

Each declared member the policy reads is passed to consume, and each wire field the model does not declare to unknown.

Arguments
NameTypeDescription
exclusive selfReader<M>
memberM
exclusive stateS
consumeMemberConsumer<M, S>
unknownUnknownConsumer<S>
Returns
TypeDescription
nil

readUnionmethod#

readUnion: function<S>(
    exclusive self: Reader<M>,
    member: M,
    exclusive state: S,
    consume: MemberConsumer<M, S>,
    unknown: UnknownConsumer<S>
): nil

Reads a union at a member, raising unless it holds exactly one alternative.

A declared alternative is passed to consume, and an undeclared one to unknown.

Arguments
NameTypeDescription
exclusive selfReader<M>
memberM
exclusive stateS
consumeMemberConsumer<M, S>
unknownUnknownConsumer<S>
Returns
TypeDescription
nil

readListmethod#

readList: function<S>(exclusive self: Reader<M>, member: M, exclusive state: S, consume: ElementConsumer<M, S>): nil

Reads a list at a member, passing each element to consume in order.

Arguments
NameTypeDescription
exclusive selfReader<M>
memberM
exclusive stateS
consumeElementConsumer<M, S>
Returns
TypeDescription
nil

readTuplemethod#

readTuple: function<S>(
    exclusive self: Reader<M>,
    member: M,
    size: integer,
    exclusive state: S,
    consume: ElementConsumer<M, S>
): nil

Reads a tuple of size slots at a member, passing each to consume in order. The codec raises when the input holds a different count.

Arguments
NameTypeDescription
exclusive selfReader<M>
memberM
sizeinteger
exclusive stateS
consumeElementConsumer<M, S>
Returns
TypeDescription
nil

readMapmethod#

readMap: function<S>(exclusive self: Reader<M>, member: M, exclusive state: S, consume: EntryConsumer<M, S>): nil

Reads a map at a member, passing each entry's key and value to consume.

Arguments
NameTypeDescription
exclusive selfReader<M>
memberM
exclusive stateS
consumeEntryConsumer<M, S>
Returns
TypeDescription
nil

containerSizemethod#

containerSize: function(self): integer?

Returns the member, element, or entry count of the next value when the format knows it before reading, or nil.

Arguments
NameTypeDescription
?self
Returns
TypeDescription
integer?

ScalarKindtype#

type ScalarKind = "null"
| "boolean"
| "integer"
| "float"
| "bigInteger"
| "decimal"
| "numberToken"
| "string"
| "bytes"
| "timestamp"
| "atom"
| "document"

The scalar kinds a Writer and Reader carry.

Timestamprecord#

record Timestamp ...

An instant as whole seconds since the Unix epoch, in decimal text, and nanoseconds within that second.

Members

NameKindDescription
secondsfieldWhole seconds since the Unix epoch, as decimal integer text.
nanosfieldNanoseconds within the second, from 0 through 999999999.

secondsfield#

seconds: string
@readonly

Whole seconds since the Unix epoch, as decimal integer text.

nanosfield#

nanos: integer
@readonly

Nanoseconds within the second, from 0 through 999999999.

UnknownConsumerinterface#

interface UnknownConsumer<S> ...

Receives a wire field the model does not declare.

Type parameters

NameDescription
S

Members

NameKindDescription
applymethodReceives an undeclared field, whose value it must skip or capture through value.

applymethod#

apply: function<F is WireField>(self, exclusive state: S, field: F, exclusive value: UnknownReader): nil

Receives an undeclared field, whose value it must skip or capture through value.

Arguments
NameTypeDescription
?self
exclusive stateS
fieldF
exclusive valueUnknownReader
Returns
TypeDescription
nil

UnknownReaderinterface#

interface UnknownReader ...

Skips or captures an undeclared wire field's value.

Members

NameKindDescription
skipValuemethodSkips the value.
captureValuemethodReads the value as a document through adapter.

skipValuemethod#

skipValue: function(exclusive self: UnknownReader): nil

Skips the value.

Arguments
NameTypeDescription
exclusive selfUnknownReader
Returns
TypeDescription
nil

captureValuemethod#

captureValue: function<D>(exclusive self: UnknownReader, adapter: DocumentAdapter<D>): D

Reads the value as a document through adapter.

Arguments
NameTypeDescription
exclusive selfUnknownReader
adapterDocumentAdapter<D>
Returns
TypeDescription
D

WireFieldinterface#

interface WireField ...

A wire field a decoder met that the model does not declare.

Members

NameKindDescription
diagnosticLabelmethodReturns the field's name as a diagnostic shows it.

diagnosticLabelmethod#

diagnosticLabel: function(self): string

Returns the field's name as a diagnostic shows it.

Arguments
NameTypeDescription
?self
Returns
TypeDescription
string

Writerinterface#

interface Writer<M is Member> is nupp.Closeable ...

What a codec emits a value into. Adapters call it; codecs implement it.

Type parameters

NameDescription
M

Members

NameKindDescription
includemethodReturns whether the codec's policy writes a member at all.
writeNullmethodWrites an explicit null at a member.
writeBooleanmethodWrites a boolean at a member.
writeIntegermethodWrites an integer at a member, raising when it does not fit its width.
writeFloatmethodWrites a floating-point value at a member, narrowed to width bits.
writeBigIntegermethodWrites an integer of any size, given as decimal text, at a member.
writeDecimalmethodWrites an exact decimal at a member.
writeNumberTokenmethodWrites a number given as unparsed number text at a member.
writeStringmethodWrites a string at a member.
writeBytesmethodWrites a byte string at a member.
writeTimestampmethodWrites a timestamp at a member.
writeAtommethodWrites a model-defined atom at a member.
writeDocumentmethodWrites a document at a member, through adapter.
writeStructmethodWrites a structure at a member, whose members emit writes from source.
writeUnionmethodWrites a union at a member.
writeListmethodWrites a list at a member, whose elements emit writes from source.
writeTuplemethodWrites a tuple of size slots at a member, which emit writes from source.
writeMapmethodWrites a map at a member, whose entries emit writes from source through writeEntry.
writeEntrymethodWrites one entry of the map being written.
writeUnknownmethodWrites an undeclared wire field, such as one captured on an earlier read, into the structure being written.

includemethod#

include: function(exclusive self: Writer<M>, member: M): boolean

Returns whether the codec's policy writes a member at all.

An adapter skips the member on false. The codec may already have written a substitute in its place, such as a redaction.

Arguments
NameTypeDescription
exclusive selfWriter<M>
memberM
Returns
TypeDescription
boolean

writeNullmethod#

writeNull: function(exclusive self: Writer<M>, member: M): nil

Writes an explicit null at a member.

Arguments
NameTypeDescription
exclusive selfWriter<M>
memberM
Returns
TypeDescription
nil

writeBooleanmethod#

writeBoolean: function(exclusive self: Writer<M>, member: M, value: boolean): nil

Writes a boolean at a member.

Arguments
NameTypeDescription
exclusive selfWriter<M>
memberM
valueboolean
Returns
TypeDescription
nil

writeIntegermethod#

writeInteger: function(exclusive self: Writer<M>, member: M, borrows value: Integer): nil

Writes an integer at a member, raising when it does not fit its width.

Arguments
NameTypeDescription
exclusive selfWriter<M>
memberM
borrows valueInteger
Returns
TypeDescription
nil

writeFloatmethod#

writeFloat: function(exclusive self: Writer<M>, member: M, value: number, width: 32 | 64): nil

Writes a floating-point value at a member, narrowed to width bits.

Arguments
NameTypeDescription
exclusive selfWriter<M>
memberM
valuenumber
width32 | 64
Returns
TypeDescription
nil

writeBigIntegermethod#

writeBigInteger: function(exclusive self: Writer<M>, member: M, value: string): nil

Writes an integer of any size, given as decimal text, at a member.

Arguments
NameTypeDescription
exclusive selfWriter<M>
memberM
valuestring
Returns
TypeDescription
nil

writeDecimalmethod#

writeDecimal: function(exclusive self: Writer<M>, member: M, borrows value: Decimal): nil

Writes an exact decimal at a member.

Arguments
NameTypeDescription
exclusive selfWriter<M>
memberM
borrows valueDecimal
Returns
TypeDescription
nil

writeNumberTokenmethod#

writeNumberToken: function(exclusive self: Writer<M>, member: M, value: string): nil

Writes a number given as unparsed number text at a member.

Arguments
NameTypeDescription
exclusive selfWriter<M>
memberM
valuestring
Returns
TypeDescription
nil

writeStringmethod#

writeString: function(exclusive self: Writer<M>, member: M, value: string): nil

Writes a string at a member.

Arguments
NameTypeDescription
exclusive selfWriter<M>
memberM
valuestring
Returns
TypeDescription
nil

writeBytesmethod#

writeBytes: function(exclusive self: Writer<M>, member: M, value: string): nil

Writes a byte string at a member.

Arguments
NameTypeDescription
exclusive selfWriter<M>
memberM
valuestring
Returns
TypeDescription
nil

writeTimestampmethod#

writeTimestamp: function(exclusive self: Writer<M>, member: M, borrows value: Timestamp): nil

Writes a timestamp at a member.

Arguments
NameTypeDescription
exclusive selfWriter<M>
memberM
borrows valueTimestamp
Returns
TypeDescription
nil

writeAtommethod#

writeAtom: function<A is Atom>(exclusive self: Writer<M>, member: M, borrows value: A): nil

Writes a model-defined atom at a member. A codec that cannot represent the atom raises.

Arguments
NameTypeDescription
exclusive selfWriter<M>
memberM
borrows valueA
Returns
TypeDescription
nil

writeDocumentmethod#

writeDocument: function<D>(exclusive self: Writer<M>, member: M, borrows value: D, adapter: DocumentAdapter<D>): nil

Writes a document at a member, through adapter.

Arguments
NameTypeDescription
exclusive selfWriter<M>
memberM
borrows valueD
adapterDocumentAdapter<D>
Returns
TypeDescription
nil

writeStructmethod#

writeStruct: function<S>(exclusive self: Writer<M>, member: M, borrows source: S, emit: Members<M, S>): nil

Writes a structure at a member, whose members emit writes from source.

Arguments
NameTypeDescription
exclusive selfWriter<M>
memberM
borrows sourceS
emitMembers<M, S>
Returns
TypeDescription
nil

writeUnionmethod#

writeUnion: function<S>(exclusive self: Writer<M>, member: M, borrows source: S, emit: Members<M, S>): nil

Writes a union at a member. emit writes exactly one alternative from source.

Arguments
NameTypeDescription
exclusive selfWriter<M>
memberM
borrows sourceS
emitMembers<M, S>
Returns
TypeDescription
nil

writeListmethod#

writeList: function<S>(
    exclusive self: Writer<M>,
    member: M,
    size: integer?,
    borrows source: S,
    emit: Members<M, S>
): nil

Writes a list at a member, whose elements emit writes from source.

size is the element count, or nil when it is not known in advance. The codec raises when emit writes a different count.

Arguments
NameTypeDescription
exclusive selfWriter<M>
memberM
sizeinteger?
borrows sourceS
emitMembers<M, S>
Returns
TypeDescription
nil

writeTuplemethod#

writeTuple: function<S>(
    exclusive self: Writer<M>,
    member: M,
    size: integer,
    borrows source: S,
    emit: Members<M, S>
): nil

Writes a tuple of size slots at a member, which emit writes from source. The codec raises when emit writes a different count.

Arguments
NameTypeDescription
exclusive selfWriter<M>
memberM
sizeinteger
borrows sourceS
emitMembers<M, S>
Returns
TypeDescription
nil

writeMapmethod#

writeMap: function<S>(
    exclusive self: Writer<M>,
    member: M,
    size: integer?,
    borrows source: S,
    emit: Members<M, S>
): nil

Writes a map at a member, whose entries emit writes from source through writeEntry.

size is the entry count, or nil when it is not known in advance. The codec raises when emit writes a different count.

Arguments
NameTypeDescription
exclusive selfWriter<M>
memberM
sizeinteger?
borrows sourceS
emitMembers<M, S>
Returns
TypeDescription
nil

writeEntrymethod#

writeEntry: function<K, V>(
    exclusive self: Writer<M>,
    borrows key: K,
    keyEmit: Members<M, K>,
    borrows value: V,
    valueEmit: Members<M, V>
): nil

Writes one entry of the map being written.

keyEmit writes exactly one value from key, and valueEmit exactly one from value. The codec raises outside a writeMap.

Arguments
NameTypeDescription
exclusive selfWriter<M>
borrows keyK
keyEmitMembers<M, K>
borrows valueV
valueEmitMembers<M, V>
Returns
TypeDescription
nil

writeUnknownmethod#

writeUnknown: function<F is WireField, D>(
    exclusive self: Writer<M>,
    field: F,
    borrows value: D,
    adapter: DocumentAdapter<D>
): nil

Writes an undeclared wire field, such as one captured on an earlier read, into the structure being written.

adapter writes the field's document value. The codec raises outside a structure or union, or when the field collides with a declared member.

Arguments
NameTypeDescription
exclusive selfWriter<M>
fieldF
borrows valueD
adapterDocumentAdapter<D>
Returns
TypeDescription
nil

Functions#

accessfunction#

function access<T is nupp.Copyable>(target: Type<T>): Access<T>

Returns the Access for a declaration, cached on the declaration.

local serde = require("nupp.serde")
local record Point
    x: number
    y: number = 0
end
local point = serde.access(Point)
assert(#point.fields == 2 and point.fields[2].hasDefault)

Type parameters

NameDescription
T

Arguments

NameTypeDescription
targetType<T>

Returns

TypeDescription
Access<T>

bindingfunction#

function binding<T is nupp.Copyable>(target: Type<T>, options: Options?): core.Binding<T>

Builds a binding from a record or struct declaration.

Fields are read through the declaration's own access rules and values are constructed through its constructor, so defaults, @private storage, and custom construction all hold. Recursive types are supported. Optional fields and homogeneous literal unions use their declared carriers; a record union needs an explicit Adapter, since a declaration names no discriminator.

local serde = require("nupp.serde")
local json = require("nupp.serde.json")
local record Node
    name: string
    children: {Node} = {}
end
local nodes = serde.binding(Node)
local tree = new Node(name = "root", children = {new Node(name = "leaf")})
assert(json.encode(nodes, tree) == '{"name":"root","children":[{"name":"leaf","children":[]}]}')

Type parameters

NameDescription
T

Arguments

NameTypeDescription
targetType<T>
optionsOptions?

Returns

TypeDescription
core.Binding<T>

Values#

iso8601Secondsvariable#

const iso8601Seconds: "iso8601Seconds"

The representation that writes an integer field of epoch seconds as an RFC 3339 timestamp, and reads one back.

local serde = require("nupp.serde")
local json = require("nupp.serde.json")
local record Event
    at: integer
end
local events = serde.binding(Event, new serde.Options(
    fields = {at = new serde.FieldOptions(representation = serde.iso8601Seconds)}
))
assert(json.encode(events, new Event(at = 0)) == '{"at":"1970-01-01T00:00:00Z"}')
assert(json.decode(events, '{"at":"1970-01-01T00:01:00Z"}').at == 60)