# `nupp.serde.codec` A new codec uses these helpers to apply the number, timestamp, error-path, and context rules the built-in codecs share. It implements `nupp.serde.Writer` and `nupp.serde.Reader` itself; see [Serialization bindings](../../../../learn/runtime/data/serde/index.html#model-owned-bindings) for where a codec sits beside a model library. A codec that follows these rules accepts and rejects the same values as `nupp.serde.json` and `nupp.serde.native`, so a binding behaves the same whichever one carries it. ```nupp local codec = require("nupp.serde.codec") assert(codec.integer("255", 8, false).decimal == "255") assert(not pcall(codec.integer, "256", 8, false)) assert(codec.formatDateTime(codec.parseEpoch("86400")) == "1970-01-02T00:00:00Z") ``` ## Types ### `ContextBuilder` _record_ ```nupp record ContextBuilder ... ``` Collects the values of a `nupp.serde.Context` before it is frozen. #### Members | Name | Kind | Description | | --- | --- | --- | | [`codec`](#nupp.serde.codec.ContextBuilder.codec) | field | | | [`profile`](#nupp.serde.codec.ContextBuilder.profile) | field | | | [`parent`](#nupp.serde.codec.ContextBuilder.parent) | field | | | [`values`](#nupp.serde.codec.ContextBuilder.values) | field | | | [`frozen`](#nupp.serde.codec.ContextBuilder.frozen) | field | | | [`set`](#nupp.serde.codec.ContextBuilder.set) | method | Stores a value under a key, replacing any value set before. | | [`freeze`](#nupp.serde.codec.ContextBuilder.freeze) | method | Returns the context holding the values set so far. | #### `codec` _field_ ```nupp codec: table ``` `@private` `@readonly` #### `profile` _field_ ```nupp profile: table ``` `@private` `@readonly` #### `parent` _field_ ```nupp parent: core.Context? ``` `@private` `@readonly` #### `values` _field_ ```nupp values: {[unknown]: Entry} ``` `@private` `@readonly` #### `frozen` _field_ ```nupp frozen: boolean ``` `@private` #### `set` _method_ ```nupp set: function set(self, key: store.Key, value: V): nil ``` Stores a value under a key, replacing any value set before. ##### Arguments | Name | Type | Description | | --- | --- | --- | | `self` | `any` | | | `key` | `store.Key\` | the key to store under | | `value` | `V` | the value | ##### Returns | Type | Description | | --- | --- | | `nil` | | ##### Raises | Type | Condition | | --- | --- | | `string` | when the builder is frozen | #### `freeze` _method_ ```nupp freeze: function freeze(self): core.Context ``` Returns the context holding the values set so far. The builder can then no longer change, so the context it returned cannot either. A key the context does not hold is looked up in its parent. ##### Arguments | Name | Type | Description | | --- | --- | --- | | `self` | `any` | | ##### Returns | Type | Description | | --- | --- | | `core.Context` | the context | ##### Raises | Type | Condition | | --- | --- | | `string` | when the builder is already frozen | ## Functions ### `contextBuilder` _function_ ```nupp function contextBuilder(codec: table, profile: table, parent: core.Context?): Builder ``` Starts a context for what a codec reads. `codec` and `profile` identify where the value came from, so a protocol can refuse to replay a document captured under an incompatible one. Values are set under `nupp.util.Key`s and must be Copyable. ```nupp local codec = require("nupp.serde.codec") local source: nupp.util.Key = nupp.util.newKey() local builder = codec.contextBuilder({}, {}, nil) builder:set(source, "upload.json") assert(builder:freeze():get(source) == "upload.json") ``` #### Arguments | Name | Type | Description | | --- | --- | --- | | `codec` | `table` | | | `profile` | `table` | | | `parent` | `core.Context?` | | #### Returns | Type | Description | | --- | --- | | `Builder` | | ### `discardFailed` _function_ ```nupp function discardFailed(owner: core.Discard, takes value: T, cause: unknown): unknown ``` Discards a value a codec decoded and then has to reject, returning the failure to raise. When the discard itself fails, its failure is recorded in the error's `suppressed` list and the original cause is kept. #### Type parameters | Name | Description | | --- | --- | | `T` | | #### Arguments | Name | Type | Description | | --- | --- | --- | | `owner` | `core.Discard\` | | | `takes value` | `T` | | | `cause` | `unknown` | | #### Returns | Type | Description | | --- | --- | | `unknown` | | ### `float` _function_ ```nupp function float(value: number, width: 32 | 64, allowNonfinite: boolean?): number ``` Rounds a number to a float width and checks it is finite. #### Arguments | Name | Type | Description | | --- | --- | --- | | `value` | `number` | | | `width` | `32 | 64` | | | `allowNonfinite` | `boolean?` | | #### Returns | Type | Description | | --- | --- | | `number` | | ### `formatDateTime` _function_ ```nupp function formatDateTime(borrows value: core.Timestamp): string ``` Formats a timestamp as an RFC 3339 date-time in UTC. #### Arguments | Name | Type | Description | | --- | --- | --- | | `borrows value` | `core.Timestamp` | | #### Returns | Type | Description | | --- | --- | | `string` | | ### `formatEpoch` _function_ ```nupp function formatEpoch(borrows value: core.Timestamp): string ``` Formats a timestamp as epoch seconds. #### Arguments | Name | Type | Description | | --- | --- | --- | | `borrows value` | `core.Timestamp` | | #### Returns | Type | Description | | --- | --- | | `string` | | ### `integer` _function_ ```nupp function integer(text: string, width: 8 | 16 | 32 | 64, signed: boolean): core.Integer ``` Checks an integer lexeme against a width and signedness. #### Arguments | Name | Type | Description | | --- | --- | --- | | `text` | `string` | | | `width` | `8 | 16 | 32 | 64` | | | `signed` | `boolean` | | #### Returns | Type | Description | | --- | --- | | `core.Integer` | | ### `parseDateTime` _function_ ```nupp function parseDateTime(text: string): core.Timestamp ``` Parses an RFC 3339 date-time. #### Arguments | Name | Type | Description | | --- | --- | --- | | `text` | `string` | | #### Returns | Type | Description | | --- | --- | | `core.Timestamp` | | ### `parseEpoch` _function_ ```nupp function parseEpoch(text: string): core.Timestamp ``` Parses epoch seconds, with an optional fraction. #### Arguments | Name | Type | Description | | --- | --- | --- | | `text` | `string` | | #### Returns | Type | Description | | --- | --- | | `core.Timestamp` | | ### `prefixError` _function_ ```nupp function prefixError(problem: unknown, parent: string): Error ``` Prefixes a failure's path with its parent's. #### Arguments | Name | Type | Description | | --- | --- | --- | | `problem` | `unknown` | the raised value | | `parent` | `string` | the path of the enclosing value | #### Returns | Type | Description | | --- | --- | | `Error` | the error, carrying the combined path | ### `wrapError` _function_ ```nupp function wrapError(problem: unknown, path: string, byte: integer?): Error ``` Wraps any failure as a `nupp.serde.Error` at a path. An existing error is returned unchanged, so wrapping at each level keeps the innermost path. #### Arguments | Name | Type | Description | | --- | --- | --- | | `problem` | `unknown` | the raised value | | `path` | `string` | the logical path to record on a new error | | `byte` | `integer?` | the input offset to record on a new error, or nil | #### Returns | Type | Description | | --- | --- | | `Error` | the error |