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//! C source: `reference/lua-5.4.7/src/linit.c`.
7
8use crate::state_stub::{LuaState, LuaStateStubExt as _};
9use lua_types::error::LuaError;
10
11type LuaCFunction = fn(&mut LuaState) -> Result<usize, LuaError>;
12
13/// Opener function names are inconsistent across stdlib modules: `base`
14/// exports the canonical `open`, while `string_lib`/`table_lib`/`math_lib`/
15/// `io_lib`/`os_lib` still export their original `luaopen_*`/`open_*` names
16/// (as do `utf8_lib`/`debug_lib`/`coro_lib`/`loadlib`). Unifying every
17/// opener to `pub fn open` would let this table be written more uniformly.
18static LOADED_LIBS: &[(&[u8], LuaCFunction)] = &[
19    (b"_G", crate::base::open),
20    #[cfg(feature = "package")]
21    (b"package", crate::loadlib::luaopen_package),
22    #[cfg(feature = "coroutine")]
23    (b"coroutine", crate::coro_lib::open_coroutine),
24    (b"table", crate::table_lib::open_table),
25    #[cfg(feature = "io")]
26    (b"io", crate::io_lib::luaopen_io),
27    #[cfg(feature = "os")]
28    (b"os", crate::os_lib::open_os),
29    (b"string", crate::string_lib::luaopen_string),
30    (b"math", crate::math_lib::luaopen_math),
31    #[cfg(feature = "utf8")]
32    (b"utf8", crate::utf8_lib::open_utf8),
33    #[cfg(feature = "debug")]
34    (b"debug", crate::debug_lib::open_debug),
35];
36
37/// Open all standard Lua libraries into `state`, registering each into the
38/// global table.
39///
40/// Corresponds to `luaL_openlibs` in `linit.c`. The `true` argument to
41/// `require_lib` means "set global": the loaded module value is assigned to
42/// the global table under `name`, and the value left on the stack is then
43/// discarded.
44pub fn open_libs(state: &mut LuaState) -> Result<(), LuaError> {
45    // Whether this version ships `utf8` (a 5.3 addition) is the #234 capability
46    // matrix — the reference-backed single source — not a second inline version
47    // check. The `#[cfg(feature = "utf8")]`-gated registration entries in
48    // LOADED_LIBS still control compile-time availability.
49    let has_utf8 = state
50        .global()
51        .lua_version
52        .supports(lua_types::Feature::Utf8Lib);
53    for &(name, func) in LOADED_LIBS {
54        if name == b"utf8".as_slice() && !has_utf8 {
55            continue;
56        }
57        state.require_lib(name, func, true)?;
58        state.pop_n(1);
59    }
60    // `bit32` is present on 5.2 and 5.3 and removed in 5.4; the version dimension
61    // comes from the #234 matrix, the compile-time dimension from the feature
62    // gate (registration = `cfg(feature) && version.supports(Bit32Lib)`).
63    #[cfg(feature = "bit32")]
64    if state
65        .global()
66        .lua_version
67        .supports(lua_types::Feature::Bit32Lib)
68    {
69        state.require_lib(b"bit32", crate::bit32_lib::open_bit32, true)?;
70        state.pop_n(1);
71    }
72    Ok(())
73}