Skip to main content

Crate low_luajit

Crate low_luajit 

Source
Expand description

A lightweight library that aims to add low level but safe (as much as possible) bindings to the LuaJIT C API with no dependencies and no-std support.

These bindings can be used to create dynamic Rust libraries that can be loaded and ran from LuaJIT like any other Lua module.

Check out the examples directory for some examples.

§Tutorial

(Replace instances of crate_name with the name of your crate!)

To create your module’s entry point, add a special function named luaopen_crate_name:

use low_luajit::{LuaState, AmountReturned};

#[unsafe(no_mangle)]
extern "C-unwind" fn luaopen_crate_name(mut lua: LuaState) -> AmountReturned {
    // ...
    return lua.return_any(1); // Can be 0, but anything higher than 1 will be discarded.
}

This is the function that will be called when Lua loads your module. It can return a value back to Lua which will be cached like any other module.

While you can choose to return any value (including none), modules usually return a table of various functions your module can do. low_luajit has some functions to ease this process:

use low_luajit::{LuaState, AmountReturned, reg};

extern "C-unwind" fn foo(lua: LuaState) -> AmountReturned {
    // ...
}

extern "C-unwind" fn bar(lua: LuaState) -> AmountReturned {
    // ...
}

#[unsafe(no_mangle)]
extern "C-unwind" fn luaopen_crate_name(lua: LuaState) -> AmountReturned {
    lua.return_module(reg![foo, bar])
}

This above code will have your module be returned as a table containing the functions foo and bar, that Lua can call directly!

Once your module is ready to be compiled, make sure to configure your crate to be of type cdylib:

[package]
name = "crate_name"
# ...

[lib]
crate-type = ["cdylib"]

[dependencies]
low_luajit = "0.1"
# ...

And you’re good to go! Move the resulting library file (.dll on Windows, .so on Linux) somewhere in the Lua code and you can now load and use your Rust library as a Lua module!

local crate_name = require("crate_name")

crate_name.foo()
crate_name.bar()

To check out how you can interact with the LuaJIT API further to continue implementing your module, see LuaState.

For some example modules to use as reference, check out the examples directory.

§Linux addendum

When compiling dynamic libraries on Linux, Cargo adds a lib prefix to the outputted file (libcrate_name.so), which trips Lua’s default path solver.

To resolve this, you can either modify the package.cpath variable:

package.cpath = "./lib?.so;" .. package.cpath

Or simply manually rename the file to crate_name.so.

§Windows addendum

Windows is, for whatever reason, more strict on dynamic libraries, requiring symbols to be bound to a specific .dll name.

The LuaJIT docs account for this:

Since Windows symbols are bound to a specific DLL name, you need to link to the lua51.dll created by the LuaJIT build (do not rename the DLL). You may link LuaJIT statically on Windows only if you don’t intend to load Lua/C modules at runtime.

Following this, when compiling on Windows the symbols are binded to lua51.dll, which should work for any program that is compliant with the LuaJIT docs and intends to allow loading external modules at runtime.

§Error handling

When Lua errors, the error is propagated upwards using a long jump, unwinding through any Rust or Lua code until it’s caught by the protected environment (where it will be handled by whoever created said environment).

(You can create protected environments using LuaState::pcall or LuaState::cpcall.)

If a long jump happens, any running Rust function will be left unfinished (any variable left will not be dropped), but it shouldn’t cause any undefined behavior.

When Lua errors outside of a protected environment, Rust should be able to catch the error and abort (though Lua programs normally always run within a protected environment).

Rust panics behave mostly as usual, just often failing to fully unwind and thus aborting instead, which should be harmless.

Functions that may trigger Lua errors will clarify the error conditions in their description. (Except unlikely but possible stack/table overflows, just assume that any function that adds more elements without removing some can overflow if called many many times.)

If a function may trigger a Lua error in an undocumented way, let me know and I’ll add the missing docs!

§Planned features

The main objective is a wrapper for the LuaJIT C API that tries to strike a good (but subjective) balance between lightweight and safe. Some C functions/types still need to be safely exposed currently.

Following that, some slightly higher level utilities to ease some important yet repetitive tasks could be added, but they would still have to directly interact with the LuaJIT C API, with little overhead; a few ideas could be:

  • Simple iterator structs that just call the functions needed to properly iterate a table for you.
  • Potentially a safe way to use this library to just run LuaJIT within Rust instead (currently only possible via ffi)?
  • Safe versions of the functions that can panic (or alternatively a safe wrapper around any function/closure)?

If you’d like to create high level bindings instead, feel free to use this library as your base/dependency! Just follow the license…

Modules§

ffi
The raw (and unsafe) LuaJIT C API.

Macros§

reg
Generates a list of named functions (&[Reg]) to be used in module creation.

Structs§

AmountReturned
Simple wrapper that tells Lua how many values a CFunction is intending to return.
DebugInfo
Activation record related to a specified active function.
LuaState
Container of the state of a Lua interpreter and entry point to the LuaJIT C API.
Reg
Safe wrapper for luaL_Reg, used in module creation.

Enums§

HookEvent
All possible event types that can call the current Hook.
LoadError
All error codes that may be returned when failing to load a chunk.
LuaType
Possible types for Lua values.
PCallError
All error codes that a function may return when erroring while called in protected mode.

Traits§

SafeFn
Auxiliary conversion methods for CFunction and Hook.
Writer
Trait for all closures and functions that can be used with LuaState::dump.

Type Aliases§

CFunction
A safe function using the C ABI that Lua can call.
Hook
Debugging function that is called by specified HookEvents.