# `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.