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:
The full qualified form reaches the same declared file without the short binding:
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.macprovides keyed authentication, including HMAC-SHA256.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.utilowns the small general-purpose types:nupp.util.Bitsetis a growable set of bit positions, andnupp.util.Storeis a bag of values indexed by the typed keysnupp.util.newKeyhands out.nupp.util.Poolleases cleared record instances of one declared type from a free list.nupp.util.fnv1a64hashes bytes with FNV-1a.nupp.util.uuid4andnupp.util.uuid7generate identifiers, and are the only members here that reach a host provider.nupp.systemreports execution platform, architecture, endianness, pointer width and available parallelism, independently of the worker scheduler.nupp.hostasks whatever runs the program, a page or an embedding application, for something by kind, and carries streams between them.nupp.host.pumpruns an embedded component's operations for a host-owned loop. See Host requests.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.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.randomprovides cryptographically secure random bytes and owns deterministic pseudo-random sequences with explicit, serializable state.nupp.suspension,nupp.tasks, andnupp.workersprovide waiting, application task scopes, and isolated worker lanes.nupp.suspension.hostis the other side of waiting: what a host installs to decide which coroutine runs while something is parked.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 module selects its implementation while it is required and retains the actual functions. Generated module prologues bind those modules before the consumer body runs. Exported operations perform no SPI lookup.
Implementations satisfy the interface in the library's .spi module and are advertised in nupp/spi.json. Standard-library consumers choose the unique highest priority, or use their built-in fallback when discovery is empty. See SPI for ordinary selection code 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#
Storage offsets count from zero; element indexes count from one. Storage is a nupp.io.Buffer, a nupp.io.ByteView, a sharedbytes.Region or an open file: a range in one is a zero-based offset and a count, because an offset names a distance from the beginning and maps directly onto a native byte range. An element view, a span or a SoA view, and text, a Lua string or nupp.text.utf8, use 1-based positions, as a Lua array and string.sub do. 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. The files, process, network, TLS and HTTP modules give that reason as a nupp.io.Error, whose kind names the failure the same way on every platform, so a program branches on err.kind == "notFound" rather than on the message. An invalid argument or a malformed programmer-owned value raises at the call site. Every owner the library hands out, from a buffer to an open file, is a nupp.Closeable: close consumes it and returns nothing, nupp.drop closes it early, and the end of its scope closes it otherwise. A destination that buffers writes reports a failure through flush, so a caller that has to know flushes before it closes. Buffers and views 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.