Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Standard Library

Decision

Modular implementation, one file per library, matching PUC-Rio Lua 5.1.1 standard library behavior.

Overview

Lua 5.1.1 ships with 9 standard libraries (base, coroutine, string, table, math, io, os, debug, package). The coroutine library is registered as part of luaopen_base() but occupies its own namespace. Each library is a collection of functions registered in a table (or as globals for the base library). Libraries can be loaded selectively — an embedded Lua environment may omit io and os for sandboxing.

Libraries

Base Library (stdlib/base.rs)

Global functions not in any table.

FunctionStatusNotes
assertRequiredError with optional message
collectgarbageRequired7 options
dofileRequiredLoad and execute file
errorRequiredThrow error object at level
getfenvRequiredGet function environment
getmetatableRequiredGet metatable (respects __metatable)
ipairsRequiredInteger key iterator
loadRequiredLoad chunk from function
loadfileRequiredLoad chunk from file
loadstringRequiredLoad chunk from string
gcinfoRequiredDeprecated GC info (returns KB used)
nextRequiredTable traversal
pairsRequiredGeneric table iterator
pcallRequiredProtected call
printRequiredPrint to stdout (uses tostring)
rawequalRequiredEquality without metamethods
rawgetRequiredTable access without metamethods
rawsetRequiredTable assignment without metamethods
_GRequiredGlobal table reference
selectRequiredselect(n, ...) or select('#', ...)
setfenvRequiredSet function environment
setmetatableRequiredSet metatable (respects __metatable)
tonumberRequiredConvert to number (with base)
tostringRequiredConvert to string (uses __tostring)
typeRequiredType name as string
unpackRequiredTable to multiple values
xpcallRequiredProtected call with error handler
_VERSIONRequired"Lua 5.1"
newproxyOptionalUndocumented, creates proxy userdata

Base Library Behavioral Notes

assert(v [, message]) — if v is nil or false, calls error(message). Default message is "assertion failed!". Returns all arguments on success.

error(message [, level]) — level 0 means no position prefix. Level 1 (default) prefixes with the current function’s location. Level 2 uses the caller’s location, etc. If message is not a string, no position prefix is added.

getfenv(f)f can be a function or a number (stack level). Level 0 returns the thread environment. Level 1 (default) returns the current function’s environment. getfenv(0) differs from getfenv() (the latter defaults to level 1).

getmetatable(object) — if the metatable has a __metatable field, returns that field’s value instead of the actual metatable. This protects metatables from user inspection.

ipairs(t) — returns an iterator function, the table, and 0. The iterator returns index, value pairs starting at 1 until t[index] is nil. Uses raw access (no metamethods).

pcall(f, ...) — calls f(...) in protected mode. Returns true, results... on success or false, error on failure. The error object can be any type, not just strings.

select(index, ...) — if index is "#", returns the count of remaining arguments. If index is negative, counts from the end. Error: "index out of range" if the resulting position is < 1.

setfenv(f, table) — level 0 changes the thread environment (returns nothing). Cannot change environments of C functions (error: "'setfenv' cannot change environment of given object").

setmetatable(table, metatable) — first arg must be a table (not userdata). If the existing metatable has a __metatable field, error: "cannot change a protected metatable".

tonumber(e [, base]) — base 10 uses lua_isnumber (handles strings, hex 0xff, whitespace). Other bases (2-36) use unsigned integer conversion only. Returns nil on failure.

tostring(e) — checks __tostring metamethod first. Without metamethod: numbers use "%.14g" format, booleans produce "true"/"false", nil produces "nil", other types produce "typename: pointer".

unpack(list [, i [, j]])i defaults to 1, j defaults to #list. Returns list[i] through list[j] using raw access. Error: "table too big to unpack" if the range exceeds stack space.

xpcall(f, err) — calls f() with zero arguments (extra args are discarded). The error handler receives the original error object and its return value becomes the error returned by xpcall.

Coroutine Library (stdlib/base.rs)

FunctionNotes
coroutine.createCreate coroutine from function
coroutine.resumeResume suspended coroutine
coroutine.runningReturn running coroutine (returns nothing if main thread)
coroutine.statusReturn status string (running/suspended/normal/dead)
coroutine.wrapCreate coroutine as iterator function
coroutine.yieldSuspend execution, return values to resume

String Library (stdlib/string.rs)

Registered as the string table and as the string metatable’s __index.

FunctionNotes
string.byteCharacter codes
string.charCharacters from codes
string.dumpDump function bytecode
string.findPattern matching search
string.formatFormatted string output
string.gmatchGlobal pattern match iterator
string.gsubGlobal pattern substitution
string.lenString length
string.lowerLowercase conversion
string.matchPattern match extraction
string.repString repetition
string.reverseString reversal
string.subSubstring extraction
string.upperUppercase conversion
string.gfindDeprecated alias for gmatch (works by default; raises error only if LUA_COMPAT_GFIND is undefined)

Lua 5.1 patterns are NOT regular expressions. They support character classes (%a, %d, %w, etc.), anchors (^, $), quantifiers (*, +, -, ?), captures, and backreferences (%1 through %9 to match a previous capture). They do not support alternation.

String Library Behavioral Notes

string.byte(s [, i [, j]])i defaults to 1, j defaults to i. Negative positions count from end. Returns one integer per byte (0-255). Stack check: "string slice too long".

string.char(...) — each argument must be 0-255 (error: "invalid value"). No arguments returns empty string.

string.dump(function) — function must be a Lua function, not a C function (error: "unable to dump given function").

string.find(s, pattern [, init [, plain]])init defaults to 1 (negative counts from end). Plain mode does literal substring search. Returns start, end, captures... on match, nil on failure. Positions are 1-based.

string.format(formatstring, ...) — specifiers: c d i o u x X e E f g G q s and %%. Flags: - + (space) # 0. Width/precision max 2 digits each. %q produces a Lua-readable quoted string (escapes ", \, newlines, \r, \0). %s with no precision and string >= 100 chars pushes directly (no truncation).

string.gmatch(s, pattern) — returns an iterator. Each call returns the next match’s captures. Empty matches advance by 1 character to prevent infinite loops.

string.gsub(s, pattern, repl [, n]) — replacement can be string (%0=match, %1-%9=captures, %%=literal %), function (called with captures; falsy return keeps original), or table (first capture as key; falsy result keeps original). Returns the result string and substitution count.

string.sub(s, i [, j])j defaults to -1 (end of string). Negative positions count from end. Returns empty string if start > end.

Pattern Language Specification

Character classes (from match_class in lstrlib.c):

ClassMatchesNegation
%aletters (isalpha)%A
%ccontrol characters (iscntrl)%C
%ddigits (isdigit)%D
%llowercase letters (islower)%L
%ppunctuation (ispunct)%P
%swhitespace (isspace)%S
%uuppercase letters (isupper)%U
%walphanumeric (isalnum)%W
%xhex digits (isxdigit)%X
%zthe null byte (\0)%Z
%.literal . (any % + non-letter = literal)

Bracket classes: [abc] matches any of a, b, c. [^abc] negated. [a-z] ranges. % classes work inside brackets.

Single character matchers: . matches any character. %x matches a class. [...] matches a bracket class. Anything else matches literally.

Quantifiers:

QuantifierMeaningStrategy
*0 or moreGreedy (max first, backtrack)
+1 or moreGreedy
-0 or moreLazy (min first, extend)
?0 or 1Greedy

Anchors: ^ at pattern start anchors to beginning. $ at pattern end anchors to end. Elsewhere they are literal.

Captures: (...) captures matched text. () captures the position (1-based integer) instead of text. Maximum 32 captures (LUA_MAXCAPTURES). Backreferences: %1 through %9 match the same text as the corresponding capture.

Special patterns: %bxy matches balanced delimiters (e.g., %b() matches balanced parentheses). %f[set] is a frontier pattern — matches a position where the previous character does not match [set] and the current character does. At string start, the “previous character” is \0.

Error conditions: "malformed pattern (ends with '%%')", "malformed pattern (missing ']')", "invalid capture index", "unfinished capture", "invalid pattern capture", "too many captures", "missing '[' after '%%f' in pattern".

Table Library (stdlib/table.rs)

FunctionNotes
table.concatConcatenate array elements
table.insertInsert element at position
table.maxnMaximum positive numeric key
table.removeRemove element at position
table.sortIn-place sort
table.foreachDeprecated: iterate table (use pairs)
table.foreachiDeprecated: iterate array (use ipairs)
table.getnDeprecated: table length (use # operator)
table.setnDeprecated: raises error in 5.1.1

Table Library Behavioral Notes

table.concat(list [, sep [, i [, j]]]) — sep defaults to "", i defaults to 1, j defaults to #list. Each element must be a string or number (error: "table contains non-strings"). Uses raw access. Returns empty string if i > j.

table.insert(list, [pos,] value) — 2 args appends at end. 3 args inserts at pos, shifting elements up. Error: "wrong number of arguments to 'insert'" for other counts.

table.maxn(list) — scans ALL keys (both parts) via next(). Returns the largest positive numeric key (including non-integer keys like 1.5). Returns 0 if no positive numeric keys exist.

table.remove(list [, pos]) — pos defaults to #list (remove from end). Shifts elements down, sets last element to nil. Returns the removed element, or nothing if the table was empty.

table.sort(list [, comp]) — Quicksort with median-of-three pivot. Tail recursion on the larger partition. Default comparison uses < (invokes __lt metamethods). Error: "invalid order function for sorting" if the comparison is inconsistent (e.g., NaN values break strict weak ordering). Not stable.

table.setn(table, n) — error: "'setn' is obsolete".

Math Library (stdlib/math.rs)

FunctionNotes
math.absAbsolute value
math.acosArc cosine
math.asinArc sine
math.atanArc tangent
math.atan2Two-argument arc tangent
math.ceilCeiling
math.cosCosine
math.coshHyperbolic cosine
math.degRadians to degrees
math.expExponential
math.floorFloor
math.fmodFloat modulo
math.frexpDecompose float
math.hugeInfinity constant
math.ldexpScale by power of 2
math.logNatural logarithm
math.log10Base-10 logarithm
math.maxMaximum
math.minMinimum
math.modDeprecated alias for fmod (enabled by default via LUA_COMPAT_MOD)
math.modfInteger and fractional parts
math.piPi constant
math.powPower
math.radDegrees to radians
math.randomRandom number
math.randomseedSet random seed
math.sinSine
math.sinhHyperbolic sine
math.sqrtSquare root
math.tanTangent
math.tanhHyperbolic tangent

Math Library Behavioral Notes

All single-argument functions use f64 methods from Rust’s standard library. Each takes one number argument and returns one number.

math.random([m [, n]]) — 0 args: float in [0, 1). 1 arg: integer in [1, m]. 2 args: integer in [m, n]. Error: "interval is empty" if the range is invalid. Uses C rand() equivalent (deterministic for a given seed).

math.randomseed(x) — seeds the random generator. Argument must be convertible to integer.

math.min(...) / math.max(...) — requires at least 1 argument. NaN asymmetry: if NaN is the first argument, it is returned. If NaN appears later, it is skipped (since NaN < x and NaN > x are both false).

math.frexp(x) — returns 2 values: mantissa m and integer exponent e where x = m * 2^e and 0.5 <= |m| < 1.

math.modf(x) — returns 2 values: integer part and fractional part.

math.log(x) — natural logarithm only (no base parameter in 5.1). Base-10 is math.log10.

Lua % vs math.fmod: the Lua % operator uses a - floor(a/b)*b (result has same sign as b), while math.fmod uses C fmod (result has same sign as a). Example: -1 % 5 is 4 in Lua but math.fmod(-1, 5) is -1.

I/O Library (stdlib/io.rs)

FunctionNotes
io.closeClose file
io.flushFlush output
io.inputSet/get default input
io.linesLine iterator
io.openOpen file
io.outputSet/get default output
io.popenOpen process (platform-dependent)
io.readRead from default input
io.tmpfileCreate temporary file
io.typeCheck file handle type
io.writeWrite to default output
File methods:close, :flush, :lines, :read, :seek, :setvbuf, :write
io.stdinStandard input file handle
io.stdoutStandard output file handle
io.stderrStandard error file handle

OS Library (stdlib/os.rs)

FunctionNotes
os.clockCPU time
os.dateDate formatting
os.difftimeTime difference
os.executeRun shell command
os.exitExit process
os.getenvEnvironment variable
os.removeDelete file
os.renameRename file
os.setlocaleSet locale
os.timeCurrent time
os.tmpnameTemporary file name

Debug Library (stdlib/debug.rs)

FunctionNotes
debug.debugInteractive debug prompt
debug.getfenvGet environment
debug.gethookGet hook function
debug.getinfoFunction information
debug.getlocalLocal variable value
debug.getmetatableRaw metatable
debug.getregistryRegistry table
debug.getupvalueUpvalue value
debug.setfenvSet environment
debug.sethookSet hook function
debug.setlocalSet local variable
debug.setmetatableSet metatable
debug.setupvalueSet upvalue
debug.tracebackStack traceback

Package Library (stdlib/package.rs)

Function/FieldNotes
requireModule loader (registered as global)
moduleCreate module (registered as global)
package.configDirectory/path separator configuration string
package.cpathC module search path
package.loadedCache of loaded modules
package.loadersOrdered list of module searchers
package.loadlibLoad native module (see Native Module Loading)
package.pathLua module search path
package.preloadPre-registered module loaders
package.seeallSet module environment to globals

Native Module Loading

PUC-Rio Lua’s package.loadlib loads C modules via lua_CFunction (int (*)(lua_State *)). rilua cannot load PUC-Rio C modules because:

  • Rust has no stable ABI. The internal types (LuaState, Val) change layout between compiler versions.
  • rilua’s function signature (fn(&mut LuaState) -> LuaResult<u32>) differs from PUC-Rio’s extern "C" fn(*mut lua_State) -> c_int.
  • Building a C API compatibility shim (lua.h-compatible) would require reimplementing the entire PUC-Rio stack API (~120 functions) with extern "C" wrappers, plus maintaining ABI stability guarantees that Rust does not provide.

Instead, rilua defines its own native module ABI. Modules are Rust cdylib crates compiled against the same rilua version and rustc version as the host. This is gated behind the dynmod Cargo feature (default off). Without the feature, package.loadlib returns (nil, msg, "absent").

When dynmod is enabled:

  • package.loadlib(path, funcname) loads a shared library, validates a RILUA_MODULE_INFO descriptor (magic bytes, version, struct sizes), and looks up the named entry point.
  • The C module loaders (package.loaders[3] and [4]) search package.cpath for modules named rilua_open_<modname>.
  • Library handles are stored as userdata with a __gc metamethod that calls dlclose/FreeLibrary on collection.

See src/dynmod.rs for the ABI contract and examples/native_module/ for a working example.

Loading

Libraries are loaded via Lua::new() (all standard libraries) or selectively via Lua::new_with(StdLib).

Mirrored at examples/selective_stdlib.rs.

use rilua::{Lua, StdLib};

fn main() -> rilua::LuaResult<()> {
    let mut lua = Lua::new_with(
        StdLib::BASE | StdLib::STRING | StdLib::TABLE | StdLib::MATH,
    )?;
    // io, os, debug, package omitted (sandboxed)
    lua.exec(r#"print(string.upper("ok"))"#)?;
    Ok(())
}

Error Message Formats

All luaL_error messages are prefixed by source location ("source:line: " or empty string).

Argument errors: "bad argument #N to 'funcname' (message)". For methods, narg is decremented by 1 (implicit self). If narg becomes 0: "calling 'name' on bad self (message)".

Type errors: "bad argument #N to 'funcname' (expected expected, got actual)".

Key format constants:

ConstantValue
LUA_MAXCAPTURES32
LUA_NUMBER_FMT"%.14g"

Implementation Priority

  1. Base library (with coroutine) — required for any Lua program
  2. String library — heavily used, pattern matching is complex
  3. Table library — common operations
  4. Math library — straightforward wrappers around f64 methods
  5. I/O library — file operations
  6. OS library — system operations
  7. Package library — module system
  8. Debug library — introspection, lowest priority