# `nupp.serde`
`nupp.serde` separates logical data from its physical representation.
`Schema` is an immutable logical graph. `Binding` 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.
```nupp
@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:
```nupp
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"}
```
## Types
### `Binding` _interface_
```nupp
sealed interface Binding
schema: function(self): Schema
extension: function(self, key: any): any
end
```
A checked physical representation of a schema as `T`.
#### Type parameters
| Name | Description |
| --- | --- |
| `T` | |
#### Methods
##### `schema`
```nupp
schema: function(self): Schema
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `?` | `self` | |
###### Returns
| Type | Description |
| --- | --- |
| `Schema` | |
##### `extension`
```nupp
extension: function(self, key: any): any
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `?` | `self` | |
| `key` | `any` | |
###### Returns
| Type | Description |
| --- | --- |
| `any` | |
### `DynamicBinding` _interface_
```nupp
sealed interface DynamicBinding is Binding
bind: function(self, value: {[string]: any}): DynamicValue
newValue: function(self): DynamicValue
end
```
A binding that constructs dense run-time values.
#### Methods
##### `bind`
```nupp
bind: function(self, value: {[string]: any}): DynamicValue
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `?` | `self` | |
| `value` | `{\[string\]: any}` | |
###### Returns
| Type | Description |
| --- | --- |
| `DynamicValue` | |
##### `newValue`
```nupp
newValue: function(self): DynamicValue
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `?` | `self` | |
###### Returns
| Type | Description |
| --- | --- |
| `DynamicValue` | |
### `DynamicValue` _record_
```nupp
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`
```nupp
get: function get(self, member: Member): any
```
Reads a resolved member.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `member` | `Member` | |
###### Returns
| Type | Description |
| --- | --- |
| `any` | |
###### Raises
- when the member belongs to another schema
##### `get`
```nupp
get: function get(self, name: string): any
```
Reads a member by logical name.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `name` | `string` | |
###### Returns
| Type | Description |
| --- | --- |
| `any` | |
##### `set`
```nupp
set: function set(self, member: Member, value: any): nil
```
Sets a resolved member after checking its schema identity.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `member` | `Member` | |
| `value` | `any` | |
###### Returns
| Type | Description |
| --- | --- |
| `nil` | |
###### Raises
- when the member belongs to another schema
### `JsonCodec` _record_
```nupp
record JsonCodec
readonly profile: JsonProfile
function prepare(self, binding: Binding): Prepared end
function encode(self, binding: Binding, value: T): string end
function write(self, binding: Binding, value: T, exclusive out: Buffer): nil end
function write(self, binding: Binding, value: T, exclusive out: Writer): nil end
function decode(self, binding: Binding, text: string): (T?, string?) end
function decodeBuffer(self, binding: Binding, exclusive input: Buffer): (T?, string?) end
end
```
A JSON codec that lazily prepares bindings.
#### Methods
##### `prepare`
```nupp
prepare: function prepare(self, binding: Binding): Prepared
```
Prepares and memoizes a fused traversal.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `binding` | `Binding\` | |
###### Returns
| Type | Description |
| --- | --- |
| `Prepared\` | |
##### `encode`
```nupp
encode: function encode(self, binding: Binding, value: T): string
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `binding` | `Binding\` | |
| `value` | `T` | |
###### Returns
| Type | Description |
| --- | --- |
| `string` | |
##### `write`
```nupp
write: function write(self, binding: Binding, value: T, exclusive out: Buffer): nil
```
Appends one complete encoded root to caller-owned storage in one chunk.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `binding` | `Binding\` | |
| `value` | `T` | |
| `exclusive out` | `Buffer` | |
###### Returns
| Type | Description |
| --- | --- |
| `nil` | |
##### `write`
```nupp
write: function write(self, binding: Binding, value: T, exclusive out: Writer): nil
```
Streams one prepared value at the writer's current value position.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `binding` | `Binding\` | |
| `value` | `T` | |
| `exclusive out` | `Writer` | |
###### Returns
| Type | Description |
| --- | --- |
| `nil` | |
##### `decode`
```nupp
decode: function decode(self, binding: Binding, text: string): T?, string?
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `binding` | `Binding\` | |
| `text` | `string` | |
###### Returns
| Type | Description |
| --- | --- |
| `T?` | |
| `string?` | |
##### `decodeBuffer`
```nupp
decodeBuffer: function decodeBuffer(self, binding: Binding, exclusive input: Buffer): T?, string?
```
Decodes from caller-owned storage without materializing a final string.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `binding` | `Binding\` | |
| `exclusive input` | `Buffer` | |
###### Returns
| Type | Description |
| --- | --- |
| `T?` | |
| `string?` | |
#### Fields
##### `profile`
```nupp
profile: JsonProfile
```
### `JsonProfile` _record_
```nupp
record JsonProfile
readonly unknownMembers: "reject" | "ignore"
end
```
Immutable JSON wire-policy identity.
#### Fields
##### `unknownMembers`
```nupp
unknownMembers: "reject" | "ignore"
```
### `Kind` _type_
```nupp
type Kind = "unit"
| "null"
| "boolean"
| "integer"
| "unsigned"
| "number"
| "decimal"
| "string"
| "bytes"
| "timestamp"
| "optional"
| "list"
| "map"
| "structure"
| "tuple"
| "union"
| "stringEnum"
| "integerEnum"
| "document"
```
### `Member` _record_
```nupp
record Member
readonly index: integer
readonly name: string
readonly target: any
readonly required: boolean
readonly hasDefault: boolean
function metadata(self, key: MetadataKey): T? end
end
```
One structure member with a stable dense index.
#### Methods
##### `metadata`
```nupp
metadata: function metadata(self, key: MetadataKey): T?
```
Answers typed metadata attached to this member.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `key` | `MetadataKey\` | |
###### Returns
| Type | Description |
| --- | --- |
| `T?` | |
#### Fields
##### `index`
```nupp
index: integer
```
##### `name`
```nupp
name: string
```
##### `target`
```nupp
target: any
```
##### `required`
```nupp
required: boolean
```
##### `hasDefault`
```nupp
hasDefault: boolean
```
### `MetadataKey` _interface_
```nupp
interface MetadataKey
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
| Name | Description |
| --- | --- |
| `T` | |
#### Fields
##### `id`
```nupp
id: integer
```
##### `name`
```nupp
name: string?
```
### `Prepared` _interface_
```nupp
sealed interface Prepared
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
| Name | Description |
| --- | --- |
| `T` | |
#### Methods
##### `encode`
```nupp
encode: function(self, value: T): string
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `?` | `self` | |
| `value` | `T` | |
###### Returns
| Type | Description |
| --- | --- |
| `string` | |
##### `write`
```nupp
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
| Name | Type | Description |
| --- | --- | --- |
| `?` | `self` | |
| `value` | `T` | |
| `exclusive out` | `Buffer` | |
###### Returns
| Type | Description |
| --- | --- |
| `nil` | |
##### `decode`
```nupp
decode: function(self, text: string): (T?, string?)
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `?` | `self` | |
| `text` | `string` | |
###### Returns
| Type | Description |
| --- | --- |
| `T?` | |
| `string?` | |
##### `decodeBuffer`
```nupp
decodeBuffer: function(self, exclusive input: Buffer): (T?, string?)
```
Decodes a value held in caller-owned storage.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `?` | `self` | |
| `exclusive input` | `Buffer` | |
###### Returns
| Type | Description |
| --- | --- |
| `T?` | |
| `string?` | |
### `PreparedDebug` _interface_
```nupp
sealed interface PreparedDebug
format: function(self, value: T): string
write: function(self, value: T, exclusive out: Buffer): nil
end
```
A prepared schema-driven Debug formatter.
#### Type parameters
| Name | Description |
| --- | --- |
| `T` | |
#### Methods
##### `format`
```nupp
format: function(self, value: T): string
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `?` | `self` | |
| `value` | `T` | |
###### Returns
| Type | Description |
| --- | --- |
| `string` | |
##### `write`
```nupp
write: function(self, value: T, exclusive out: Buffer): nil
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `?` | `self` | |
| `value` | `T` | |
| `exclusive out` | `Buffer` | |
###### Returns
| Type | Description |
| --- | --- |
| `nil` | |
### `Schema` _record_
```nupp
record Schema
readonly kind: Kind
readonly name: string?
readonly members: {Member}
function extension(self, key: nupp.reflect.ExtensionKey): T end
function metadata(self, key: MetadataKey): 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`
```nupp
extension: function extension(self, key: nupp.reflect.ExtensionKey): T
```
Answers a lazily computed typed extension.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `key` | `nupp.reflect.ExtensionKey\` | |
###### Returns
| Type | Description |
| --- | --- |
| `T` | |
##### `metadata`
```nupp
metadata: function metadata(self, key: MetadataKey): T?
```
Answers typed metadata attached to this schema node.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `key` | `MetadataKey\` | |
###### Returns
| Type | Description |
| --- | --- |
| `T?` | |
##### `member`
```nupp
member: function member(self, name: string): Member?
```
Finds a structure member by its logical name.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `name` | `string` | |
###### Returns
| Type | Description |
| --- | --- |
| `Member?` | |
##### `element`
```nupp
element: function element(self): Schema?
```
Answers the element schema of an optional or list node.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
###### Returns
| Type | Description |
| --- | --- |
| `Schema?` | |
##### `key`
```nupp
key: function key(self): Schema?
```
Answers the key schema of a map node.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
###### Returns
| Type | Description |
| --- | --- |
| `Schema?` | |
##### `value`
```nupp
value: function value(self): Schema?
```
Answers the value schema of a map node.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
###### Returns
| Type | Description |
| --- | --- |
| `Schema?` | |
##### `expectMember`
```nupp
expectMember: function expectMember(self, name: string): Member
```
Finds a member or raises when it is absent.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `name` | `string` | |
###### Returns
| Type | Description |
| --- | --- |
| `Member` | |
###### Raises
- when the structure has no member with this name
#### Fields
##### `kind`
```nupp
kind: Kind
```
##### `name`
```nupp
name: string?
```
##### `members`
```nupp
members: {Member}
```
### `SchemaBuilder` _record_
```nupp
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(self, key: MetadataKey, value: T): SchemaBuilder end
function memberMetadata(self, name: string, key: MetadataKey, value: T): SchemaBuilder end
function freeze(self): Schema end
end
```
Incrementally constructs and then freezes a run-time structure schema.
#### Methods
##### `constructor`
```nupp
constructor: function constructor(self)
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
##### `structure`
```nupp
structure: function structure(self, name: string): SchemaBuilder
```
Starts a named structure.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `name` | `string` | |
###### Returns
| Type | Description |
| --- | --- |
| `SchemaBuilder` | |
###### Raises
- when a root was already selected
##### `required`
```nupp
required: function required(self, name: string, target: Schema): SchemaBuilder
```
Adds a required member.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `name` | `string` | |
| `target` | `Schema` | |
###### Returns
| Type | Description |
| --- | --- |
| `SchemaBuilder` | |
##### `optional`
```nupp
optional: function optional(self, name: string, target: Schema): SchemaBuilder
```
Adds an optional member.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `name` | `string` | |
| `target` | `Schema` | |
###### Returns
| Type | Description |
| --- | --- |
| `SchemaBuilder` | |
##### `defaulted`
```nupp
defaulted: function defaulted(self, name: string, target: Schema, value: any): SchemaBuilder
```
Adds a member with a default.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `name` | `string` | |
| `target` | `Schema` | |
| `value` | `any` | |
###### Returns
| Type | Description |
| --- | --- |
| `SchemaBuilder` | |
##### `metadata`
```nupp
metadata: function metadata(self, key: MetadataKey, value: T): SchemaBuilder
```
Attaches typed metadata to the root schema.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `key` | `MetadataKey\` | |
| `value` | `T` | |
###### Returns
| Type | Description |
| --- | --- |
| `SchemaBuilder` | |
##### `memberMetadata`
```nupp
memberMetadata: function memberMetadata(self, name: string, key: MetadataKey, value: T): SchemaBuilder
```
Attaches typed metadata to a named structure member.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `name` | `string` | |
| `key` | `MetadataKey\` | |
| `value` | `T` | |
###### Returns
| Type | Description |
| --- | --- |
| `SchemaBuilder` | |
###### Raises
- when the member is absent
##### `freeze`
```nupp
freeze: function freeze(self): Schema
```
Freezes and answers the immutable schema.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
###### Returns
| Type | Description |
| --- | --- |
| `Schema` | |
###### Raises
- when the builder has no root
### `Serializable` _interface_
```nupp
interface Serializable
end
```
Marker claimed by `@derive(nupp.derive.Serde)`.
Serialization remains a property of a `Binding`, not an instance method. The
empty contract lets derive advertise checked participation without making values
carry a codec API.
## Functions
### `bindingOf` _function_
```nupp
local function bindingOf(type: any): any
```
Retrieves the binding registered by `@derive(nupp.derive.Serde)`.
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `type` | `any` | |
#### Returns
| Type | Description |
| --- | --- |
| `any` | |
#### Raises
- when the type did not derive Serde
### `dynamic` _function_
```nupp
function dynamic(schema: Schema): DynamicBinding
```
Creates the indexed dynamic binding for a frozen schema.
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `schema` | `Schema` | |
#### Returns
| Type | Description |
| --- | --- |
| `DynamicBinding` | |
#### Raises
- when the schema is not a structure
### `json` _function_
```nupp
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
| Name | Type | Description |
| --- | --- | --- |
| `options` | `any?` | |
#### Returns
| Type | Description |
| --- | --- |
| `JsonCodec` | |
#### Raises
- when unknownMembers is not reject or ignore
### `key` _function_
```nupp
function key(name: string, binding: Binding): store.Key
```
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
| Name | Description |
| --- | --- |
| `T` | |
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `name` | `string` | the opaque name to register |
| `binding` | `Binding\` | the binding that encodes and decodes the value |
#### Returns
| Type | Description |
| --- | --- |
| `store.Key\` | the key |
#### Raises
- when the name is empty or already registered
### `list` _function_
```nupp
function list(target: Schema): Schema
```
Creates an immutable list node.
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `target` | `Schema` | |
#### Returns
| Type | Description |
| --- | --- |
| `Schema` | |
### `loadStore` _function_
```nupp
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
| Name | Type | Description |
| --- | --- | --- |
| `exclusive value` | `store.Store` | the store to write |
| `saved` | `{\[string\]: any}` | the table `saveStore` returned, or one decoded from a document |
#### Returns
| Type | Description |
| --- | --- |
| `nil` | nothing |
#### Raises
- when a name is not registered, its key has no binding, or a value does not fit
### `map` _function_
```nupp
function map(key: Schema, value: Schema): Schema
```
Creates an immutable map node.
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `key` | `Schema` | |
| `value` | `Schema` | |
#### Returns
| Type | Description |
| --- | --- |
| `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
### `metadataKey` _function_
```nupp
function metadataKey(): MetadataKey
```
Creates a typed schema metadata identity.
#### Type parameters
| Name | Description |
| --- | --- |
| `T` | |
#### Returns
| Type | Description |
| --- | --- |
| `MetadataKey\` | the key |
### `of` _function_
```nupp
function of(type: Type): Binding
```
#### Type parameters
| Name | Description |
| --- | --- |
| `T` | |
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `type` | `Type\` | |
#### Returns
| Type | Description |
| --- | --- |
| `Binding\` | |
### `optional` _function_
```nupp
function optional(target: Schema): Schema
```
Creates an immutable optional node.
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `target` | `Schema` | |
#### Returns
| Type | Description |
| --- | --- |
| `Schema` | |
### `prepareDebug` _function_
```nupp
function prepareDebug(binding: Binding): PreparedDebug
```
Prepares and memoizes Debug formatting for a binding.
#### Type parameters
| Name | Description |
| --- | --- |
| `T` | |
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `binding` | `Binding\` | |
#### Returns
| Type | Description |
| --- | --- |
| `PreparedDebug\` | |
### `saveStore` _function_
```nupp
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
| Name | Type | Description |
| --- | --- | --- |
| `borrows value` | `store.Store` | the store to save |
#### Returns
| Type | Description |
| --- | --- |
| `{\[string\]: any}` | a fresh table from name to plain value |
#### Raises
- when an occupied key is anonymous or was declared without a binding
## Values
### `boolean` _variable_
```nupp
const boolean
```
### `debugRedact` _variable_
```nupp
const debugRedact: MetadataKey
```
### `debugSkip` _variable_
```nupp
const debugSkip: MetadataKey
```
Standard Debug policy metadata shared by derived and dynamic schemas.
### `document` _variable_
```nupp
const document
```
### `int16` _variable_
```nupp
const int16
```
### `int32` _variable_
```nupp
const int32
```
### `int8` _variable_
```nupp
const int8
```
### `integer` _variable_
```nupp
const integer
```
### `null` _variable_
```nupp
const null
```
### `number` _variable_
```nupp
const number
```
### `string` _variable_
```nupp
const string
```
### `uint16` _variable_
```nupp
const uint16
```
### `uint32` _variable_
```nupp
const uint32
```
### `uint8` _variable_
```nupp
const uint8
```
### `unit` _variable_
```nupp
const unit
```
Format-neutral scalar schema singletons.