low-luajit 0.4.0

Low level but safe bindings to the LuaJIT C API with no dependencies and no-std support to create Lua modules using Rust.
Documentation
//! 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 {
//!     // ...
//! # AmountReturned::NONE
//! }
//!
//! extern "C-unwind" fn bar(lua: LuaState) -> AmountReturned {
//!     // ...
//! # AmountReturned::NONE
//! }
//!
//! #[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`:
//!
//! ```toml
//! [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!
//!
//! ```lua
//! 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:
//!
//! ```lua
//! 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...*
//!
//! [examples directory]: https://git.blossomdevs.com/Rosy.iso/low-luajit/src/branch/main/examples

#![no_std]

pub mod ffi;
mod lua;

/// Internal auxiliary macro for mapping pointers to an `Option`.
macro_rules! map_ptr {
	($ptr:expr, $some:expr) => { if $ptr.is_null() { None } else { Some($some) } };
}

pub(crate) use map_ptr;

/// Auxiliary conversion methods for [`CFunction`] and [`Hook`].
///
/// *([`CFunction`] and [`Hook`] are simple type definitions, so methods can't be implemented directly...)*
pub trait SafeFn {
	/// The raw version of this function type.
	type RawFn;

	/// Converts the given raw function into their safe version.
	///
	/// # Safety
	///
	/// `raw` must always be safe to call.
	unsafe fn from_raw(raw: Self::RawFn) -> Self;

	/// Converts this function into their raw version.
	///
	/// The returned function is safe to call as long as the function receives valid pointers for any pointer argument it may have.
	fn to_raw(self) -> Self::RawFn;
}

pub use lua::*;