Standard library#
nupp is the compiler-provided intrinsic namespace, present in every checked file. Reach for it when a program needs bytes, text, digests, logging, math, or a parser and does not want a dependency for them.
local digest = nupp.digest.hexDigest("sha256", "payload")
print(#digest, nupp.math.lerp(10, 20, 0.25))Intrinsics and declared modules#
The namespace is a language surface, not an ambient source module and not a package tree assembled from declaration files. The compiler selects each implementation from the members checked source actually reaches, so nothing is loaded on a program's behalf.
Nupp-authored libraries outside that surface are ordinary declared modules on disk. A qualified module path loads one only when the source uses it:
const span = nupp.mem.span
local storage = carray(int32, 4)
local values = span.fromCarray(storage, 4)The full qualified form reaches the same declared file without the short binding:
local values = nupp.mem.span.fromCarray(storage, 4)It lowers to one hidden require in the containing module. It does not build a global nupp.mem table and does not add a load check at every call. The same rule applies to a dependency root such as tecs. See Modules for how a declared module is named and resolved.
Dive deeper
Keeping the intrinsic surface out of the module graph is what lets the compiler decide, per program, which implementations exist at all. A package tree would have to answer every parent-package import with a table whose members are all present, so either every program carries every facility or the answer depends on a load order the source does not show. A language surface hands out no such table: the members a file names are the members that get emitted.
Library modules#
The standard surface is deliberately small. These pages cover both the intrinsic namespaces and the declared modules:
nupp.digestprovides incremental MD5, SHA-1, SHA-256 and SHA-512 with provider lookup, output-size metadata and consuming finalization.nupp.checksumprovides Adler-32 and explicitly named CRC variants as numeric values; protocols choose their serialization byte order.nupp.hashprovides general-purpose FNV-1a hashing.nupp.macprovides keyed authentication, including HMAC-SHA256.nupp.cryptoprovides cryptographically secure random bytes.nupp.uuidgenerates version 4 and version 7 identifiers.nupp.codec.json,nupp.codec.base64andnupp.codec.hexencode and decode representations.nupp.codec.valuebuildersupports codec authors.nupp.text.utf8validates and walks UTF-8 text.nupp.serdebinds application types to reusable serialization schemas.nupp.storeowns typed keys and stores;nupp.bitsetowns bitsets.nupp.systemreports execution platform, architecture, endianness, pointer width and available parallelism, independently of the worker scheduler.nupp.io.storageprovides persistent key-value storage through the require-time provider.nupp.ioowns byte buffers, readers, writers, and typed scalar reads and writes over them.nupp.io.filesowns filesystem metadata and directories.nupp.io.netowns listeners and the connections they accept, and connections a program opens itself.nupp.io.tlsencrypts one of those connections.nupp.io.pathmodels filesystem paths, andnupp.io.urimodels resource names.nupp.logowns leveled logging over a swappable destination.nupp.mathowns scalar and two-dimensional vector helpers.nupp.mem.spanowns rooted, bounds-checked shared and writable C array views.nupp.mem.soastores every top-level field of a reified struct in its own column.nupp.mem.poolleases cleared record instances from a free list, andnupp.mem.arenaleases zero-filled struct rows from pages that never move.nupp.gpuowns resident buffers, generated kernel dispatches, and tensor views.nupp.gpu.layoutowns the checked layout algebra.nupp.browser.gpusupplies the bounded browserxorU32operation.nupp.randomowns deterministic pseudo-random sequences with explicit, serializable state.nupp.suspension,nupp.tasks, andnupp.workersprovide waiting, application task scopes, and isolated worker lanes.nupp.timeowns monotonic time, wall time, sleeps, and deadlines.nupp.pegcompiles byte-oriented parsing-expression grammars.
See GPU compute for generated GPU kernels and the browser provider, and Worker tasks for the worker scheduler and sendable values.
Availability and initialization#
nupp and nupp.math are intrinsic namespaces. The other standard modules have their own declared module identities and are loaded through qualified references or ordinary require calls. Providers resolve while their facades load.
Selection follows use#
A member's implementation is emitted only when checked source resolves that member, and an alias stays as precise as the name it came from:
At -O1 and above, feature effects are recomputed after constant folding, so a facility used only in a branch or loop that dead-code elimination removed keeps neither its adapter nor its provider. Code generation makes the final selection from the constructs it actually writes, so comptime erasure, materialization, and other lowering cannot leave a source-only facility in the generated first-line bootstrap. Native FFI declarations are split by that same set: selecting UUID does not declare the path, files, or process ABI. SHA-256 declares none of its own: it is Nupp rather than a native provider.
Provider initialization#
A service-backed module resolves its provider while it is required. Generated module prologues bind those modules before the consumer body runs. Exported operations retain the resolved implementation and call it directly.
A setup entry imports canonical handles from nupp.runtime.services, registers or selects implementations, and then requires its consumer entry. Importing a contract defines its handle without loading a provider. Once a facade resolves, its default selection is fixed for that Lua state. See service providers for typed contracts and package discovery.
The public surface does not expose the JSON provider module, a provider's own handles, or FFI pointers. Those are implementation details, so application code keeps the same Nupp API when a provider changes.
Forcing a native feature#
nativeFeatures turns a binary feature on or off for an unusual packaging arrangement. Leave it unset and use automatic detection unless the packaging requires otherwise.
Byte positions#
String functions inherited from Lua use 1-based positions. The byte container APIs use zero-based offsets, because an offset names a distance from the beginning and maps directly onto a native byte range. Each API page states its convention; do not pass a string.find position to a buffer method.
Errors and ownership#
An operation that can fail because of the environment returns nil, reason. An invalid argument or a malformed programmer-owned value raises at the call site. Buffers and views implement close and report use after release, and a reader or writer returns a reason once it has been closed. See ownership.md for the cleanup obligation an affine result carries.
FAQ#
Does an intrinsic need a require?#
No. A member reached through the nupp namespace is selected by the compiler from the source that names it, which is why the example above runs with no imports. A declared module such as nupp.mem.span is a file on disk, so it is bound with require or reached through its qualified name, as Intrinsics and declared modules shows.
Does an unused facility cost anything in the built program?#
No adapter and no native artifact are emitted for a member no checked source resolves. Selection is recomputed after constant folding at -O1 and above, so a facility whose only use was eliminated drops out with it. See Selection follows use for what counts as a use.
Can a buffer offset be passed to a Lua string function?#
Not directly. A buffer offset counts from zero and a Lua string position counts from one, so the two differ by one on every call. Convert at the boundary, and see Byte positions for which convention an API uses.