Skip to main content

lua_stdlib/
init.rs

1//! Initialization of standard libraries for Lua.
2//!
3//! Opens all standard libraries via `require`-style loading and registers
4//! them into the global table.
5//!
6//! Port of `src/linit.c` (66 lines, 1 function).
7
8use crate::state_stub::{LuaState, LuaStateStubExt as _, lua_CFunction, upvalue_index, CompareOp, LuaDebug};
9use lua_types::error::LuaError;
10
11// C: lua_CFunction — fn pointer type for Lua-callable C functions.
12// Matches types.tsv: lua_CFunction → fn(&mut LuaState) -> Result<usize, LuaError>
13type LuaCFunction = fn(&mut LuaState) -> Result<usize, LuaError>;
14
15// ── Library-name byte-string constants ────────────────────────────────────
16//
17// These replace the C macros from lualib.h and lauxlib.h:
18//   LUA_GNAME        = "_G"         (lauxlib.h)
19//   LUA_LOADLIBNAME  = "package"    (lualib.h)
20//   LUA_COLIBNAME    = "coroutine"  (lualib.h)
21//   LUA_TABLIBNAME   = "table"      (lualib.h)
22//   LUA_IOLIBNAME    = "io"         (lualib.h)
23//   LUA_OSLIBNAME    = "os"         (lualib.h)
24//   LUA_STRLIBNAME   = "string"     (lualib.h)
25//   LUA_MATHLIBNAME  = "math"       (lualib.h)
26//   LUA_UTF8LIBNAME  = "utf8"       (lualib.h)
27//   LUA_DBLIBNAME    = "debug"      (lualib.h)
28//
29// Per PORTING.md §3.1 all Lua string data uses &[u8], not &str.
30
31// C: static const luaL_Reg loadedlibs[] = {
32//   {LUA_GNAME, luaopen_base},
33//   {LUA_LOADLIBNAME, luaopen_package},
34//   {LUA_COLIBNAME, luaopen_coroutine},
35//   {LUA_TABLIBNAME, luaopen_table},
36//   {LUA_IOLIBNAME, luaopen_io},
37//   {LUA_OSLIBNAME, luaopen_os},
38//   {LUA_STRLIBNAME, luaopen_string},
39//   {LUA_MATHLIBNAME, luaopen_math},
40//   {LUA_UTF8LIBNAME, luaopen_utf8},
41//   {LUA_DBLIBNAME, luaopen_debug},
42//   {NULL, NULL}
43// };
44//
45// PORT NOTE: C sentinel `{NULL, NULL}` dropped — Rust slices carry their
46//   own length, so no terminator is needed.
47//
48// PORT NOTE: Per PORTING.md §7, `luaopen_X` → `open` inside the module
49//   (e.g. `crate::base::open`, `crate::string_lib::open`).  As of Phase A
50//   the individual stdlib modules exported inconsistent names:
51//     base.rs        → `pub fn open`          (canonical; matches here)
52//     string_lib.rs  → `pub fn luaopen_string` (needs rename in Phase B)
53//     table_lib.rs   → `pub fn open_table`    (needs rename in Phase B)
54//     math_lib.rs    → `pub fn luaopen_math`  (needs rename in Phase B)
55//     io_lib.rs      → `pub fn luaopen_io`    (needs rename in Phase B)
56//     os_lib.rs      → `pub fn open_os`       (needs rename in Phase B)
57//     utf8_lib, debug_lib, coro_lib, loadlib  → not yet ported (Phase B)
58//   Phase B should rename every stdlib opener to `pub fn open` and update
59//   this table accordingly.
60static LOADED_LIBS: &[(&[u8], LuaCFunction)] = &[
61    (b"_G",         crate::base::open),
62    (b"package",    crate::loadlib::luaopen_package),
63    (b"coroutine",  crate::coro_lib::open_coroutine),
64    (b"table",      crate::table_lib::open_table),
65    (b"io",         crate::io_lib::luaopen_io),
66    (b"os",         crate::os_lib::open_os),
67    (b"string",     crate::string_lib::luaopen_string),
68    (b"math",       crate::math_lib::luaopen_math),
69    (b"utf8",       crate::utf8_lib::open_utf8),
70    (b"debug",      crate::debug_lib::open_debug),
71];
72
73// C: LUALIB_API void luaL_openlibs (lua_State *L) {
74//   const luaL_Reg *lib;
75//   /* "require" functions from 'loadedlibs' and set results to global table */
76//   for (lib = loadedlibs; lib->func; lib++) {
77//     luaL_requiref(L, lib->name, lib->func, 1);
78//     lua_pop(L, 1);  /* remove lib */
79//   }
80// }
81//
82// PORT NOTE: `LUALIB_API` → `pub` (PORTING.md §4.1 / macros.tsv).
83//   `luaL_requiref(L, name, func, 1)` → `state.require_lib(name, func, true)?`
84//   The final `1` argument means "set global" — the loaded module value is
85//   assigned to the global table under `name` and the value left on the
86//   stack is then discarded by `lua_pop(L, 1)`.
87//   `lua_pop(L, 1)` → `state.pop_n(1)` (macros.tsv).
88/// Open all standard Lua libraries into `state`, registering each into the
89/// global table.
90///
91/// Corresponds to `luaL_openlibs` in `linit.c`.
92pub fn open_libs(state: &mut LuaState) -> Result<(), LuaError> {
93    for &(name, func) in LOADED_LIBS {
94        // C: luaL_requiref(L, lib->name, lib->func, 1);
95        state.require_lib(name, func, true)?;
96        // C: lua_pop(L, 1);  /* remove lib */
97        state.pop_n(1);
98    }
99    Ok(())
100}
101
102// ──────────────────────────────────────────────────────────────────────────
103// PORT STATUS
104//   source:        src/linit.c  (66 lines, 1 function)
105//   target_crate:  lua-stdlib
106//   confidence:    high
107//   todos:         1
108//   port_notes:    3
109//   unsafe_blocks: 0
110//   notes:         Trivial file. Cross-crate refs (state.require_lib,
111//                  state.pop_n, crate::*::open) resolve in Phase B.
112//                  Phase B must also reconcile inconsistent open-function
113//                  names in the existing stdlib modules (see PORT NOTEs).
114// ──────────────────────────────────────────────────────────────────────────