# Module: `nupp.data`
# Data and text
`nupp.data` groups serialization, Unicode, identifiers and byte digests. Reach it
directly from the global [`nupp` namespace](stdlib.md); the C and Rust providers remain
hidden.
## JSON
`encodeJSON` and `decodeJSON` use the mature cjson implementation without exposing its
module name:
```nupp
local encoded = nupp.data.encodeJSON({name = "Nupp", ready = true})
local decoded = nupp.data.decodeJSON(encoded)
assert(decoded.name == "Nupp")
```
`null`, `emptyArray`, `arrayMt`, and `emptyArrayMt` preserve distinctions Lua tables
cannot express by themselves. The configuration methods match cjson's established
semantics, but live on `nupp.data`. `newJSON()` returns an independent `nupp.data.JSON`
encoder/decoder with its own settings:
```nupp
local compact = nupp.data.newJSON()
compact.encodeKeepBuffer(false)
local text = compact.encodeJSON({1, 2, 3})
```
JSON selects the `cjson` native feature. No `require("cjson")` is needed or recommended.
| Member | Result | Purpose |
| --- | --- | --- |
| `encodeJSON(value)` | `string` | Encode one Lua value. |
| `decodeJSON(text)` | `any` | Decode one JSON document. |
| `newJSON()` | `nupp.data.JSON` | Create an independently configured codec. |
| `null`, `emptyArray` | sentinel values | Represent JSON values that plain Lua tables cannot distinguish. |
| `arrayMt`, `emptyArrayMt` | metatables | Mark array-shaped tables explicitly. |
Both `nupp.data` and an object returned by `newJSON` provide the configuration
methods `encodeEmptyTableAsObject`, `decodeArrayWithArrayMt`,
`decodeAllowComment`, `encodeSparseArray`, `encodeMaxDepth`,
`decodeMaxDepth`, `encodeNumberPrecision`, `encodeKeepBuffer`,
`encodeInvalidNumbers`, `decodeInvalidNumbers`,
`encodeEscapeForwardSlash`, `encodeSkipUnsupportedValueTypes`, and
`encodeIndent`. Omitting a method's setting reads the current value where the
provider supports that form; passing a setting changes only that codec.
## UTF-8
`nupp.data.utf8` treats strings and [`nupp.io.ByteView`](io.md#byte-views) values as byte
sequences. Byte offsets are 1-based here so they compose with Lua string positions.
Invalid input decodes as U+FFFD while validation remains explicit.
```nupp
local utf8 = nupp.data.utf8
assert(utf8.length("A€") == 2)
local codepoint, nextByte = utf8.decodeAt("A€", 2)
assert(codepoint == 0x20ac and nextByte == 5)
codepoint, nextByte = utf8.decodeBefore("A€", nextByte)
assert(codepoint == 0x20ac and nextByte == 2)
assert(utf8.encode(0x20ac) == "€")
assert(utf8.isValid("café"))
assert(not utf8.isValid("\xff"))
assert(utf8.truncate("A€B", 4) == "A€")
```
`validPrefixLength(value, maxBytes)` returns the largest valid prefix no longer than the
byte budget. `truncate` applies that operation to a string. The underlying lua-utf8
provider loads only when this namespace is selected and reached.
| Member | Result | Position rule |
| --- | --- | --- |
| `length(value)` | `integer` | Counts decoded scalar values, replacing malformed bytes individually. |
| `decodeAt(value, byteOffset)` | `integer?, integer` | Decodes forward from a 1-based byte offset and returns the next offset. |
| `decodeBefore(value, byteOffset)` | `integer?, integer` | Decodes the scalar ending before a 1-based byte offset. |
| `encode(codepoint)` | `string` | Encodes one Unicode scalar value. |
| `isValid(value)` | `boolean` | Validates the complete byte sequence. |
| `validPrefixLength(value, maxBytes)` | `integer` | Finds a valid prefix within a byte budget. |
| `truncate(text, maxBytes)` | `string` | Copies that valid prefix. |
## UUIDs
`uuid4()` returns a random RFC 9562 version 4 identifier. `uuid7()` returns a
time-ordered version 7 identifier, useful when identifier order should roughly follow
creation order:
```nupp
local objectID = nupp.data.uuid4()
local eventID = nupp.data.uuid7()
```
Both are lowercase canonical strings. They share one `uuid` feature and never expose a
native UUID object.
## Hashes and checksums
Each function accepts a string or immutable [`nupp.io.ByteView`](io.md#byte-views).
```nupp
assert(nupp.data.fnv1a64("hello") == "a430d84680aabd0b")
assert(nupp.data.sha256("abc") ==
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad")
local checksum = nupp.data.crc32(header)
checksum = nupp.data.crc32(body, checksum)
```
`fnv1a64` is a fast non-cryptographic identity rendered as 16 lowercase hexadecimal
digits. `sha256` is a cryptographic digest rendered as 64 lowercase hexadecimal digits.
`adler32` and `crc32` return unsigned 32-bit numbers and accept a previous result for
incremental checksumming. Checksums detect accidental damage; they do not authenticate
data. A supplied previous checksum must itself be an unsigned 32-bit integer.
FNV-1a, Adler-32 and CRC-32 are pure generated Lua. SHA-256 is independently gated in
the shared Rust provider. See [automatic native selection](tooling/build.md#compiler-native-features).
| Member | Result | Native provider |
| --- | --- | --- |
| `uuid4()` | canonical UUID string | shared provider, `uuid` feature |
| `uuid7()` | canonical UUID string | shared provider, `uuid` feature |
| `fnv1a64(value)` | 16 lowercase hex digits | none |
| `sha256(value)` | 64 lowercase hex digits | shared provider, `sha256` feature |
| `adler32(value, previous?)` | unsigned 32-bit number | none |
| `crc32(value, previous?)` | unsigned 32-bit number | none |
JSON, UTF-8, UUIDs, hashes and checksums.
## Submodules
| Module | Description |
| --- | --- |
| `nupp.data.utf8` | UTF-8 codepoint operations over strings and byte views. |
## Constructors
### `newJSON` _constructor_
Creates an independent JSON codec with its own settings.
```nupp
local newJSON: function(): JSON
```
#### Returns
| Type | Description |
| --- | --- |
| `JSON` | the new codec |
## Types
### `JSON` _interface_
One independently configured JSON encoder and decoder.
```nupp
interface JSON
encodeJSON: function(value: any): string
decodeJSON: function(text: string): any
null: any
emptyArray: any
arrayMt: metatable<{any}>
emptyArrayMt: metatable<{any}>
encodeEmptyTableAsObject: function(setting: boolean | string?): boolean
decodeArrayWithArrayMt: function(setting: boolean | string?): boolean
decodeAllowComment: function(setting: boolean | string?): boolean
encodeSparseArray: function(convert: boolean?, ratio: integer?, safe: integer?): (boolean, integer, integer)
encodeMaxDepth: function(depth: integer?): integer
decodeMaxDepth: function(depth: integer?): integer
encodeNumberPrecision: function(precision: integer?): integer
encodeKeepBuffer: function(keep: boolean | string?): boolean
encodeInvalidNumbers: function(setting: boolean | string?): boolean | string
decodeInvalidNumbers: function(setting: boolean | string?): boolean
encodeEscapeForwardSlash: function(setting: boolean | string?): boolean
encodeSkipUnsupportedValueTypes: function(setting: boolean | string?): boolean
encodeIndent: function(indent: string?): string
end
```
#### Methods
##### `encodeJSON`
Encodes a Lua value as JSON text.
```nupp
encodeJSON: function(value: any): string
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `value` | `any` | the value to encode |
###### Returns
| Type | Description |
| --- | --- |
| `string` | the encoded JSON document |
##### `decodeJSON`
Decodes one JSON document into Lua values.
```nupp
decodeJSON: function(text: string): any
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `text` | `string` | the JSON document to decode |
###### Returns
| Type | Description |
| --- | --- |
| `any` | the decoded value |
##### `encodeEmptyTableAsObject`
Sets whether an empty table encodes as an object, or reads the current
setting when omitted.
```nupp
encodeEmptyTableAsObject: function(setting: boolean | string?): boolean
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `setting` | `boolean | string?` | true or "on" for `{}`, false or "off" for `[]` |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | whether empty tables encode as objects |
##### `decodeArrayWithArrayMt`
Sets whether decoded arrays carry `arrayMt`, or reads the current setting
when omitted.
```nupp
decodeArrayWithArrayMt: function(setting: boolean | string?): boolean
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `setting` | `boolean | string?` | the new setting |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | whether decoded arrays carry `arrayMt` |
##### `decodeAllowComment`
Sets whether the decoder accepts comments, or reads the current setting
when omitted.
```nupp
decodeAllowComment: function(setting: boolean | string?): boolean
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `setting` | `boolean | string?` | the new setting |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | whether comments are accepted |
##### `encodeSparseArray`
Configures how excessively sparse arrays are encoded, or reads the current
settings when every argument is omitted.
```nupp
encodeSparseArray: function(convert: boolean?, ratio: integer?, safe: integer?): (boolean, integer, integer)
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `convert` | `boolean?` | whether sparse arrays become JSON objects instead of raising |
| `ratio` | `integer?` | the maximum ratio between the highest index and item count |
| `safe` | `integer?` | the array size below which sparsity is always accepted |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | whether sparse arrays are converted |
| `integer` | the current ratio limit |
| `integer` | the current safe size |
##### `encodeMaxDepth`
Sets the maximum nested-container depth accepted by the encoder, or reads
the current limit when omitted.
```nupp
encodeMaxDepth: function(depth: integer?): integer
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `depth` | `integer?` | the new maximum depth |
###### Returns
| Type | Description |
| --- | --- |
| `integer` | the current maximum depth |
##### `decodeMaxDepth`
Sets the maximum nested-container depth accepted by the decoder, or reads
the current limit when omitted.
```nupp
decodeMaxDepth: function(depth: integer?): integer
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `depth` | `integer?` | the new maximum depth |
###### Returns
| Type | Description |
| --- | --- |
| `integer` | the current maximum depth |
##### `encodeNumberPrecision`
Sets the significant-digit precision used to encode numbers, or reads the
current precision when omitted.
```nupp
encodeNumberPrecision: function(precision: integer?): integer
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `precision` | `integer?` | the new number of significant digits |
###### Returns
| Type | Description |
| --- | --- |
| `integer` | the current precision |
##### `encodeKeepBuffer`
Sets whether the encoder reuses its internal buffer, or reads the current
setting when omitted.
```nupp
encodeKeepBuffer: function(keep: boolean | string?): boolean
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `keep` | `boolean | string?` | the new setting |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | whether the internal buffer is retained |
##### `encodeInvalidNumbers`
Configures encoding of NaN and infinities, or reads the current setting
when omitted.
```nupp
encodeInvalidNumbers: function(setting: boolean | string?): boolean | string
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `setting` | `boolean | string?` | false to reject them, true to emit them, or "null" to emit null |
###### Returns
| Type | Description |
| --- | --- |
| `boolean | string` | the active invalid-number setting |
##### `decodeInvalidNumbers`
Sets whether the decoder accepts NaN and infinities, or reads the current
setting when omitted.
```nupp
decodeInvalidNumbers: function(setting: boolean | string?): boolean
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `setting` | `boolean | string?` | the new setting |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | whether invalid numbers are accepted |
##### `encodeEscapeForwardSlash`
Sets whether `/` is escaped in JSON strings, or reads the current setting
when omitted.
```nupp
encodeEscapeForwardSlash: function(setting: boolean | string?): boolean
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `setting` | `boolean | string?` | the new setting |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | whether forward slashes are escaped |
##### `encodeSkipUnsupportedValueTypes`
Sets whether unsupported values are skipped instead of raising, or reads the
current setting when omitted.
```nupp
encodeSkipUnsupportedValueTypes: function(setting: boolean | string?): boolean
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `setting` | `boolean | string?` | the new setting |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | whether unsupported values are skipped |
##### `encodeIndent`
Sets the indentation used for encoded containers, or reads the current
indentation when omitted.
```nupp
encodeIndent: function(indent: string?): string
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `indent` | `string?` | the indentation string |
###### Returns
| Type | Description |
| --- | --- |
| `string` | the current indentation string |
#### Fields
| Name | Type | Description |
| --- | --- | --- |
| `null` | `any` | Sentinel that decodes from and encodes as JSON null. |
| `emptyArray` | `any` | Sentinel that always encodes as an empty JSON array. |
| `arrayMt` | `metatable\<{any}\>` | Metatable marking a table to encode as a JSON array. |
| `emptyArrayMt` | `metatable\<{any}\>` | Metatable marking a table to encode as an empty JSON array. |
### `JSONEncodable` _interface_
Values that can encode themselves as JSON text.
```nupp
interface JSONEncodable
toJSON: function(self): string
end
```
#### Methods
##### `toJSON`
```nupp
toJSON: function(self): string
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `?` | `self` | |
###### Returns
| Type | Description |
| --- | --- |
| `string` | |
## Functions
### `adler32` _function_
Computes or continues an Adler-32 checksum.
```nupp
local adler32: function(value: string | nupp.io.ByteView, previous: integer?): integer
```
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `value` | `string | nupp.io.ByteView` | the bytes to checksum |
| `previous` | `integer?` | a previous Adler-32 value, or 1 to start |
#### Returns
| Type | Description |
| --- | --- |
| `integer` | the unsigned 32-bit checksum |
### `crc32` _function_
Computes or continues a CRC-32 checksum.
```nupp
local crc32: function(value: string | nupp.io.ByteView, previous: integer?): integer
```
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `value` | `string | nupp.io.ByteView` | the bytes to checksum |
| `previous` | `integer?` | a previous CRC-32 value, or 0 to start |
#### Returns
| Type | Description |
| --- | --- |
| `integer` | the unsigned 32-bit checksum |
### `decodeAllowComment` _function_
Sets whether the decoder accepts comments, or reads the current setting
when omitted.
```nupp
local decodeAllowComment: function(setting: boolean | string?): boolean
```
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `setting` | `boolean | string?` | the new setting |
#### Returns
| Type | Description |
| --- | --- |
| `boolean` | whether comments are accepted |
### `decodeArrayWithArrayMt` _function_
Sets whether decoded arrays carry `arrayMt`, or reads the current setting
when omitted.
```nupp
local decodeArrayWithArrayMt: function(setting: boolean | string?): boolean
```
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `setting` | `boolean | string?` | the new setting |
#### Returns
| Type | Description |
| --- | --- |
| `boolean` | whether decoded arrays carry `arrayMt` |
### `decodeInvalidNumbers` _function_
Sets whether the decoder accepts NaN and infinities, or reads the current
setting when omitted.
```nupp
local decodeInvalidNumbers: function(setting: boolean | string?): boolean
```
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `setting` | `boolean | string?` | the new setting |
#### Returns
| Type | Description |
| --- | --- |
| `boolean` | whether invalid numbers are accepted |
### `decodeJSON` _function_
Decodes one JSON document into Lua values.
```nupp
local decodeJSON: function(text: string): any
```
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `text` | `string` | the JSON document to decode |
#### Returns
| Type | Description |
| --- | --- |
| `any` | the decoded value |
### `decodeMaxDepth` _function_
Sets the maximum nested-container depth accepted by the decoder, or reads
the current limit when omitted.
```nupp
local decodeMaxDepth: function(depth: integer?): integer
```
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `depth` | `integer?` | the new maximum depth |
#### Returns
| Type | Description |
| --- | --- |
| `integer` | the current maximum depth |
### `encodeEmptyTableAsObject` _function_
Sets whether an empty table encodes as an object, or reads the current
setting when omitted.
```nupp
local encodeEmptyTableAsObject: function(setting: boolean | string?): boolean
```
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `setting` | `boolean | string?` | true or "on" for `{}`, false or "off" for `[]` |
#### Returns
| Type | Description |
| --- | --- |
| `boolean` | whether empty tables encode as objects |
### `encodeEscapeForwardSlash` _function_
Sets whether `/` is escaped in JSON strings, or reads the current setting
when omitted.
```nupp
local encodeEscapeForwardSlash: function(setting: boolean | string?): boolean
```
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `setting` | `boolean | string?` | the new setting |
#### Returns
| Type | Description |
| --- | --- |
| `boolean` | whether forward slashes are escaped |
### `encodeIndent` _function_
Sets the indentation used for encoded containers, or reads the current
indentation when omitted.
```nupp
local encodeIndent: function(indent: string?): string
```
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `indent` | `string?` | the indentation string |
#### Returns
| Type | Description |
| --- | --- |
| `string` | the current indentation string |
### `encodeInvalidNumbers` _function_
Configures encoding of NaN and infinities, or reads the current setting
when omitted.
```nupp
local encodeInvalidNumbers: function(setting: boolean | string?): boolean | string
```
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `setting` | `boolean | string?` | false to reject them, true to emit them, or "null" to emit null |
#### Returns
| Type | Description |
| --- | --- |
| `boolean | string` | the active invalid-number setting |
### `encodeJSON` _function_
Encodes a Lua value as JSON text.
```nupp
local encodeJSON: function(value: any): string
```
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `value` | `any` | the value to encode |
#### Returns
| Type | Description |
| --- | --- |
| `string` | the encoded JSON document |
### `encodeKeepBuffer` _function_
Sets whether the encoder reuses its internal buffer, or reads the current
setting when omitted.
```nupp
local encodeKeepBuffer: function(keep: boolean | string?): boolean
```
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `keep` | `boolean | string?` | the new setting |
#### Returns
| Type | Description |
| --- | --- |
| `boolean` | whether the internal buffer is retained |
### `encodeMaxDepth` _function_
Sets the maximum nested-container depth accepted by the encoder, or reads
the current limit when omitted.
```nupp
local encodeMaxDepth: function(depth: integer?): integer
```
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `depth` | `integer?` | the new maximum depth |
#### Returns
| Type | Description |
| --- | --- |
| `integer` | the current maximum depth |
### `encodeNumberPrecision` _function_
Sets the significant-digit precision used to encode numbers, or reads the
current precision when omitted.
```nupp
local encodeNumberPrecision: function(precision: integer?): integer
```
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `precision` | `integer?` | the new number of significant digits |
#### Returns
| Type | Description |
| --- | --- |
| `integer` | the current precision |
### `encodeSkipUnsupportedValueTypes` _function_
Sets whether unsupported values are skipped instead of raising, or reads the
current setting when omitted.
```nupp
local encodeSkipUnsupportedValueTypes: function(setting: boolean | string?): boolean
```
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `setting` | `boolean | string?` | the new setting |
#### Returns
| Type | Description |
| --- | --- |
| `boolean` | whether unsupported values are skipped |
### `encodeSparseArray` _function_
Configures how excessively sparse arrays are encoded, or reads the current
settings when every argument is omitted.
```nupp
local encodeSparseArray: function(convert: boolean?, ratio: integer?, safe: integer?): (boolean, integer, integer)
```
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `convert` | `boolean?` | whether sparse arrays become JSON objects instead of raising |
| `ratio` | `integer?` | the maximum ratio between the highest index and item count |
| `safe` | `integer?` | the array size below which sparsity is always accepted |
#### Returns
| Type | Description |
| --- | --- |
| `boolean` | whether sparse arrays are converted |
| `integer` | the current ratio limit |
| `integer` | the current safe size |
### `fnv1a64` _function_
Computes the 64-bit FNV-1a digest of bytes.
```nupp
local fnv1a64: function(value: string | nupp.io.ByteView): string
```
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `value` | `string | nupp.io.ByteView` | the bytes to hash |
#### Returns
| Type | Description |
| --- | --- |
| `string` | the lowercase hexadecimal digest |
### `sha256` _function_
Computes the SHA-256 digest of bytes.
```nupp
local sha256: function(value: string | nupp.io.ByteView): string
```
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `value` | `string | nupp.io.ByteView` | the bytes to hash |
#### Returns
| Type | Description |
| --- | --- |
| `string` | the lowercase hexadecimal digest |
### `uuid4` _function_
Generates a random version 4 UUID.
```nupp
local uuid4: function(): string
```
#### Returns
| Type | Description |
| --- | --- |
| `string` | the canonical lowercase UUID text |
### `uuid7` _function_
Generates a time-ordered version 7 UUID.
```nupp
local uuid7: function(): string
```
#### Returns
| Type | Description |
| --- | --- |
| `string` | the canonical lowercase UUID text |
## Values
### `arrayMt` _variable_
Metatable marking a table to encode as a JSON array.
```nupp
local arrayMt: metatable<{any}>
```
### `emptyArray` _variable_
Sentinel that always encodes as an empty JSON array.
```nupp
local emptyArray: any
```
### `emptyArrayMt` _variable_
Metatable marking a table to encode as an empty JSON array.
```nupp
local emptyArrayMt: metatable<{any}>
```
### `null` _variable_
Sentinel that decodes from and encodes as JSON null.
```nupp
local null: any
```