mirror of
https://github.com/mlua-rs/mlua
synced 2026-06-08 16:05:43 +00:00
Compare commits
62 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 31efd0cf72 | |||
| 6b79e4cd76 | |||
| ee2da72685 | |||
| 6180a528a7 | |||
| 69ef08d4d2 | |||
| f7f04d5180 | |||
| e10623d658 | |||
| c3ab89ba66 | |||
| fa500639f0 | |||
| 3d2574a855 | |||
| 003935db47 | |||
| fbed171f90 | |||
| 298d48f708 | |||
| 4ff677f5fc | |||
| 5b920321dd | |||
| 6bb99783e9 | |||
| 547f82acc1 | |||
| 9ea98e3f1e | |||
| 0ad03bee98 | |||
| ba7c331984 | |||
| 53dea3166a | |||
| 129dec43ed | |||
| a7f58e57ec | |||
| e6871525c4 | |||
| c4956dbf49 | |||
| d0ea428e23 | |||
| 3e87d3ea9b | |||
| 0f8bde4b4e | |||
| b9c9dfbd03 | |||
| 71824297f6 | |||
| c0a8064228 | |||
| 84efb8bf95 | |||
| cf687a6ac6 | |||
| ea85edb242 | |||
| 788175e0d6 | |||
| 90ef25a6ee | |||
| ac72f6acae | |||
| 4444ac4ea3 | |||
| 5f950e30ec | |||
| 311aa5f6e1 | |||
| 739d5f5262 | |||
| 375028e13f | |||
| 46e949c184 | |||
| 62b53e218c | |||
| 0393406b9f | |||
| 272cfdb89b | |||
| 8e244a25ea | |||
| ef8b8e11ec | |||
| 2543414726 | |||
| ee112568d6 | |||
| 69d3ddec29 | |||
| 5b0d811c5a | |||
| 19536db976 | |||
| fc69551f87 | |||
| a68b0b6905 | |||
| 1ec1cc9922 | |||
| fd68b033f0 | |||
| c3817409a8 | |||
| 863d8092d6 | |||
| 24b6ff3c20 | |||
| bc36261f5c | |||
| bcb9a4d220 |
@@ -129,8 +129,8 @@ jobs:
|
||||
- name: Run compile tests (macos lua54)
|
||||
if: ${{ matrix.os == 'macos-latest' && matrix.lua == 'lua54' }}
|
||||
run: |
|
||||
TRYBUILD=overwrite cargo test --features "${{ matrix.lua }},vendored" -- --ignored
|
||||
TRYBUILD=overwrite cargo test --features "${{ matrix.lua }},vendored,async,send,serialize,macros" -- --ignored
|
||||
TRYBUILD=overwrite cargo test --features "${{ matrix.lua }},vendored" --tests -- --ignored
|
||||
TRYBUILD=overwrite cargo test --features "${{ matrix.lua }},vendored,async,send,serialize,macros" --tests -- --ignored
|
||||
shell: bash
|
||||
|
||||
test_with_sanitizer:
|
||||
@@ -194,7 +194,7 @@ jobs:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
rust: [stable]
|
||||
lua: [lua54, lua53, lua52, lua51, luajit]
|
||||
lua: [lua54, lua53, lua52, lua51, luajit, luau]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
target: x86_64-unknown-linux-gnu
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
name: Typos Check
|
||||
on:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
run:
|
||||
name: Spell Check with Typos
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Actions Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Check spelling
|
||||
uses: crate-ci/typos@master
|
||||
with:
|
||||
config: ./typos.toml
|
||||
+6
-13
@@ -1,20 +1,13 @@
|
||||
## v0.11.0-beta.1 (May 7th, 2025)
|
||||
## v0.10.5 (May 24th, 2025)
|
||||
|
||||
- New "require-by-string" for Luau (with `Require` trait and async support)
|
||||
- Added `Thread::resume_error` support for Luau
|
||||
- 52 bit integers support for Luau (this is a breaking change)
|
||||
- New features for Luau compiler (constants, disabled builtins, known members)
|
||||
- `AsyncThread<A, R>` changed to `AsyncThread<R>` (`A` pushed to stack immediately)
|
||||
- Lifetime `'a` moved from `AsChunk<'a>` to `AsChunk::source where Self: 'a`
|
||||
- `Lua::scope` pass `&Scope` instead of `&mut Scope` to closure
|
||||
- Added global hooks support (Lua 5.1+)
|
||||
- Added per-thread hooks support (Lua 5.1+)
|
||||
- `Lua::init_from_ptr` renamed to `Lua::get_or_init_from_ptr` and returns `&Lua`
|
||||
- `Lua:load_from_function` is deprecated (this is `register_module` now)
|
||||
- Added `Lua::register_module` and `Lua::preload_module`
|
||||
- mlua-sys is back to 0.6.x (Luau 0.663)
|
||||
- Reverted: Trigger abort when Luau userdata destructors are panic (requires new mlua-sys)
|
||||
- Reverted: Added large (52bit) integers support for Luau (breaking change)
|
||||
|
||||
## v0.10.4 (May 5th, 2025)
|
||||
|
||||
_yanked_ because of semver-breaking changes
|
||||
|
||||
- Luau updated to 0.672
|
||||
- New serde option `encode_empty_tables_as_array` to serialize empty tables as arrays
|
||||
- Added `WeakLua` and `Lua::weak()` to create weak references to Lua state
|
||||
|
||||
+8
-5
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mlua"
|
||||
version = "0.11.0-beta.1" # remember to update mlua_derive
|
||||
version = "0.10.5" # remember to update mlua_derive
|
||||
authors = ["Aleksandr Orlenko <zxteam@pm.me>", "kyren <catherine@kyju.org>"]
|
||||
rust-version = "1.79.0"
|
||||
edition = "2021"
|
||||
@@ -32,11 +32,11 @@ lua52 = ["ffi/lua52"]
|
||||
lua51 = ["ffi/lua51"]
|
||||
luajit = ["ffi/luajit"]
|
||||
luajit52 = ["luajit", "ffi/luajit52"]
|
||||
luau = ["ffi/luau"]
|
||||
luau = ["ffi/luau", "dep:libloading"]
|
||||
luau-jit = ["luau", "ffi/luau-codegen"]
|
||||
luau-vector4 = ["luau", "ffi/luau-vector4"]
|
||||
vendored = ["ffi/vendored"]
|
||||
module = ["dep:mlua_derive", "ffi/module"]
|
||||
module = ["mlua_derive", "ffi/module"]
|
||||
async = ["dep:futures-util"]
|
||||
send = ["parking_lot/send_guard", "error-send"]
|
||||
error-send = []
|
||||
@@ -46,7 +46,7 @@ anyhow = ["dep:anyhow", "error-send"]
|
||||
userdata-wrappers = []
|
||||
|
||||
[dependencies]
|
||||
mlua_derive = { version = "=0.11.0-beta.1", optional = true, path = "mlua_derive" }
|
||||
mlua_derive = { version = "=0.10.1", optional = true, path = "mlua_derive" }
|
||||
bstr = { version = "1.0", features = ["std"], default-features = false }
|
||||
either = "1.0"
|
||||
num-traits = { version = "0.2.14" }
|
||||
@@ -59,7 +59,10 @@ parking_lot = { version = "0.12", features = ["arc_lock"] }
|
||||
anyhow = { version = "1.0", optional = true }
|
||||
rustversion = "1.0"
|
||||
|
||||
ffi = { package = "mlua-sys", version = "0.7.0", path = "mlua-sys" }
|
||||
ffi = { package = "mlua-sys", version = "0.6.8", path = "mlua-sys" }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
libloading = { version = "0.8", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
trybuild = "1.0"
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
[Benchmarks]: https://github.com/khvzak/script-bench-rs
|
||||
[FAQ]: FAQ.md
|
||||
|
||||
# The main branch is the development version of `mlua`. Please see the [v0.10](https://github.com/mlua-rs/mlua/tree/v0.10) branch for the stable versions of `mlua`.
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> See v0.10 [release notes](https://github.com/mlua-rs/mlua/blob/main/docs/release_notes/v0.10.md).
|
||||
|
||||
+4
-4
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mlua-sys"
|
||||
version = "0.7.0"
|
||||
version = "0.6.8"
|
||||
authors = ["Aleksandr Orlenko <zxteam@pm.me>"]
|
||||
rust-version = "1.71"
|
||||
edition = "2021"
|
||||
@@ -38,9 +38,9 @@ module = []
|
||||
cc = "1.0"
|
||||
cfg-if = "1.0"
|
||||
pkg-config = "0.3.17"
|
||||
lua-src = { version = ">= 547.1.0, < 547.2.0", optional = true }
|
||||
luajit-src = { version = ">= 210.6.0, < 210.7.0", optional = true }
|
||||
luau0-src = { version = "0.14.2", optional = true }
|
||||
lua-src = { version = ">= 547.0.0, < 547.1.0", optional = true }
|
||||
luajit-src = { version = ">= 210.5.0, < 210.6.0", optional = true }
|
||||
luau0-src = { version = "0.12.0", optional = true }
|
||||
|
||||
[lints.rust]
|
||||
unexpected_cfgs = { level = "allow", check-cfg = ['cfg(raw_dylib)'] }
|
||||
|
||||
+1
-2
@@ -1,8 +1,7 @@
|
||||
//! Low level bindings to Lua 5.4/5.3/5.2/5.1 (including LuaJIT) and Luau.
|
||||
|
||||
#![allow(non_camel_case_types, non_snake_case)]
|
||||
#![allow(non_camel_case_types, non_snake_case, dead_code)]
|
||||
#![allow(clippy::missing_safety_doc)]
|
||||
#![allow(unsafe_op_in_unsafe_fn)]
|
||||
#![doc(test(attr(deny(warnings))))]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ unsafe fn compat53_findfield(L: *mut lua_State, objidx: c_int, level: c_int) ->
|
||||
} else if compat53_findfield(L, objidx, level - 1) != 0 {
|
||||
// try recursively
|
||||
lua_remove(L, -2); // remove table (but keep name)
|
||||
lua_pushliteral(L, c".");
|
||||
lua_pushliteral(L, ".");
|
||||
lua_insert(L, -2); // place '.' between the two names
|
||||
lua_concat(L, 3);
|
||||
return 1;
|
||||
@@ -121,13 +121,13 @@ unsafe fn compat53_pushfuncname(L: *mut lua_State, ar: *mut lua_Debug) {
|
||||
lua_pushfstring(L, cstr!("function '%s'"), (*ar).name);
|
||||
} else if *(*ar).what == b'm' as c_char {
|
||||
// main?
|
||||
lua_pushliteral(L, c"main chunk");
|
||||
lua_pushliteral(L, "main chunk");
|
||||
} else if *(*ar).what == b'C' as c_char {
|
||||
if compat53_pushglobalfuncname(L, ar) != 0 {
|
||||
lua_pushfstring(L, cstr!("function '%s'"), lua_tostring(L, -1));
|
||||
lua_remove(L, -2); // remove name
|
||||
} else {
|
||||
lua_pushliteral(L, c"?");
|
||||
lua_pushliteral(L, "?");
|
||||
}
|
||||
} else {
|
||||
lua_pushfstring(
|
||||
@@ -377,7 +377,7 @@ pub unsafe fn luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char)
|
||||
if !msg.is_null() {
|
||||
luaL_error(L, cstr!("stack overflow (%s)"), msg);
|
||||
} else {
|
||||
lua_pushliteral(L, c"stack overflow");
|
||||
lua_pushliteral(L, "stack overflow");
|
||||
lua_error(L);
|
||||
}
|
||||
}
|
||||
@@ -467,12 +467,12 @@ pub unsafe fn luaL_traceback(L: *mut lua_State, L1: *mut lua_State, msg: *const
|
||||
if !msg.is_null() {
|
||||
lua_pushfstring(L, cstr!("%s\n"), msg);
|
||||
}
|
||||
lua_pushliteral(L, c"stack traceback:");
|
||||
lua_pushliteral(L, "stack traceback:");
|
||||
while lua_getstack(L1, level, &mut ar) != 0 {
|
||||
level += 1;
|
||||
if level == mark {
|
||||
// too many levels?
|
||||
lua_pushliteral(L, c"\n\t..."); // add a '...'
|
||||
lua_pushliteral(L, "\n\t..."); // add a '...'
|
||||
level = numlevels - COMPAT53_LEVELS2; // and skip to last ones
|
||||
} else {
|
||||
lua_getinfo(L1, cstr!("Slnt"), &mut ar);
|
||||
@@ -480,7 +480,7 @@ pub unsafe fn luaL_traceback(L: *mut lua_State, L1: *mut lua_State, msg: *const
|
||||
if ar.currentline > 0 {
|
||||
lua_pushfstring(L, cstr!("%d:"), ar.currentline);
|
||||
}
|
||||
lua_pushliteral(L, c" in ");
|
||||
lua_pushliteral(L, " in ");
|
||||
compat53_pushfuncname(L, &mut ar);
|
||||
lua_concat(L, lua_gettop(L) - top);
|
||||
}
|
||||
@@ -493,16 +493,16 @@ pub unsafe fn luaL_tolstring(L: *mut lua_State, mut idx: c_int, len: *mut usize)
|
||||
if luaL_callmeta(L, idx, cstr!("__tostring")) == 0 {
|
||||
match lua_type(L, idx) {
|
||||
LUA_TNIL => {
|
||||
lua_pushliteral(L, c"nil");
|
||||
lua_pushliteral(L, "nil");
|
||||
}
|
||||
LUA_TSTRING | LUA_TNUMBER => {
|
||||
lua_pushvalue(L, idx);
|
||||
}
|
||||
LUA_TBOOLEAN => {
|
||||
if lua_toboolean(L, idx) == 0 {
|
||||
lua_pushliteral(L, c"false");
|
||||
lua_pushliteral(L, "false");
|
||||
} else {
|
||||
lua_pushliteral(L, c"true");
|
||||
lua_pushliteral(L, "true");
|
||||
}
|
||||
}
|
||||
t => {
|
||||
|
||||
@@ -18,7 +18,7 @@ pub struct luaL_Reg {
|
||||
}
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua51", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn luaL_register(L: *mut lua_State, libname: *const c_char, l: *const luaL_Reg);
|
||||
#[link_name = "luaL_getmetafield"]
|
||||
pub fn luaL_getmetafield_(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int;
|
||||
@@ -61,7 +61,7 @@ pub const LUA_NOREF: c_int = -2;
|
||||
pub const LUA_REFNIL: c_int = -1;
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua51", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn luaL_ref(L: *mut lua_State, t: c_int) -> c_int;
|
||||
pub fn luaL_unref(L: *mut lua_State, t: c_int, r#ref: c_int);
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
//! Contains definitions from `lua.h`.
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::marker::{PhantomData, PhantomPinned};
|
||||
use std::os::raw::{c_char, c_double, c_int, c_void};
|
||||
use std::ptr;
|
||||
@@ -84,13 +83,13 @@ pub type lua_Reader =
|
||||
pub type lua_Writer =
|
||||
unsafe extern "C-unwind" fn(L: *mut lua_State, p: *const c_void, sz: usize, ud: *mut c_void) -> c_int;
|
||||
|
||||
/// Type for memory-allocation functions (no unwinding)
|
||||
/// Type for memory-allocation functions
|
||||
#[rustfmt::skip]
|
||||
pub type lua_Alloc =
|
||||
unsafe extern "C" fn(ud: *mut c_void, ptr: *mut c_void, osize: usize, nsize: usize) -> *mut c_void;
|
||||
unsafe extern "C-unwind" fn(ud: *mut c_void, ptr: *mut c_void, osize: usize, nsize: usize) -> *mut c_void;
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua51", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
//
|
||||
// State manipulation
|
||||
//
|
||||
@@ -220,7 +219,7 @@ pub const LUA_GCSETPAUSE: c_int = 6;
|
||||
pub const LUA_GCSETSTEPMUL: c_int = 7;
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua51", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn lua_gc(L: *mut lua_State, what: c_int, data: c_int) -> c_int;
|
||||
}
|
||||
|
||||
@@ -228,7 +227,7 @@ unsafe extern "C-unwind" {
|
||||
// Miscellaneous functions
|
||||
//
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua51", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
#[link_name = "lua_error"]
|
||||
fn lua_error_(L: *mut lua_State) -> c_int;
|
||||
pub fn lua_next(L: *mut lua_State, idx: c_int) -> c_int;
|
||||
@@ -313,8 +312,10 @@ pub unsafe fn lua_isnoneornil(L: *mut lua_State, n: c_int) -> c_int {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushliteral(L: *mut lua_State, s: &'static CStr) {
|
||||
lua_pushstring_(L, s.as_ptr());
|
||||
pub unsafe fn lua_pushliteral(L: *mut lua_State, s: &'static str) {
|
||||
use std::ffi::CString;
|
||||
let c_str = CString::new(s).unwrap();
|
||||
lua_pushlstring_(L, c_str.as_ptr(), c_str.as_bytes().len())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@@ -370,7 +371,7 @@ pub const LUA_MASKCOUNT: c_int = 1 << (LUA_HOOKCOUNT as usize);
|
||||
pub type lua_Hook = unsafe extern "C-unwind" fn(L: *mut lua_State, ar: *mut lua_Debug);
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua51", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn lua_getstack(L: *mut lua_State, level: c_int, ar: *mut lua_Debug) -> c_int;
|
||||
pub fn lua_getinfo(L: *mut lua_State, what: *const c_char, ar: *mut lua_Debug) -> c_int;
|
||||
pub fn lua_getlocal(L: *mut lua_State, ar: *const lua_Debug, n: c_int) -> *const c_char;
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
//! Contains definitions from `lualib.h`.
|
||||
|
||||
use std::os::raw::{c_char, c_int};
|
||||
use std::os::raw::c_int;
|
||||
|
||||
use super::lua::lua_State;
|
||||
|
||||
pub const LUA_COLIBNAME: *const c_char = cstr!("coroutine");
|
||||
pub const LUA_TABLIBNAME: *const c_char = cstr!("table");
|
||||
pub const LUA_IOLIBNAME: *const c_char = cstr!("io");
|
||||
pub const LUA_OSLIBNAME: *const c_char = cstr!("os");
|
||||
pub const LUA_STRLIBNAME: *const c_char = cstr!("string");
|
||||
pub const LUA_MATHLIBNAME: *const c_char = cstr!("math");
|
||||
pub const LUA_DBLIBNAME: *const c_char = cstr!("debug");
|
||||
pub const LUA_LOADLIBNAME: *const c_char = cstr!("package");
|
||||
pub const LUA_COLIBNAME: &str = "coroutine";
|
||||
pub const LUA_TABLIBNAME: &str = "table";
|
||||
pub const LUA_IOLIBNAME: &str = "io";
|
||||
pub const LUA_OSLIBNAME: &str = "os";
|
||||
pub const LUA_STRLIBNAME: &str = "string";
|
||||
pub const LUA_MATHLIBNAME: &str = "math";
|
||||
pub const LUA_DBLIBNAME: &str = "debug";
|
||||
pub const LUA_LOADLIBNAME: &str = "package";
|
||||
|
||||
#[cfg(feature = "luajit")]
|
||||
pub const LUA_BITLIBNAME: *const c_char = cstr!("bit");
|
||||
pub const LUA_BITLIBNAME: &str = "bit";
|
||||
#[cfg(feature = "luajit")]
|
||||
pub const LUA_JITLIBNAME: *const c_char = cstr!("jit");
|
||||
pub const LUA_JITLIBNAME: &str = "jit";
|
||||
#[cfg(feature = "luajit")]
|
||||
pub const LUA_FFILIBNAME: *const c_char = cstr!("ffi");
|
||||
pub const LUA_FFILIBNAME: &str = "ffi";
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua51", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn luaopen_base(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_table(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_io(L: *mut lua_State) -> c_int;
|
||||
|
||||
@@ -199,16 +199,16 @@ pub unsafe fn luaL_tolstring(L: *mut lua_State, mut idx: c_int, len: *mut usize)
|
||||
if luaL_callmeta(L, idx, cstr!("__tostring")) == 0 {
|
||||
match lua_type(L, idx) {
|
||||
LUA_TNIL => {
|
||||
lua_pushliteral(L, c"nil");
|
||||
lua_pushliteral(L, "nil");
|
||||
}
|
||||
LUA_TSTRING | LUA_TNUMBER => {
|
||||
lua_pushvalue(L, idx);
|
||||
}
|
||||
LUA_TBOOLEAN => {
|
||||
if lua_toboolean(L, idx) == 0 {
|
||||
lua_pushliteral(L, c"false");
|
||||
lua_pushliteral(L, "false");
|
||||
} else {
|
||||
lua_pushliteral(L, c"true");
|
||||
lua_pushliteral(L, "true");
|
||||
}
|
||||
}
|
||||
t => {
|
||||
|
||||
@@ -21,7 +21,7 @@ pub struct luaL_Reg {
|
||||
}
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua52", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn luaL_checkversion_(L: *mut lua_State, ver: lua_Number);
|
||||
|
||||
#[link_name = "luaL_getmetafield"]
|
||||
@@ -69,7 +69,7 @@ pub const LUA_NOREF: c_int = -2;
|
||||
pub const LUA_REFNIL: c_int = -1;
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua52", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn luaL_ref(L: *mut lua_State, t: c_int) -> c_int;
|
||||
pub fn luaL_unref(L: *mut lua_State, t: c_int, r#ref: c_int);
|
||||
|
||||
@@ -82,7 +82,7 @@ pub unsafe fn luaL_loadfile(L: *mut lua_State, f: *const c_char) -> c_int {
|
||||
}
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua52", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn luaL_loadbufferx(
|
||||
L: *mut lua_State,
|
||||
buff: *const c_char,
|
||||
|
||||
+13
-12
@@ -1,6 +1,5 @@
|
||||
//! Contains definitions from `lua.h`.
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::marker::{PhantomData, PhantomPinned};
|
||||
use std::os::raw::{c_char, c_double, c_int, c_uchar, c_uint, c_void};
|
||||
use std::ptr;
|
||||
@@ -89,13 +88,13 @@ pub type lua_Reader =
|
||||
pub type lua_Writer =
|
||||
unsafe extern "C-unwind" fn(L: *mut lua_State, p: *const c_void, sz: usize, ud: *mut c_void) -> c_int;
|
||||
|
||||
/// Type for memory-allocation functions (no unwinding)
|
||||
/// Type for memory-allocation functions
|
||||
#[rustfmt::skip]
|
||||
pub type lua_Alloc =
|
||||
unsafe extern "C" fn(ud: *mut c_void, ptr: *mut c_void, osize: usize, nsize: usize) -> *mut c_void;
|
||||
unsafe extern "C-unwind" fn(ud: *mut c_void, ptr: *mut c_void, osize: usize, nsize: usize) -> *mut c_void;
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua52", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
//
|
||||
// State manipulation
|
||||
//
|
||||
@@ -161,14 +160,14 @@ pub const LUA_OPLT: c_int = 1;
|
||||
pub const LUA_OPLE: c_int = 2;
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua52", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn lua_arith(L: *mut lua_State, op: c_int);
|
||||
pub fn lua_rawequal(L: *mut lua_State, idx1: c_int, idx2: c_int) -> c_int;
|
||||
pub fn lua_compare(L: *mut lua_State, idx1: c_int, idx2: c_int, op: c_int) -> c_int;
|
||||
}
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua52", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
//
|
||||
// Push functions (C -> stack)
|
||||
//
|
||||
@@ -257,7 +256,7 @@ pub unsafe fn lua_pcall(L: *mut lua_State, n: c_int, r: c_int, f: c_int) -> c_in
|
||||
}
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua52", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
//
|
||||
// Coroutine functions
|
||||
//
|
||||
@@ -289,12 +288,12 @@ pub const LUA_GCGEN: c_int = 10;
|
||||
pub const LUA_GCINC: c_int = 11;
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua52", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn lua_gc(L: *mut lua_State, what: c_int, data: c_int) -> c_int;
|
||||
}
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua52", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
//
|
||||
// Miscellaneous functions
|
||||
//
|
||||
@@ -396,8 +395,10 @@ pub unsafe fn lua_isnoneornil(L: *mut lua_State, n: c_int) -> c_int {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushliteral(L: *mut lua_State, s: &'static CStr) {
|
||||
lua_pushstring(L, s.as_ptr());
|
||||
pub unsafe fn lua_pushliteral(L: *mut lua_State, s: &'static str) -> *const c_char {
|
||||
use std::ffi::CString;
|
||||
let c_str = CString::new(s).unwrap();
|
||||
lua_pushlstring_(L, c_str.as_ptr(), c_str.as_bytes().len())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@@ -448,7 +449,7 @@ pub const LUA_MASKCOUNT: c_int = 1 << (LUA_HOOKCOUNT as usize);
|
||||
pub type lua_Hook = unsafe extern "C-unwind" fn(L: *mut lua_State, ar: *mut lua_Debug);
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua52", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn lua_getstack(L: *mut lua_State, level: c_int, ar: *mut lua_Debug) -> c_int;
|
||||
pub fn lua_getinfo(L: *mut lua_State, what: *const c_char, ar: *mut lua_Debug) -> c_int;
|
||||
pub fn lua_getlocal(L: *mut lua_State, ar: *const lua_Debug, n: c_int) -> *const c_char;
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//! Contains definitions from `lualib.h`.
|
||||
|
||||
use std::os::raw::{c_char, c_int};
|
||||
use std::os::raw::c_int;
|
||||
|
||||
use super::lua::lua_State;
|
||||
|
||||
pub const LUA_COLIBNAME: *const c_char = cstr!("coroutine");
|
||||
pub const LUA_TABLIBNAME: *const c_char = cstr!("table");
|
||||
pub const LUA_IOLIBNAME: *const c_char = cstr!("io");
|
||||
pub const LUA_OSLIBNAME: *const c_char = cstr!("os");
|
||||
pub const LUA_STRLIBNAME: *const c_char = cstr!("string");
|
||||
pub const LUA_BITLIBNAME: *const c_char = cstr!("bit32");
|
||||
pub const LUA_MATHLIBNAME: *const c_char = cstr!("math");
|
||||
pub const LUA_DBLIBNAME: *const c_char = cstr!("debug");
|
||||
pub const LUA_LOADLIBNAME: *const c_char = cstr!("package");
|
||||
pub const LUA_COLIBNAME: &str = "coroutine";
|
||||
pub const LUA_TABLIBNAME: &str = "table";
|
||||
pub const LUA_IOLIBNAME: &str = "io";
|
||||
pub const LUA_OSLIBNAME: &str = "os";
|
||||
pub const LUA_STRLIBNAME: &str = "string";
|
||||
pub const LUA_BITLIBNAME: &str = "bit32";
|
||||
pub const LUA_MATHLIBNAME: &str = "math";
|
||||
pub const LUA_DBLIBNAME: &str = "debug";
|
||||
pub const LUA_LOADLIBNAME: &str = "package";
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua52", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn luaopen_base(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_coroutine(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_table(L: *mut lua_State) -> c_int;
|
||||
|
||||
@@ -9,10 +9,10 @@ use super::lua::{self, lua_CFunction, lua_Integer, lua_Number, lua_State};
|
||||
pub const LUA_ERRFILE: c_int = lua::LUA_ERRERR + 1;
|
||||
|
||||
// Key, in the registry, for table of loaded modules
|
||||
pub const LUA_LOADED_TABLE: *const c_char = cstr!("_LOADED");
|
||||
pub const LUA_LOADED_TABLE: &str = "_LOADED";
|
||||
|
||||
// Key, in the registry, for table of preloaded loaders
|
||||
pub const LUA_PRELOAD_TABLE: *const c_char = cstr!("_PRELOAD");
|
||||
pub const LUA_PRELOAD_TABLE: &str = "_PRELOAD";
|
||||
|
||||
#[repr(C)]
|
||||
pub struct luaL_Reg {
|
||||
@@ -21,7 +21,7 @@ pub struct luaL_Reg {
|
||||
}
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua53", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn luaL_checkversion_(L: *mut lua_State, ver: lua_Number, sz: usize);
|
||||
|
||||
pub fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int;
|
||||
@@ -65,7 +65,7 @@ pub const LUA_NOREF: c_int = -2;
|
||||
pub const LUA_REFNIL: c_int = -1;
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua53", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn luaL_ref(L: *mut lua_State, t: c_int) -> c_int;
|
||||
pub fn luaL_unref(L: *mut lua_State, t: c_int, r#ref: c_int);
|
||||
|
||||
@@ -78,7 +78,7 @@ pub unsafe fn luaL_loadfile(L: *mut lua_State, f: *const c_char) -> c_int {
|
||||
}
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua53", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn luaL_loadbufferx(
|
||||
L: *mut lua_State,
|
||||
buff: *const c_char,
|
||||
|
||||
+13
-12
@@ -1,6 +1,5 @@
|
||||
//! Contains definitions from `lua.h`.
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::marker::{PhantomData, PhantomPinned};
|
||||
use std::os::raw::{c_char, c_double, c_int, c_uchar, c_void};
|
||||
use std::{mem, ptr};
|
||||
@@ -96,13 +95,13 @@ pub type lua_Reader =
|
||||
pub type lua_Writer =
|
||||
unsafe extern "C-unwind" fn(L: *mut lua_State, p: *const c_void, sz: usize, ud: *mut c_void) -> c_int;
|
||||
|
||||
/// Type for memory-allocation functions (no unwinding)
|
||||
/// Type for memory-allocation functions
|
||||
#[rustfmt::skip]
|
||||
pub type lua_Alloc =
|
||||
unsafe extern "C" fn(ud: *mut c_void, ptr: *mut c_void, osize: usize, nsize: usize) -> *mut c_void;
|
||||
unsafe extern "C-unwind" fn(ud: *mut c_void, ptr: *mut c_void, osize: usize, nsize: usize) -> *mut c_void;
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua53", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
//
|
||||
// State manipulation
|
||||
//
|
||||
@@ -172,14 +171,14 @@ pub const LUA_OPLT: c_int = 1;
|
||||
pub const LUA_OPLE: c_int = 2;
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua53", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn lua_arith(L: *mut lua_State, op: c_int);
|
||||
pub fn lua_rawequal(L: *mut lua_State, idx1: c_int, idx2: c_int) -> c_int;
|
||||
pub fn lua_compare(L: *mut lua_State, idx1: c_int, idx2: c_int, op: c_int) -> c_int;
|
||||
}
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua53", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
//
|
||||
// Push functions (C -> stack)
|
||||
//
|
||||
@@ -265,7 +264,7 @@ pub unsafe fn lua_pcall(L: *mut lua_State, n: c_int, r: c_int, f: c_int) -> c_in
|
||||
}
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua53", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
//
|
||||
// Coroutine functions
|
||||
//
|
||||
@@ -300,12 +299,12 @@ pub const LUA_GCSETSTEPMUL: c_int = 7;
|
||||
pub const LUA_GCISRUNNING: c_int = 9;
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua53", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn lua_gc(L: *mut lua_State, what: c_int, data: c_int) -> c_int;
|
||||
}
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua53", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
//
|
||||
// Miscellaneous functions
|
||||
//
|
||||
@@ -408,8 +407,10 @@ pub unsafe fn lua_isnoneornil(L: *mut lua_State, n: c_int) -> c_int {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushliteral(L: *mut lua_State, s: &'static CStr) {
|
||||
lua_pushstring(L, s.as_ptr());
|
||||
pub unsafe fn lua_pushliteral(L: *mut lua_State, s: &'static str) -> *const c_char {
|
||||
use std::ffi::CString;
|
||||
let c_str = CString::new(s).unwrap();
|
||||
lua_pushlstring(L, c_str.as_ptr(), c_str.as_bytes().len())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@@ -477,7 +478,7 @@ pub const LUA_MASKCOUNT: c_int = 1 << (LUA_HOOKCOUNT as usize);
|
||||
pub type lua_Hook = unsafe extern "C-unwind" fn(L: *mut lua_State, ar: *mut lua_Debug);
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua53", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn lua_getstack(L: *mut lua_State, level: c_int, ar: *mut lua_Debug) -> c_int;
|
||||
pub fn lua_getinfo(L: *mut lua_State, what: *const c_char, ar: *mut lua_Debug) -> c_int;
|
||||
pub fn lua_getlocal(L: *mut lua_State, ar: *const lua_Debug, n: c_int) -> *const c_char;
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
//! Contains definitions from `lualib.h`.
|
||||
|
||||
use std::os::raw::{c_char, c_int};
|
||||
use std::os::raw::c_int;
|
||||
|
||||
use super::lua::lua_State;
|
||||
|
||||
pub const LUA_COLIBNAME: *const c_char = cstr!("coroutine");
|
||||
pub const LUA_TABLIBNAME: *const c_char = cstr!("table");
|
||||
pub const LUA_IOLIBNAME: *const c_char = cstr!("io");
|
||||
pub const LUA_OSLIBNAME: *const c_char = cstr!("os");
|
||||
pub const LUA_STRLIBNAME: *const c_char = cstr!("string");
|
||||
pub const LUA_UTF8LIBNAME: *const c_char = cstr!("utf8");
|
||||
pub const LUA_BITLIBNAME: *const c_char = cstr!("bit32");
|
||||
pub const LUA_MATHLIBNAME: *const c_char = cstr!("math");
|
||||
pub const LUA_DBLIBNAME: *const c_char = cstr!("debug");
|
||||
pub const LUA_LOADLIBNAME: *const c_char = cstr!("package");
|
||||
pub const LUA_COLIBNAME: &str = "coroutine";
|
||||
pub const LUA_TABLIBNAME: &str = "table";
|
||||
pub const LUA_IOLIBNAME: &str = "io";
|
||||
pub const LUA_OSLIBNAME: &str = "os";
|
||||
pub const LUA_STRLIBNAME: &str = "string";
|
||||
pub const LUA_UTF8LIBNAME: &str = "utf8";
|
||||
pub const LUA_BITLIBNAME: &str = "bit32";
|
||||
pub const LUA_MATHLIBNAME: &str = "math";
|
||||
pub const LUA_DBLIBNAME: &str = "debug";
|
||||
pub const LUA_LOADLIBNAME: &str = "package";
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua53", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn luaopen_base(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_coroutine(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_table(L: *mut lua_State) -> c_int;
|
||||
|
||||
@@ -9,10 +9,10 @@ use super::lua::{self, lua_CFunction, lua_Integer, lua_Number, lua_State};
|
||||
pub const LUA_ERRFILE: c_int = lua::LUA_ERRERR + 1;
|
||||
|
||||
// Key, in the registry, for table of loaded modules
|
||||
pub const LUA_LOADED_TABLE: *const c_char = cstr!("_LOADED");
|
||||
pub const LUA_LOADED_TABLE: &str = "_LOADED";
|
||||
|
||||
// Key, in the registry, for table of preloaded loaders
|
||||
pub const LUA_PRELOAD_TABLE: *const c_char = cstr!("_PRELOAD");
|
||||
pub const LUA_PRELOAD_TABLE: &str = "_PRELOAD";
|
||||
|
||||
#[repr(C)]
|
||||
pub struct luaL_Reg {
|
||||
@@ -21,7 +21,7 @@ pub struct luaL_Reg {
|
||||
}
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua54", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn luaL_checkversion_(L: *mut lua_State, ver: lua_Number, sz: usize);
|
||||
|
||||
pub fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int;
|
||||
@@ -64,7 +64,7 @@ pub const LUA_NOREF: c_int = -2;
|
||||
pub const LUA_REFNIL: c_int = -1;
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua54", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn luaL_ref(L: *mut lua_State, t: c_int) -> c_int;
|
||||
pub fn luaL_unref(L: *mut lua_State, t: c_int, r#ref: c_int);
|
||||
|
||||
@@ -77,7 +77,7 @@ pub unsafe fn luaL_loadfile(L: *mut lua_State, f: *const c_char) -> c_int {
|
||||
}
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua54", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn luaL_loadbufferx(
|
||||
L: *mut lua_State,
|
||||
buff: *const c_char,
|
||||
|
||||
+14
-13
@@ -1,6 +1,5 @@
|
||||
//! Contains definitions from `lua.h`.
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::marker::{PhantomData, PhantomPinned};
|
||||
use std::os::raw::{c_char, c_double, c_int, c_uchar, c_ushort, c_void};
|
||||
use std::{mem, ptr};
|
||||
@@ -95,16 +94,16 @@ pub type lua_Reader =
|
||||
pub type lua_Writer =
|
||||
unsafe extern "C-unwind" fn(L: *mut lua_State, p: *const c_void, sz: usize, ud: *mut c_void) -> c_int;
|
||||
|
||||
/// Type for memory-allocation functions (no unwinding)
|
||||
/// Type for memory-allocation functions
|
||||
#[rustfmt::skip]
|
||||
pub type lua_Alloc =
|
||||
unsafe extern "C" fn(ud: *mut c_void, ptr: *mut c_void, osize: usize, nsize: usize) -> *mut c_void;
|
||||
unsafe extern "C-unwind" fn(ud: *mut c_void, ptr: *mut c_void, osize: usize, nsize: usize) -> *mut c_void;
|
||||
|
||||
/// Type for warning functions
|
||||
pub type lua_WarnFunction = unsafe extern "C-unwind" fn(ud: *mut c_void, msg: *const c_char, tocont: c_int);
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua54", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
//
|
||||
// State manipulation
|
||||
//
|
||||
@@ -186,14 +185,14 @@ pub const LUA_OPLT: c_int = 1;
|
||||
pub const LUA_OPLE: c_int = 2;
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua54", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn lua_arith(L: *mut lua_State, op: c_int);
|
||||
pub fn lua_rawequal(L: *mut lua_State, idx1: c_int, idx2: c_int) -> c_int;
|
||||
pub fn lua_compare(L: *mut lua_State, idx1: c_int, idx2: c_int, op: c_int) -> c_int;
|
||||
}
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua54", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
//
|
||||
// Push functions (C -> stack)
|
||||
//
|
||||
@@ -279,7 +278,7 @@ pub unsafe fn lua_pcall(L: *mut lua_State, n: c_int, r: c_int, f: c_int) -> c_in
|
||||
}
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua54", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
//
|
||||
// Coroutine functions
|
||||
//
|
||||
@@ -303,7 +302,7 @@ pub unsafe fn lua_yield(L: *mut lua_State, n: c_int) -> c_int {
|
||||
// Warning-related functions
|
||||
//
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua54", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn lua_setwarnf(L: *mut lua_State, f: Option<lua_WarnFunction>, ud: *mut c_void);
|
||||
pub fn lua_warning(L: *mut lua_State, msg: *const c_char, tocont: c_int);
|
||||
}
|
||||
@@ -324,12 +323,12 @@ pub const LUA_GCGEN: c_int = 10;
|
||||
pub const LUA_GCINC: c_int = 11;
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua54", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn lua_gc(L: *mut lua_State, what: c_int, ...) -> c_int;
|
||||
}
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua54", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
//
|
||||
// Miscellaneous functions
|
||||
//
|
||||
@@ -435,8 +434,10 @@ pub unsafe fn lua_isnoneornil(L: *mut lua_State, n: c_int) -> c_int {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushliteral(L: *mut lua_State, s: &'static CStr) {
|
||||
lua_pushstring(L, s.as_ptr());
|
||||
pub unsafe fn lua_pushliteral(L: *mut lua_State, s: &'static str) -> *const c_char {
|
||||
use std::ffi::CString;
|
||||
let c_str = CString::new(s).unwrap();
|
||||
lua_pushlstring(L, c_str.as_ptr(), c_str.as_bytes().len())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@@ -519,7 +520,7 @@ pub const LUA_MASKCOUNT: c_int = 1 << (LUA_HOOKCOUNT as usize);
|
||||
pub type lua_Hook = unsafe extern "C-unwind" fn(L: *mut lua_State, ar: *mut lua_Debug);
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua54", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn lua_getstack(L: *mut lua_State, level: c_int, ar: *mut lua_Debug) -> c_int;
|
||||
pub fn lua_getinfo(L: *mut lua_State, what: *const c_char, ar: *mut lua_Debug) -> c_int;
|
||||
pub fn lua_getlocal(L: *mut lua_State, ar: *const lua_Debug, n: c_int) -> *const c_char;
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//! Contains definitions from `lualib.h`.
|
||||
|
||||
use std::os::raw::{c_char, c_int};
|
||||
use std::os::raw::c_int;
|
||||
|
||||
use super::lua::lua_State;
|
||||
|
||||
pub const LUA_COLIBNAME: *const c_char = cstr!("coroutine");
|
||||
pub const LUA_TABLIBNAME: *const c_char = cstr!("table");
|
||||
pub const LUA_IOLIBNAME: *const c_char = cstr!("io");
|
||||
pub const LUA_OSLIBNAME: *const c_char = cstr!("os");
|
||||
pub const LUA_STRLIBNAME: *const c_char = cstr!("string");
|
||||
pub const LUA_UTF8LIBNAME: *const c_char = cstr!("utf8");
|
||||
pub const LUA_MATHLIBNAME: *const c_char = cstr!("math");
|
||||
pub const LUA_DBLIBNAME: *const c_char = cstr!("debug");
|
||||
pub const LUA_LOADLIBNAME: *const c_char = cstr!("package");
|
||||
pub const LUA_COLIBNAME: &str = "coroutine";
|
||||
pub const LUA_TABLIBNAME: &str = "table";
|
||||
pub const LUA_IOLIBNAME: &str = "io";
|
||||
pub const LUA_OSLIBNAME: &str = "os";
|
||||
pub const LUA_STRLIBNAME: &str = "string";
|
||||
pub const LUA_UTF8LIBNAME: &str = "utf8";
|
||||
pub const LUA_MATHLIBNAME: &str = "math";
|
||||
pub const LUA_DBLIBNAME: &str = "debug";
|
||||
pub const LUA_LOADLIBNAME: &str = "package";
|
||||
|
||||
#[cfg_attr(all(windows, raw_dylib), link(name = "lua54", kind = "raw-dylib"))]
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn luaopen_base(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_coroutine(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_table(L: *mut lua_State) -> c_int;
|
||||
|
||||
+14
-54
@@ -10,8 +10,6 @@ use super::lauxlib::*;
|
||||
use super::lua::*;
|
||||
use super::luacode::*;
|
||||
|
||||
pub const LUA_RESUMEERROR: c_int = -1;
|
||||
|
||||
unsafe fn compat53_reverse(L: *mut lua_State, mut a: c_int, mut b: c_int) {
|
||||
while a < b {
|
||||
lua_pushvalue(L, a);
|
||||
@@ -43,7 +41,7 @@ unsafe fn compat53_findfield(L: *mut lua_State, objidx: c_int, level: c_int) ->
|
||||
} else if compat53_findfield(L, objidx, level - 1) != 0 {
|
||||
// try recursively
|
||||
lua_remove(L, -2); // remove table (but keep name)
|
||||
lua_pushliteral(L, c".");
|
||||
lua_pushliteral(L, ".");
|
||||
lua_insert(L, -2); // place '.' between the two names
|
||||
lua_concat(L, 3);
|
||||
return 1;
|
||||
@@ -77,7 +75,7 @@ unsafe fn compat53_pushfuncname(L: *mut lua_State, level: c_int, ar: *mut lua_De
|
||||
lua_pushfstring(L, cstr!("function '%s'"), lua_tostring(L, -1));
|
||||
lua_remove(L, -2); // remove name
|
||||
} else {
|
||||
lua_pushliteral(L, c"?");
|
||||
lua_pushliteral(L, "?");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,11 +125,6 @@ pub unsafe fn lua_isinteger(L: *mut lua_State, idx: c_int) -> c_int {
|
||||
0
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushinteger(L: *mut lua_State, i: lua_Integer) {
|
||||
lua_pushnumber(L, i as lua_Number);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_tointeger(L: *mut lua_State, i: c_int) -> lua_Integer {
|
||||
lua_tointegerx(L, i, ptr::null_mut())
|
||||
@@ -183,7 +176,6 @@ pub unsafe fn lua_geti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) -> c_i
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int {
|
||||
let n = n.try_into().expect("cannot convert index from lua_Integer");
|
||||
lua_rawgeti_(L, idx, n)
|
||||
}
|
||||
|
||||
@@ -198,7 +190,7 @@ pub unsafe fn lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_
|
||||
pub unsafe fn lua_getuservalue(L: *mut lua_State, mut idx: c_int) -> c_int {
|
||||
luaL_checkstack(L, 2, cstr!("not enough stack slots available"));
|
||||
idx = lua_absindex(L, idx);
|
||||
lua_pushliteral(L, c"__mlua_uservalues");
|
||||
lua_pushliteral(L, "__mlua_uservalues");
|
||||
if lua_rawget(L, LUA_REGISTRYINDEX) != LUA_TTABLE {
|
||||
return LUA_TNIL;
|
||||
}
|
||||
@@ -219,7 +211,6 @@ pub unsafe fn lua_seti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) {
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_rawseti(L: *mut lua_State, idx: c_int, n: lua_Integer) {
|
||||
let n = n.try_into().expect("cannot convert index from lua_Integer");
|
||||
lua_rawseti_(L, idx, n)
|
||||
}
|
||||
|
||||
@@ -236,13 +227,13 @@ pub unsafe fn lua_rawsetp(L: *mut lua_State, idx: c_int, p: *const c_void) {
|
||||
pub unsafe fn lua_setuservalue(L: *mut lua_State, mut idx: c_int) {
|
||||
luaL_checkstack(L, 4, cstr!("not enough stack slots available"));
|
||||
idx = lua_absindex(L, idx);
|
||||
lua_pushliteral(L, c"__mlua_uservalues");
|
||||
lua_pushliteral(L, "__mlua_uservalues");
|
||||
lua_pushvalue(L, -1);
|
||||
if lua_rawget(L, LUA_REGISTRYINDEX) != LUA_TTABLE {
|
||||
lua_pop(L, 1);
|
||||
lua_createtable(L, 0, 2); // main table
|
||||
lua_createtable(L, 0, 1); // metatable
|
||||
lua_pushliteral(L, c"k");
|
||||
lua_pushliteral(L, "k");
|
||||
lua_setfield(L, -2, cstr!("__mode"));
|
||||
lua_setmetatable(L, -2);
|
||||
lua_pushvalue(L, -2);
|
||||
@@ -293,19 +284,6 @@ pub unsafe fn lua_resume(L: *mut lua_State, from: *mut lua_State, narg: c_int, n
|
||||
ret
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_resumex(L: *mut lua_State, from: *mut lua_State, narg: c_int, nres: *mut c_int) -> c_int {
|
||||
let ret = if narg == LUA_RESUMEERROR {
|
||||
lua_resumeerror(L, from)
|
||||
} else {
|
||||
lua_resume_(L, from, narg)
|
||||
};
|
||||
if (ret == LUA_OK || ret == LUA_YIELD) && !(nres.is_null()) {
|
||||
*nres = lua_gettop(L);
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
//
|
||||
// lauxlib ported functions
|
||||
//
|
||||
@@ -316,30 +294,12 @@ pub unsafe fn luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char)
|
||||
if !msg.is_null() {
|
||||
luaL_error(L, cstr!("stack overflow (%s)"), msg);
|
||||
} else {
|
||||
lua_pushliteral(L, c"stack overflow");
|
||||
lua_pushliteral(L, "stack overflow");
|
||||
lua_error(L);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_checkinteger(L: *mut lua_State, narg: c_int) -> lua_Integer {
|
||||
let mut isnum = 0;
|
||||
let int = lua_tointegerx(L, narg, &mut isnum);
|
||||
if isnum == 0 {
|
||||
luaL_typeerror(L, narg, lua_typename(L, LUA_TNUMBER));
|
||||
}
|
||||
int
|
||||
}
|
||||
|
||||
pub unsafe fn luaL_optinteger(L: *mut lua_State, narg: c_int, def: lua_Integer) -> lua_Integer {
|
||||
if lua_isnoneornil(L, narg) != 0 {
|
||||
def
|
||||
} else {
|
||||
luaL_checkinteger(L, narg)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int {
|
||||
if luaL_getmetafield_(L, obj, e) != 0 {
|
||||
@@ -368,11 +328,11 @@ pub unsafe fn luaL_loadbufferenv(
|
||||
mode: *const c_char,
|
||||
mut env: c_int,
|
||||
) -> c_int {
|
||||
unsafe extern "C" {
|
||||
extern "C" {
|
||||
fn free(p: *mut c_void);
|
||||
}
|
||||
|
||||
unsafe extern "C" fn data_dtor(_: *mut lua_State, data: *mut c_void) {
|
||||
unsafe extern "C-unwind" fn data_dtor(data: *mut c_void) {
|
||||
free(*(data as *mut *mut c_char) as *mut c_void);
|
||||
}
|
||||
|
||||
@@ -455,11 +415,11 @@ pub unsafe fn luaL_traceback(L: *mut lua_State, L1: *mut lua_State, msg: *const
|
||||
if !msg.is_null() {
|
||||
lua_pushfstring(L, cstr!("%s\n"), msg);
|
||||
}
|
||||
lua_pushliteral(L, c"stack traceback:");
|
||||
lua_pushliteral(L, "stack traceback:");
|
||||
while lua_getinfo(L1, level, cstr!(""), &mut ar) != 0 {
|
||||
if level + 1 == mark {
|
||||
// too many levels?
|
||||
lua_pushliteral(L, c"\n\t..."); // add a '...'
|
||||
lua_pushliteral(L, "\n\t..."); // add a '...'
|
||||
level = numlevels - COMPAT53_LEVELS2; // and skip to last ones
|
||||
} else {
|
||||
lua_getinfo(L1, level, cstr!("sln"), &mut ar);
|
||||
@@ -467,7 +427,7 @@ pub unsafe fn luaL_traceback(L: *mut lua_State, L1: *mut lua_State, msg: *const
|
||||
if ar.currentline > 0 {
|
||||
lua_pushfstring(L, cstr!("%d:"), ar.currentline);
|
||||
}
|
||||
lua_pushliteral(L, c" in ");
|
||||
lua_pushliteral(L, " in ");
|
||||
compat53_pushfuncname(L, level, &mut ar);
|
||||
lua_concat(L, lua_gettop(L) - top);
|
||||
}
|
||||
@@ -481,16 +441,16 @@ pub unsafe fn luaL_tolstring(L: *mut lua_State, mut idx: c_int, len: *mut usize)
|
||||
if luaL_callmeta(L, idx, cstr!("__tostring")) == 0 {
|
||||
match lua_type(L, idx) {
|
||||
LUA_TNIL => {
|
||||
lua_pushliteral(L, c"nil");
|
||||
lua_pushliteral(L, "nil");
|
||||
}
|
||||
LUA_TSTRING | LUA_TNUMBER => {
|
||||
lua_pushvalue(L, idx);
|
||||
}
|
||||
LUA_TBOOLEAN => {
|
||||
if lua_toboolean(L, idx) == 0 {
|
||||
lua_pushliteral(L, c"false");
|
||||
lua_pushliteral(L, "false");
|
||||
} else {
|
||||
lua_pushliteral(L, c"true");
|
||||
lua_pushliteral(L, "true");
|
||||
}
|
||||
}
|
||||
t => {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
use std::os::raw::{c_char, c_float, c_int, c_void};
|
||||
use std::ptr;
|
||||
|
||||
use super::lua::{self, lua_CFunction, lua_Number, lua_State, lua_Unsigned, LUA_REGISTRYINDEX};
|
||||
use super::lua::{self, lua_CFunction, lua_Integer, lua_Number, lua_State, lua_Unsigned, LUA_REGISTRYINDEX};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct luaL_Reg {
|
||||
@@ -11,7 +11,7 @@ pub struct luaL_Reg {
|
||||
pub func: lua_CFunction,
|
||||
}
|
||||
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn luaL_register(L: *mut lua_State, libname: *const c_char, l: *const luaL_Reg);
|
||||
#[link_name = "luaL_getmetafield"]
|
||||
pub fn luaL_getmetafield_(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int;
|
||||
@@ -33,10 +33,8 @@ unsafe extern "C-unwind" {
|
||||
pub fn luaL_checkboolean(L: *mut lua_State, narg: c_int) -> c_int;
|
||||
pub fn luaL_optboolean(L: *mut lua_State, narg: c_int, def: c_int) -> c_int;
|
||||
|
||||
#[link_name = "luaL_checkinteger"]
|
||||
pub fn luaL_checkinteger_(L: *mut lua_State, narg: c_int) -> c_int;
|
||||
#[link_name = "luaL_optinteger"]
|
||||
pub fn luaL_optinteger_(L: *mut lua_State, narg: c_int, def: c_int) -> c_int;
|
||||
pub fn luaL_checkinteger(L: *mut lua_State, narg: c_int) -> lua_Integer;
|
||||
pub fn luaL_optinteger(L: *mut lua_State, narg: c_int, def: lua_Integer) -> lua_Integer;
|
||||
pub fn luaL_checkunsigned(L: *mut lua_State, narg: c_int) -> lua_Unsigned;
|
||||
pub fn luaL_optunsigned(L: *mut lua_State, narg: c_int, def: lua_Unsigned) -> lua_Unsigned;
|
||||
|
||||
@@ -71,17 +69,10 @@ unsafe extern "C-unwind" {
|
||||
|
||||
pub fn luaL_newstate() -> *mut lua_State;
|
||||
|
||||
pub fn luaL_findtable(
|
||||
L: *mut lua_State,
|
||||
idx: c_int,
|
||||
fname: *const c_char,
|
||||
szhint: c_int,
|
||||
) -> *const c_char;
|
||||
// TODO: luaL_findtable
|
||||
|
||||
pub fn luaL_typename(L: *mut lua_State, idx: c_int) -> *const c_char;
|
||||
|
||||
pub fn luaL_callyieldable(L: *mut lua_State, nargs: c_int, nresults: c_int) -> c_int;
|
||||
|
||||
// sandbox libraries and globals
|
||||
#[link_name = "luaL_sandbox"]
|
||||
pub fn luaL_sandbox_(L: *mut lua_State);
|
||||
@@ -150,7 +141,7 @@ pub unsafe fn luaL_sandbox(L: *mut lua_State, enabled: c_int) {
|
||||
}
|
||||
|
||||
// set all builtin metatables to read-only
|
||||
lua_pushliteral(L, c"");
|
||||
lua_pushliteral(L, "");
|
||||
if lua_getmetatable(L, -1) != 0 {
|
||||
lua_setreadonly(L, -1, enabled);
|
||||
lua_pop(L, 2);
|
||||
@@ -182,7 +173,7 @@ pub struct luaL_Strbuf {
|
||||
// For compatibility
|
||||
pub type luaL_Buffer = luaL_Strbuf;
|
||||
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn luaL_buffinit(L: *mut lua_State, B: *mut luaL_Strbuf);
|
||||
pub fn luaL_buffinitsize(L: *mut lua_State, B: *mut luaL_Strbuf, size: usize) -> *mut c_char;
|
||||
pub fn luaL_prepbuffsize(B: *mut luaL_Strbuf, size: usize) -> *mut c_char;
|
||||
|
||||
+32
-36
@@ -1,6 +1,5 @@
|
||||
//! Contains definitions from `lua.h`.
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::marker::{PhantomData, PhantomPinned};
|
||||
use std::os::raw::{c_char, c_double, c_float, c_int, c_uint, c_void};
|
||||
use std::{mem, ptr};
|
||||
@@ -12,10 +11,10 @@ pub const LUA_MULTRET: c_int = -1;
|
||||
const LUAI_MAXCSTACK: c_int = 1000000;
|
||||
|
||||
// Number of valid Lua userdata tags
|
||||
pub const LUA_UTAG_LIMIT: c_int = 128;
|
||||
const LUA_UTAG_LIMIT: c_int = 128;
|
||||
|
||||
// Number of valid Lua lightuserdata tags
|
||||
pub const LUA_LUTAG_LIMIT: c_int = 128;
|
||||
const LUA_LUTAG_LIMIT: c_int = 128;
|
||||
|
||||
//
|
||||
// Pseudo-indices
|
||||
@@ -70,11 +69,8 @@ pub const LUA_MINSTACK: c_int = 20;
|
||||
/// A Lua number, usually equivalent to `f64`.
|
||||
pub type lua_Number = c_double;
|
||||
|
||||
/// A Lua integer, usually equivalent to `i64`
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
pub type lua_Integer = i32;
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
pub type lua_Integer = i64;
|
||||
/// A Lua integer, equivalent to `i32`.
|
||||
pub type lua_Integer = c_int;
|
||||
|
||||
/// A Lua unsigned integer, equivalent to `u32`.
|
||||
pub type lua_Unsigned = c_uint;
|
||||
@@ -83,19 +79,20 @@ pub type lua_Unsigned = c_uint;
|
||||
pub type lua_CFunction = unsafe extern "C-unwind" fn(L: *mut lua_State) -> c_int;
|
||||
pub type lua_Continuation = unsafe extern "C-unwind" fn(L: *mut lua_State, status: c_int) -> c_int;
|
||||
|
||||
/// Type for userdata destructor functions (no unwinding).
|
||||
pub type lua_Destructor = unsafe extern "C" fn(L: *mut lua_State, *mut c_void);
|
||||
/// Type for userdata destructor functions.
|
||||
pub type lua_Udestructor = unsafe extern "C-unwind" fn(*mut c_void);
|
||||
pub type lua_Destructor = unsafe extern "C-unwind" fn(L: *mut lua_State, *mut c_void);
|
||||
|
||||
/// Type for memory-allocation functions (no unwinding).
|
||||
/// Type for memory-allocation functions.
|
||||
pub type lua_Alloc =
|
||||
unsafe extern "C" fn(ud: *mut c_void, ptr: *mut c_void, osize: usize, nsize: usize) -> *mut c_void;
|
||||
unsafe extern "C-unwind" fn(ud: *mut c_void, ptr: *mut c_void, osize: usize, nsize: usize) -> *mut c_void;
|
||||
|
||||
/// Returns Luau release version (eg. `0.xxx`).
|
||||
pub const fn luau_version() -> Option<&'static str> {
|
||||
option_env!("LUAU_VERSION")
|
||||
}
|
||||
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
//
|
||||
// State manipulation
|
||||
//
|
||||
@@ -139,7 +136,7 @@ unsafe extern "C-unwind" {
|
||||
|
||||
pub fn lua_tonumberx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Number;
|
||||
#[link_name = "lua_tointegerx"]
|
||||
pub fn lua_tointegerx_(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> c_int;
|
||||
pub fn lua_tointegerx_(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Integer;
|
||||
pub fn lua_tounsignedx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Unsigned;
|
||||
pub fn lua_tovector(L: *mut lua_State, idx: c_int) -> *const c_float;
|
||||
pub fn lua_toboolean(L: *mut lua_State, idx: c_int) -> c_int;
|
||||
@@ -163,8 +160,7 @@ unsafe extern "C-unwind" {
|
||||
//
|
||||
pub fn lua_pushnil(L: *mut lua_State);
|
||||
pub fn lua_pushnumber(L: *mut lua_State, n: lua_Number);
|
||||
#[link_name = "lua_pushinteger"]
|
||||
pub fn lua_pushinteger_(L: *mut lua_State, n: c_int);
|
||||
pub fn lua_pushinteger(L: *mut lua_State, n: lua_Integer);
|
||||
pub fn lua_pushunsigned(L: *mut lua_State, n: lua_Unsigned);
|
||||
#[cfg(not(feature = "luau-vector4"))]
|
||||
pub fn lua_pushvector(L: *mut lua_State, x: c_float, y: c_float, z: c_float);
|
||||
@@ -190,7 +186,7 @@ unsafe extern "C-unwind" {
|
||||
pub fn lua_pushlightuserdatatagged(L: *mut lua_State, p: *mut c_void, tag: c_int);
|
||||
pub fn lua_newuserdatatagged(L: *mut lua_State, sz: usize, tag: c_int) -> *mut c_void;
|
||||
pub fn lua_newuserdatataggedwithmetatable(L: *mut lua_State, sz: usize, tag: c_int) -> *mut c_void;
|
||||
pub fn lua_newuserdatadtor(L: *mut lua_State, sz: usize, dtor: lua_Destructor) -> *mut c_void;
|
||||
pub fn lua_newuserdatadtor(L: *mut lua_State, sz: usize, dtor: lua_Udestructor) -> *mut c_void;
|
||||
|
||||
pub fn lua_newbuffer(L: *mut lua_State, sz: usize) -> *mut c_void;
|
||||
|
||||
@@ -264,14 +260,14 @@ pub const LUA_GCSETGOAL: c_int = 7;
|
||||
pub const LUA_GCSETSTEPMUL: c_int = 8;
|
||||
pub const LUA_GCSETSTEPSIZE: c_int = 9;
|
||||
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn lua_gc(L: *mut lua_State, what: c_int, data: c_int) -> c_int;
|
||||
}
|
||||
|
||||
//
|
||||
// Memory statistics
|
||||
//
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn lua_setmemcat(L: *mut lua_State, category: c_int);
|
||||
pub fn lua_totalbytes(L: *mut lua_State, category: c_int) -> usize;
|
||||
}
|
||||
@@ -279,7 +275,7 @@ unsafe extern "C-unwind" {
|
||||
//
|
||||
// Miscellaneous functions
|
||||
//
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn lua_error(L: *mut lua_State) -> !;
|
||||
pub fn lua_next(L: *mut lua_State, idx: c_int) -> c_int;
|
||||
pub fn lua_rawiter(L: *mut lua_State, idx: c_int, iter: c_int) -> c_int;
|
||||
@@ -289,7 +285,7 @@ unsafe extern "C-unwind" {
|
||||
pub fn lua_setuserdatatag(L: *mut lua_State, idx: c_int, tag: c_int);
|
||||
pub fn lua_setuserdatadtor(L: *mut lua_State, tag: c_int, dtor: Option<lua_Destructor>);
|
||||
pub fn lua_getuserdatadtor(L: *mut lua_State, tag: c_int) -> Option<lua_Destructor>;
|
||||
pub fn lua_setuserdatametatable(L: *mut lua_State, tag: c_int);
|
||||
pub fn lua_setuserdatametatable(L: *mut lua_State, tag: c_int, idx: c_int);
|
||||
pub fn lua_getuserdatametatable(L: *mut lua_State, tag: c_int);
|
||||
pub fn lua_setlightuserdataname(L: *mut lua_State, tag: c_int, name: *const c_char);
|
||||
pub fn lua_getlightuserdataname(L: *mut lua_State, tag: c_int) -> *const c_char;
|
||||
@@ -304,7 +300,7 @@ unsafe extern "C-unwind" {
|
||||
pub const LUA_NOREF: c_int = -1;
|
||||
pub const LUA_REFNIL: c_int = 0;
|
||||
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn lua_ref(L: *mut lua_State, idx: c_int) -> c_int;
|
||||
pub fn lua_unref(L: *mut lua_State, r#ref: c_int);
|
||||
}
|
||||
@@ -314,13 +310,13 @@ unsafe extern "C-unwind" {
|
||||
//
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_tonumber(L: *mut lua_State, idx: c_int) -> lua_Number {
|
||||
lua_tonumberx(L, idx, ptr::null_mut())
|
||||
pub unsafe fn lua_tonumber(L: *mut lua_State, i: c_int) -> lua_Number {
|
||||
lua_tonumberx(L, i, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_tointeger_(L: *mut lua_State, idx: c_int) -> c_int {
|
||||
lua_tointegerx_(L, idx, ptr::null_mut())
|
||||
pub unsafe fn lua_tointeger_(L: *mut lua_State, i: c_int) -> lua_Integer {
|
||||
lua_tointegerx_(L, i, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@@ -344,14 +340,12 @@ pub unsafe fn lua_newuserdata(L: *mut lua_State, sz: usize) -> *mut c_void {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_newuserdata_t<T>(L: *mut lua_State, data: T) -> *mut T {
|
||||
unsafe extern "C" fn destructor<T>(_: *mut lua_State, ud: *mut c_void) {
|
||||
pub unsafe fn lua_newuserdata_t<T>(L: *mut lua_State) -> *mut T {
|
||||
unsafe extern "C-unwind" fn destructor<T>(ud: *mut c_void) {
|
||||
ptr::drop_in_place(ud as *mut T);
|
||||
}
|
||||
|
||||
let ud_ptr = lua_newuserdatadtor(L, const { mem::size_of::<T>() }, destructor::<T>) as *mut T;
|
||||
ptr::write(ud_ptr, data);
|
||||
ud_ptr
|
||||
lua_newuserdatadtor(L, mem::size_of::<T>(), destructor::<T>) as *mut T
|
||||
}
|
||||
|
||||
// TODO: lua_strlen
|
||||
@@ -407,8 +401,10 @@ pub unsafe fn lua_isnoneornil(L: *mut lua_State, n: c_int) -> c_int {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushliteral(L: *mut lua_State, s: &'static CStr) {
|
||||
lua_pushstring_(L, s.as_ptr());
|
||||
pub unsafe fn lua_pushliteral(L: *mut lua_State, s: &'static str) {
|
||||
use std::ffi::CString;
|
||||
let c_str = CString::new(s).unwrap();
|
||||
lua_pushlstring_(L, c_str.as_ptr(), c_str.as_bytes().len())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@@ -470,7 +466,7 @@ pub type lua_Coverage = unsafe extern "C-unwind" fn(
|
||||
size: usize,
|
||||
);
|
||||
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn lua_stackdepth(L: *mut lua_State) -> c_int;
|
||||
pub fn lua_getinfo(L: *mut lua_State, level: c_int, what: *const c_char, ar: *mut lua_Debug) -> c_int;
|
||||
pub fn lua_getargument(L: *mut lua_State, level: c_int, n: c_int) -> c_int;
|
||||
@@ -536,12 +532,12 @@ pub struct lua_Callbacks {
|
||||
pub onallocate: Option<unsafe extern "C-unwind" fn(L: *mut lua_State, osize: usize, nsize: usize)>,
|
||||
}
|
||||
|
||||
unsafe extern "C" {
|
||||
extern "C" {
|
||||
pub fn lua_callbacks(L: *mut lua_State) -> *mut lua_Callbacks;
|
||||
}
|
||||
|
||||
// Functions from customization lib
|
||||
unsafe extern "C" {
|
||||
extern "C" {
|
||||
pub fn luau_setfflag(name: *const c_char, value: c_int) -> c_int;
|
||||
pub fn lua_getmetatablepointer(L: *mut lua_State, idx: c_int) -> *const c_void;
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ pub type lua_LibraryMemberConstantCallback = unsafe extern "C-unwind" fn(
|
||||
constant: *mut lua_CompileConstant,
|
||||
);
|
||||
|
||||
unsafe extern "C" {
|
||||
extern "C" {
|
||||
pub fn luau_set_compile_constant_nil(cons: *mut lua_CompileConstant);
|
||||
pub fn luau_set_compile_constant_boolean(cons: *mut lua_CompileConstant, b: c_int);
|
||||
pub fn luau_set_compile_constant_number(cons: *mut lua_CompileConstant, n: f64);
|
||||
@@ -84,7 +84,7 @@ unsafe extern "C" {
|
||||
pub fn luau_set_compile_constant_string(cons: *mut lua_CompileConstant, s: *const c_char, l: usize);
|
||||
}
|
||||
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
#[link_name = "luau_compile"]
|
||||
pub fn luau_compile_(
|
||||
source: *const c_char,
|
||||
@@ -94,7 +94,7 @@ unsafe extern "C-unwind" {
|
||||
) -> *mut c_char;
|
||||
}
|
||||
|
||||
unsafe extern "C" {
|
||||
extern "C" {
|
||||
fn free(p: *mut c_void);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::os::raw::c_int;
|
||||
|
||||
use super::lua::lua_State;
|
||||
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn luau_codegen_supported() -> c_int;
|
||||
pub fn luau_codegen_create(state: *mut lua_State);
|
||||
pub fn luau_codegen_compile(state: *mut lua_State, idx: c_int);
|
||||
|
||||
+12
-12
@@ -1,21 +1,21 @@
|
||||
//! Contains definitions from `lualib.h`.
|
||||
|
||||
use std::os::raw::{c_char, c_int};
|
||||
use std::os::raw::c_int;
|
||||
|
||||
use super::lua::lua_State;
|
||||
|
||||
pub const LUA_COLIBNAME: *const c_char = cstr!("coroutine");
|
||||
pub const LUA_TABLIBNAME: *const c_char = cstr!("table");
|
||||
pub const LUA_OSLIBNAME: *const c_char = cstr!("os");
|
||||
pub const LUA_STRLIBNAME: *const c_char = cstr!("string");
|
||||
pub const LUA_BITLIBNAME: *const c_char = cstr!("bit32");
|
||||
pub const LUA_BUFFERLIBNAME: *const c_char = cstr!("buffer");
|
||||
pub const LUA_UTF8LIBNAME: *const c_char = cstr!("utf8");
|
||||
pub const LUA_MATHLIBNAME: *const c_char = cstr!("math");
|
||||
pub const LUA_DBLIBNAME: *const c_char = cstr!("debug");
|
||||
pub const LUA_VECLIBNAME: *const c_char = cstr!("vector");
|
||||
pub const LUA_COLIBNAME: &str = "coroutine";
|
||||
pub const LUA_TABLIBNAME: &str = "table";
|
||||
pub const LUA_OSLIBNAME: &str = "os";
|
||||
pub const LUA_STRLIBNAME: &str = "string";
|
||||
pub const LUA_BITLIBNAME: &str = "bit32";
|
||||
pub const LUA_BUFFERLIBNAME: &str = "buffer";
|
||||
pub const LUA_UTF8LIBNAME: &str = "utf8";
|
||||
pub const LUA_MATHLIBNAME: &str = "math";
|
||||
pub const LUA_DBLIBNAME: &str = "debug";
|
||||
pub const LUA_VECLIBNAME: &str = "vector";
|
||||
|
||||
unsafe extern "C-unwind" {
|
||||
extern "C-unwind" {
|
||||
pub fn luaopen_base(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_coroutine(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_table(L: *mut lua_State) -> c_int;
|
||||
|
||||
@@ -1,154 +0,0 @@
|
||||
//! Contains definitions from `Require.h`.
|
||||
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
|
||||
use super::lua::lua_State;
|
||||
|
||||
pub const LUA_REGISTERED_MODULES_TABLE: *const c_char = cstr!("_REGISTEREDMODULES");
|
||||
|
||||
#[repr(C)]
|
||||
pub enum luarequire_NavigateResult {
|
||||
Success,
|
||||
Ambiguous,
|
||||
NotFound,
|
||||
}
|
||||
|
||||
// Functions returning WriteSuccess are expected to set their size_out argument
|
||||
// to the number of bytes written to the buffer. If WriteBufferTooSmall is
|
||||
// returned, size_out should be set to the required buffer size.
|
||||
#[repr(C)]
|
||||
pub enum luarequire_WriteResult {
|
||||
Success,
|
||||
BufferTooSmall,
|
||||
Failure,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct luarequire_Configuration {
|
||||
// Returns whether requires are permitted from the given chunkname.
|
||||
pub is_require_allowed:
|
||||
unsafe extern "C" fn(L: *mut lua_State, ctx: *mut c_void, requirer_chunkname: *const c_char) -> bool,
|
||||
|
||||
// Resets the internal state to point at the requirer module.
|
||||
pub reset: unsafe extern "C" fn(
|
||||
L: *mut lua_State,
|
||||
ctx: *mut c_void,
|
||||
requirer_chunkname: *const c_char,
|
||||
) -> luarequire_NavigateResult,
|
||||
|
||||
// Resets the internal state to point at an aliased module, given its exact path from a configuration
|
||||
// file. This function is only called when an alias's path cannot be resolved relative to its
|
||||
// configuration file.
|
||||
pub jump_to_alias: unsafe extern "C" fn(
|
||||
L: *mut lua_State,
|
||||
ctx: *mut c_void,
|
||||
path: *const c_char,
|
||||
) -> luarequire_NavigateResult,
|
||||
|
||||
// Navigates through the context by making mutations to the internal state.
|
||||
pub to_parent: unsafe extern "C" fn(L: *mut lua_State, ctx: *mut c_void) -> luarequire_NavigateResult,
|
||||
pub to_child: unsafe extern "C" fn(
|
||||
L: *mut lua_State,
|
||||
ctx: *mut c_void,
|
||||
name: *const c_char,
|
||||
) -> luarequire_NavigateResult,
|
||||
|
||||
// Returns whether the context is currently pointing at a module.
|
||||
pub is_module_present: unsafe extern "C" fn(L: *mut lua_State, ctx: *mut c_void) -> bool,
|
||||
|
||||
// Provides the contents of the current module. This function is only called if is_module_present returns
|
||||
// true.
|
||||
pub get_contents: unsafe extern "C" fn(
|
||||
L: *mut lua_State,
|
||||
ctx: *mut c_void,
|
||||
buffer: *mut c_char,
|
||||
buffer_size: usize,
|
||||
size_out: *mut usize,
|
||||
) -> luarequire_WriteResult,
|
||||
|
||||
// Provides a chunkname for the current module. This will be accessible through the debug library. This
|
||||
// function is only called if is_module_present returns true.
|
||||
pub get_chunkname: unsafe extern "C" fn(
|
||||
L: *mut lua_State,
|
||||
ctx: *mut c_void,
|
||||
buffer: *mut c_char,
|
||||
buffer_size: usize,
|
||||
size_out: *mut usize,
|
||||
) -> luarequire_WriteResult,
|
||||
|
||||
// Provides a cache key representing the current module. This function is only called if
|
||||
// is_module_present returns true.
|
||||
pub get_cache_key: unsafe extern "C" fn(
|
||||
L: *mut lua_State,
|
||||
ctx: *mut c_void,
|
||||
buffer: *mut c_char,
|
||||
buffer_size: usize,
|
||||
size_out: *mut usize,
|
||||
) -> luarequire_WriteResult,
|
||||
|
||||
// Returns whether a configuration file is present in the current context.
|
||||
// If not, require-by-string will call to_parent until either a configuration file is present or
|
||||
// NAVIGATE_FAILURE is returned (at root).
|
||||
pub is_config_present: unsafe extern "C" fn(L: *mut lua_State, ctx: *mut c_void) -> bool,
|
||||
|
||||
// Provides the contents of the configuration file in the current context.
|
||||
// This function is only called if is_config_present returns true.
|
||||
pub get_config: unsafe extern "C" fn(
|
||||
L: *mut lua_State,
|
||||
ctx: *mut c_void,
|
||||
buffer: *mut c_char,
|
||||
buffer_size: usize,
|
||||
size_out: *mut usize,
|
||||
) -> luarequire_WriteResult,
|
||||
|
||||
// Executes the module and places the result on the stack. Returns the number of results placed on the
|
||||
// stack.
|
||||
// Returning -1 directs the requiring thread to yield. In this case, this thread should be resumed with
|
||||
// the module result pushed onto its stack.
|
||||
pub load: unsafe extern "C-unwind" fn(
|
||||
L: *mut lua_State,
|
||||
ctx: *mut c_void,
|
||||
path: *const c_char,
|
||||
chunkname: *const c_char,
|
||||
contents: *const c_char,
|
||||
) -> c_int,
|
||||
}
|
||||
|
||||
// Populates function pointers in the given luarequire_Configuration.
|
||||
pub type luarequire_Configuration_init = unsafe extern "C" fn(config: *mut luarequire_Configuration);
|
||||
|
||||
unsafe extern "C-unwind" {
|
||||
// Initializes and pushes the require closure onto the stack without registration.
|
||||
pub fn luarequire_pushrequire(
|
||||
L: *mut lua_State,
|
||||
config_init: luarequire_Configuration_init,
|
||||
ctx: *mut c_void,
|
||||
) -> c_int;
|
||||
|
||||
// Initializes the require library and registers it globally.
|
||||
pub fn luaopen_require(L: *mut lua_State, config_init: luarequire_Configuration_init, ctx: *mut c_void);
|
||||
|
||||
// Initializes and pushes a "proxyrequire" closure onto the stack.
|
||||
//
|
||||
// The closure takes two parameters: the string path to resolve and the chunkname of an existing
|
||||
// module.
|
||||
pub fn luarequire_pushproxyrequire(
|
||||
L: *mut lua_State,
|
||||
config_init: luarequire_Configuration_init,
|
||||
ctx: *mut c_void,
|
||||
) -> c_int;
|
||||
|
||||
// Registers an aliased require path to a result.
|
||||
//
|
||||
// After registration, the given result will always be immediately returned when the given path is
|
||||
// required.
|
||||
// Expects the path and table to be passed as arguments on the stack.
|
||||
pub fn luarequire_registermodule(L: *mut lua_State) -> c_int;
|
||||
|
||||
// Clears the entry associated with the given cache key from the require cache.
|
||||
// Expects the cache key to be passed as an argument on the stack.
|
||||
pub fn luarequire_clearcacheentry(L: *mut lua_State) -> c_int;
|
||||
|
||||
// Clears all entries from the require cache.
|
||||
pub fn luarequire_clearcache(L: *mut lua_State) -> c_int;
|
||||
}
|
||||
@@ -6,7 +6,6 @@ pub use lua::*;
|
||||
pub use luacode::*;
|
||||
pub use luacodegen::*;
|
||||
pub use lualib::*;
|
||||
pub use luarequire::*;
|
||||
|
||||
pub mod compat;
|
||||
pub mod lauxlib;
|
||||
@@ -14,4 +13,3 @@ pub mod lua;
|
||||
pub mod luacode;
|
||||
pub mod luacodegen;
|
||||
pub mod lualib;
|
||||
pub mod luarequire;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mlua_derive"
|
||||
version = "0.11.0-beta.1"
|
||||
version = "0.10.1"
|
||||
authors = ["Aleksandr Orlenko <zxteam@pm.me>"]
|
||||
edition = "2021"
|
||||
description = "Procedural macros for the mlua crate."
|
||||
|
||||
@@ -103,7 +103,7 @@ pub fn chunk(input: TokenStream) -> TokenStream {
|
||||
|
||||
struct InnerChunk<F: FnOnce(&Lua) -> Result<Table>>(Cell<Option<F>>);
|
||||
|
||||
impl<F> AsChunk for InnerChunk<F>
|
||||
impl<F> AsChunk<'static> for InnerChunk<F>
|
||||
where
|
||||
F: FnOnce(&Lua) -> Result<Table>,
|
||||
{
|
||||
@@ -120,7 +120,7 @@ pub fn chunk(input: TokenStream) -> TokenStream {
|
||||
Some(ChunkMode::Text)
|
||||
}
|
||||
|
||||
fn source<'a>(self) -> IoResult<Cow<'a, [u8]>> {
|
||||
fn source(self) -> IoResult<Cow<'static, [u8]>> {
|
||||
Ok(Cow::Borrowed((#source).as_bytes()))
|
||||
}
|
||||
}
|
||||
|
||||
+54
-164
@@ -2,6 +2,7 @@ use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::CString;
|
||||
use std::io::Result as IoResult;
|
||||
use std::marker::PhantomData;
|
||||
use std::panic::Location;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::string::String as StdString;
|
||||
@@ -16,7 +17,7 @@ use crate::value::Value;
|
||||
/// Trait for types [loadable by Lua] and convertible to a [`Chunk`]
|
||||
///
|
||||
/// [loadable by Lua]: https://www.lua.org/manual/5.4/manual.html#3.3.2
|
||||
pub trait AsChunk {
|
||||
pub trait AsChunk<'a> {
|
||||
/// Returns optional chunk name
|
||||
///
|
||||
/// See [`Chunk::set_name`] for possible name prefixes.
|
||||
@@ -38,75 +39,61 @@ pub trait AsChunk {
|
||||
}
|
||||
|
||||
/// Returns chunk data (can be text or binary)
|
||||
fn source<'a>(self) -> IoResult<Cow<'a, [u8]>>
|
||||
where
|
||||
Self: 'a;
|
||||
fn source(self) -> IoResult<Cow<'a, [u8]>>;
|
||||
}
|
||||
|
||||
impl AsChunk for &str {
|
||||
fn source<'a>(self) -> IoResult<Cow<'a, [u8]>>
|
||||
where
|
||||
Self: 'a,
|
||||
{
|
||||
impl<'a> AsChunk<'a> for &'a str {
|
||||
fn source(self) -> IoResult<Cow<'a, [u8]>> {
|
||||
Ok(Cow::Borrowed(self.as_ref()))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsChunk for StdString {
|
||||
fn source<'a>(self) -> IoResult<Cow<'a, [u8]>> {
|
||||
impl AsChunk<'static> for StdString {
|
||||
fn source(self) -> IoResult<Cow<'static, [u8]>> {
|
||||
Ok(Cow::Owned(self.into_bytes()))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsChunk for &StdString {
|
||||
fn source<'a>(self) -> IoResult<Cow<'a, [u8]>>
|
||||
where
|
||||
Self: 'a,
|
||||
{
|
||||
impl<'a> AsChunk<'a> for &'a StdString {
|
||||
fn source(self) -> IoResult<Cow<'a, [u8]>> {
|
||||
Ok(Cow::Borrowed(self.as_bytes()))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsChunk for &[u8] {
|
||||
fn source<'a>(self) -> IoResult<Cow<'a, [u8]>>
|
||||
where
|
||||
Self: 'a,
|
||||
{
|
||||
impl<'a> AsChunk<'a> for &'a [u8] {
|
||||
fn source(self) -> IoResult<Cow<'a, [u8]>> {
|
||||
Ok(Cow::Borrowed(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsChunk for Vec<u8> {
|
||||
fn source<'a>(self) -> IoResult<Cow<'a, [u8]>> {
|
||||
impl AsChunk<'static> for Vec<u8> {
|
||||
fn source(self) -> IoResult<Cow<'static, [u8]>> {
|
||||
Ok(Cow::Owned(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsChunk for &Vec<u8> {
|
||||
fn source<'a>(self) -> IoResult<Cow<'a, [u8]>>
|
||||
where
|
||||
Self: 'a,
|
||||
{
|
||||
Ok(Cow::Borrowed(self))
|
||||
impl<'a> AsChunk<'a> for &'a Vec<u8> {
|
||||
fn source(self) -> IoResult<Cow<'a, [u8]>> {
|
||||
Ok(Cow::Borrowed(self.as_ref()))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsChunk for &Path {
|
||||
impl AsChunk<'static> for &Path {
|
||||
fn name(&self) -> Option<StdString> {
|
||||
Some(format!("@{}", self.display()))
|
||||
}
|
||||
|
||||
fn source<'a>(self) -> IoResult<Cow<'a, [u8]>> {
|
||||
fn source(self) -> IoResult<Cow<'static, [u8]>> {
|
||||
std::fs::read(self).map(Cow::Owned)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsChunk for PathBuf {
|
||||
impl AsChunk<'static> for PathBuf {
|
||||
fn name(&self) -> Option<StdString> {
|
||||
Some(format!("@{}", self.display()))
|
||||
}
|
||||
|
||||
fn source<'a>(self) -> IoResult<Cow<'a, [u8]>> {
|
||||
fn source(self) -> IoResult<Cow<'static, [u8]>> {
|
||||
std::fs::read(self).map(Cow::Owned)
|
||||
}
|
||||
}
|
||||
@@ -130,28 +117,6 @@ pub enum ChunkMode {
|
||||
Binary,
|
||||
}
|
||||
|
||||
/// Represents a constant value that can be used by Luau compiler.
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum CompileConstant {
|
||||
Nil,
|
||||
Boolean(bool),
|
||||
Number(crate::Number),
|
||||
Vector(crate::Vector),
|
||||
String(String),
|
||||
}
|
||||
|
||||
#[cfg(feature = "luau")]
|
||||
impl From<&'static str> for CompileConstant {
|
||||
fn from(s: &'static str) -> Self {
|
||||
CompileConstant::String(s.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
type LibraryMemberConstantMap = std::sync::Arc<HashMap<(String, String), CompileConstant>>;
|
||||
|
||||
/// Luau compiler
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
@@ -166,9 +131,6 @@ pub struct Compiler {
|
||||
vector_type: Option<String>,
|
||||
mutable_globals: Vec<String>,
|
||||
userdata_types: Vec<String>,
|
||||
libraries_with_known_members: Vec<String>,
|
||||
library_constants: Option<LibraryMemberConstantMap>,
|
||||
disabled_builtins: Vec<String>,
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
@@ -193,9 +155,6 @@ impl Compiler {
|
||||
vector_type: None,
|
||||
mutable_globals: Vec::new(),
|
||||
userdata_types: Vec::new(),
|
||||
libraries_with_known_members: Vec::new(),
|
||||
library_constants: None,
|
||||
disabled_builtins: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,7 +187,6 @@ impl Compiler {
|
||||
/// Possible values:
|
||||
/// * 0 - generate for native modules (default)
|
||||
/// * 1 - generate for all modules
|
||||
#[must_use]
|
||||
pub const fn set_type_info_level(mut self, level: u8) -> Self {
|
||||
self.type_info_level = level;
|
||||
self
|
||||
@@ -271,46 +229,15 @@ impl Compiler {
|
||||
///
|
||||
/// It disables the import optimization for fields accessed through these.
|
||||
#[must_use]
|
||||
pub fn set_mutable_globals<S: Into<String>>(mut self, globals: Vec<S>) -> Self {
|
||||
self.mutable_globals = globals.into_iter().map(|s| s.into()).collect();
|
||||
pub fn set_mutable_globals(mut self, globals: Vec<String>) -> Self {
|
||||
self.mutable_globals = globals;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets a list of userdata types that will be included in the type information.
|
||||
#[must_use]
|
||||
pub fn set_userdata_types<S: Into<String>>(mut self, types: Vec<S>) -> Self {
|
||||
self.userdata_types = types.into_iter().map(|s| s.into()).collect();
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets constants for known library members.
|
||||
///
|
||||
/// The constants are used by the compiler to optimize the generated bytecode.
|
||||
/// Optimization level must be at least 2 for this to have any effect.
|
||||
///
|
||||
/// The first element of the tuple is the library name,the second is the member name, and the
|
||||
/// third is the constant value.
|
||||
#[must_use]
|
||||
pub fn set_library_constants<L, M>(mut self, constants: Vec<(L, M, CompileConstant)>) -> Self
|
||||
where
|
||||
L: Into<String>,
|
||||
M: Into<String>,
|
||||
{
|
||||
let map = constants
|
||||
.into_iter()
|
||||
.map(|(lib, member, cons)| ((lib.into(), member.into()), cons))
|
||||
.collect::<HashMap<_, _>>();
|
||||
self.library_constants = Some(std::sync::Arc::new(map));
|
||||
self.libraries_with_known_members = (self.library_constants.clone())
|
||||
.map(|map| map.keys().map(|(lib, _)| lib.clone()).collect())
|
||||
.unwrap_or_default();
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets a list of builtins that should be disabled.
|
||||
#[must_use]
|
||||
pub fn set_disabled_builtins<S: Into<String>>(mut self, builtins: Vec<S>) -> Self {
|
||||
self.disabled_builtins = builtins.into_iter().map(|s| s.into()).collect();
|
||||
pub fn set_userdata_types(mut self, types: Vec<String>) -> Self {
|
||||
self.userdata_types = types;
|
||||
self
|
||||
}
|
||||
|
||||
@@ -318,9 +245,7 @@ impl Compiler {
|
||||
///
|
||||
/// Returns [`Error::SyntaxError`] if the source code is invalid.
|
||||
pub fn compile(&self, source: impl AsRef<[u8]>) -> Result<Vec<u8>> {
|
||||
use std::cell::RefCell;
|
||||
use std::ffi::CStr;
|
||||
use std::os::raw::{c_char, c_int};
|
||||
use std::os::raw::c_int;
|
||||
use std::ptr;
|
||||
|
||||
let vector_lib = self.vector_lib.clone();
|
||||
@@ -352,44 +277,6 @@ impl Compiler {
|
||||
|
||||
vec2cstring_ptr!(mutable_globals, mutable_globals_ptr);
|
||||
vec2cstring_ptr!(userdata_types, userdata_types_ptr);
|
||||
vec2cstring_ptr!(libraries_with_known_members, libraries_with_known_members_ptr);
|
||||
vec2cstring_ptr!(disabled_builtins, disabled_builtins_ptr);
|
||||
|
||||
thread_local! {
|
||||
static LIBRARY_MEMBER_CONSTANT_MAP: RefCell<LibraryMemberConstantMap> = Default::default();
|
||||
}
|
||||
|
||||
#[cfg(feature = "luau")]
|
||||
unsafe extern "C-unwind" fn library_member_constant_callback(
|
||||
library: *const c_char,
|
||||
member: *const c_char,
|
||||
constant: *mut ffi::lua_CompileConstant,
|
||||
) {
|
||||
let library = CStr::from_ptr(library).to_string_lossy();
|
||||
let member = CStr::from_ptr(member).to_string_lossy();
|
||||
LIBRARY_MEMBER_CONSTANT_MAP.with_borrow(|map| {
|
||||
if let Some(cons) = map.get(&(library.to_string(), member.to_string())) {
|
||||
match cons {
|
||||
CompileConstant::Nil => ffi::luau_set_compile_constant_nil(constant),
|
||||
CompileConstant::Boolean(b) => {
|
||||
ffi::luau_set_compile_constant_boolean(constant, *b as c_int)
|
||||
}
|
||||
CompileConstant::Number(n) => ffi::luau_set_compile_constant_number(constant, *n),
|
||||
CompileConstant::Vector(v) => {
|
||||
#[cfg(not(feature = "luau-vector4"))]
|
||||
ffi::luau_set_compile_constant_vector(constant, v.x(), v.y(), v.z(), 0.0);
|
||||
#[cfg(feature = "luau-vector4")]
|
||||
ffi::luau_set_compile_constant_vector(constant, v.x(), v.y(), v.z(), v.w());
|
||||
}
|
||||
CompileConstant::String(s) => ffi::luau_set_compile_constant_string(
|
||||
constant,
|
||||
s.as_ptr() as *const c_char,
|
||||
s.len(),
|
||||
),
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
let bytecode = unsafe {
|
||||
let mut options = ffi::lua_CompileOptions::default();
|
||||
@@ -402,14 +289,6 @@ impl Compiler {
|
||||
options.vectorType = vector_type.map_or(ptr::null(), |s| s.as_ptr());
|
||||
options.mutableGlobals = mutable_globals_ptr;
|
||||
options.userdataTypes = userdata_types_ptr;
|
||||
options.librariesWithKnownMembers = libraries_with_known_members_ptr;
|
||||
if let Some(map) = self.library_constants.as_ref() {
|
||||
if !self.libraries_with_known_members.is_empty() {
|
||||
LIBRARY_MEMBER_CONSTANT_MAP.with_borrow_mut(|gmap| *gmap = map.clone());
|
||||
options.libraryMemberConstantCallback = Some(library_member_constant_callback);
|
||||
}
|
||||
}
|
||||
options.disabledBuiltins = disabled_builtins_ptr;
|
||||
ffi::luau_compile(source.as_ref(), options)
|
||||
};
|
||||
|
||||
@@ -482,6 +361,8 @@ impl Chunk<'_> {
|
||||
/// Sets or overwrites a Luau compiler used for this chunk.
|
||||
///
|
||||
/// See [`Compiler`] for details and possible options.
|
||||
///
|
||||
/// Requires `feature = "luau"`
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
pub fn set_compiler(mut self, compiler: Compiler) -> Self {
|
||||
@@ -500,6 +381,8 @@ impl Chunk<'_> {
|
||||
///
|
||||
/// See [`exec`] for more details.
|
||||
///
|
||||
/// Requires `feature = "async"`
|
||||
///
|
||||
/// [`exec`]: Chunk::exec
|
||||
#[cfg(feature = "async")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||
@@ -530,6 +413,8 @@ impl Chunk<'_> {
|
||||
///
|
||||
/// See [`eval`] for more details.
|
||||
///
|
||||
/// Requires `feature = "async"`
|
||||
///
|
||||
/// [`eval`]: Chunk::eval
|
||||
#[cfg(feature = "async")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||
@@ -557,6 +442,8 @@ impl Chunk<'_> {
|
||||
///
|
||||
/// See [`call`] for more details.
|
||||
///
|
||||
/// Requires `feature = "async"`
|
||||
///
|
||||
/// [`call`]: Chunk::call
|
||||
#[cfg(feature = "async")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||
@@ -634,10 +521,10 @@ impl Chunk<'_> {
|
||||
if self.detect_mode() == ChunkMode::Binary {
|
||||
let lua = self.lua.lock();
|
||||
if let Some(mut cache) = lua.app_data_mut_unguarded::<ChunksCache>() {
|
||||
cache.0.insert(text_source, binary_source.to_vec());
|
||||
cache.0.insert(text_source, binary_source.as_ref().to_vec());
|
||||
} else {
|
||||
let mut cache = ChunksCache(HashMap::new());
|
||||
cache.0.insert(text_source, binary_source.to_vec());
|
||||
cache.0.insert(text_source, binary_source.as_ref().to_vec());
|
||||
let _ = lua.try_set_app_data(cache);
|
||||
};
|
||||
}
|
||||
@@ -671,20 +558,21 @@ impl Chunk<'_> {
|
||||
}
|
||||
|
||||
fn detect_mode(&self) -> ChunkMode {
|
||||
if let Some(mode) = self.mode {
|
||||
return mode;
|
||||
}
|
||||
if let Ok(source) = &self.source {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
if source.starts_with(ffi::LUA_SIGNATURE) {
|
||||
return ChunkMode::Binary;
|
||||
}
|
||||
#[cfg(feature = "luau")]
|
||||
if *source.first().unwrap_or(&u8::MAX) < b'\n' {
|
||||
return ChunkMode::Binary;
|
||||
match (self.mode, &self.source) {
|
||||
(Some(mode), _) => mode,
|
||||
(None, Ok(source)) => {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
if source.starts_with(ffi::LUA_SIGNATURE) {
|
||||
return ChunkMode::Binary;
|
||||
}
|
||||
#[cfg(feature = "luau")]
|
||||
if *source.first().unwrap_or(&u8::MAX) < b'\n' {
|
||||
return ChunkMode::Binary;
|
||||
}
|
||||
ChunkMode::Text
|
||||
}
|
||||
(None, Err(_)) => ChunkMode::Text, // any value is fine
|
||||
}
|
||||
ChunkMode::Text
|
||||
}
|
||||
|
||||
fn convert_name(name: String) -> Result<CString> {
|
||||
@@ -699,27 +587,29 @@ impl Chunk<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
struct WrappedChunk<T: AsChunk> {
|
||||
struct WrappedChunk<'a, T: AsChunk<'a>> {
|
||||
chunk: T,
|
||||
caller: &'static Location<'static>,
|
||||
_marker: PhantomData<&'a T>,
|
||||
}
|
||||
|
||||
impl Chunk<'_> {
|
||||
impl<'a> Chunk<'a> {
|
||||
/// Wraps a chunk of Lua code, returning an opaque type that implements [`IntoLua`] trait.
|
||||
///
|
||||
/// The resulted `IntoLua` implementation will convert the chunk into a Lua function without
|
||||
/// executing it.
|
||||
#[doc(hidden)]
|
||||
#[track_caller]
|
||||
pub fn wrap(chunk: impl AsChunk) -> impl IntoLua {
|
||||
pub fn wrap(chunk: impl AsChunk<'a> + 'a) -> impl IntoLua + 'a {
|
||||
WrappedChunk {
|
||||
chunk,
|
||||
caller: Location::caller(),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsChunk> IntoLua for WrappedChunk<T> {
|
||||
impl<'a, T: AsChunk<'a>> IntoLua for WrappedChunk<'a, T> {
|
||||
fn into_lua(self, lua: &Lua) -> Result<Value> {
|
||||
lua.load_with_location(self.chunk, self.caller)
|
||||
.into_function()
|
||||
|
||||
+31
-5
@@ -808,9 +808,15 @@ macro_rules! lua_convert_int {
|
||||
impl IntoLua for $x {
|
||||
#[inline]
|
||||
fn into_lua(self, _: &Lua) -> Result<Value> {
|
||||
Ok(cast(self)
|
||||
cast(self)
|
||||
.map(Value::Integer)
|
||||
.unwrap_or_else(|| Value::Number(self as ffi::lua_Number)))
|
||||
.or_else(|| cast(self).map(Value::Number))
|
||||
// This is impossible error because conversion to Number never fails
|
||||
.ok_or_else(|| Error::ToLuaConversionError {
|
||||
from: stringify!($x).to_string(),
|
||||
to: "number",
|
||||
message: Some("out of range".to_owned()),
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -893,7 +899,13 @@ macro_rules! lua_convert_float {
|
||||
impl IntoLua for $x {
|
||||
#[inline]
|
||||
fn into_lua(self, _: &Lua) -> Result<Value> {
|
||||
Ok(Value::Number(self as _))
|
||||
cast(self)
|
||||
.ok_or_else(|| Error::ToLuaConversionError {
|
||||
from: stringify!($x).to_string(),
|
||||
to: "number",
|
||||
message: Some("out of range".to_string()),
|
||||
})
|
||||
.map(Value::Number)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -902,19 +914,33 @@ macro_rules! lua_convert_float {
|
||||
fn from_lua(value: Value, lua: &Lua) -> Result<Self> {
|
||||
let ty = value.type_name();
|
||||
lua.coerce_number(value)?
|
||||
.map(|n| n as $x)
|
||||
.ok_or_else(|| Error::FromLuaConversionError {
|
||||
from: ty,
|
||||
to: stringify!($x).to_string(),
|
||||
message: Some("expected number or string coercible to number".to_string()),
|
||||
})
|
||||
.and_then(|n| {
|
||||
cast(n).ok_or_else(|| Error::FromLuaConversionError {
|
||||
from: ty,
|
||||
to: stringify!($x).to_string(),
|
||||
message: Some("number out of range".to_string()),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> {
|
||||
let state = lua.state();
|
||||
let type_id = ffi::lua_type(state, idx);
|
||||
if type_id == ffi::LUA_TNUMBER {
|
||||
return Ok(ffi::lua_tonumber(state, idx) as _);
|
||||
let mut ok = 0;
|
||||
let i = ffi::lua_tonumberx(state, idx, &mut ok);
|
||||
if ok != 0 {
|
||||
return cast(i).ok_or_else(|| Error::FromLuaConversionError {
|
||||
from: "number",
|
||||
to: stringify!($x).to_string(),
|
||||
message: Some("out of range".to_owned()),
|
||||
});
|
||||
}
|
||||
}
|
||||
// Fallback to default
|
||||
Self::from_lua(lua.stack_value(idx, Some(type_id)), lua.lua())
|
||||
|
||||
+16
-37
@@ -14,12 +14,9 @@ use crate::value::Value;
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
use {
|
||||
crate::thread::AsyncThread,
|
||||
crate::traits::LuaNativeAsyncFn,
|
||||
crate::types::AsyncCallback,
|
||||
std::future::{self, Future},
|
||||
std::pin::Pin,
|
||||
std::task::{Context, Poll},
|
||||
};
|
||||
|
||||
/// Handle to an internal Lua function.
|
||||
@@ -131,8 +128,9 @@ impl Function {
|
||||
/// Returns a future that, when polled, calls `self`, passing `args` as function arguments,
|
||||
/// and drives the execution.
|
||||
///
|
||||
/// Internally it wraps the function to an [`AsyncThread`]. The returned type implements
|
||||
/// `Future<Output = Result<R>>` and can be awaited.
|
||||
/// Internally it wraps the function to an [`AsyncThread`].
|
||||
///
|
||||
/// Requires `feature = "async"`
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -157,18 +155,19 @@ impl Function {
|
||||
/// [`AsyncThread`]: crate::AsyncThread
|
||||
#[cfg(feature = "async")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||
pub fn call_async<R>(&self, args: impl IntoLuaMulti) -> AsyncCallFuture<R>
|
||||
pub fn call_async<R>(&self, args: impl IntoLuaMulti) -> impl Future<Output = Result<R>>
|
||||
where
|
||||
R: FromLuaMulti,
|
||||
{
|
||||
let lua = self.0.lua.lock();
|
||||
AsyncCallFuture(unsafe {
|
||||
lua.create_recycled_thread(self).and_then(|th| {
|
||||
let mut th = th.into_async(args)?;
|
||||
let thread_res = unsafe {
|
||||
lua.create_recycled_thread(self).map(|th| {
|
||||
let mut th = th.into_async(args);
|
||||
th.set_recyclable(true);
|
||||
Ok(th)
|
||||
th
|
||||
})
|
||||
})
|
||||
};
|
||||
async move { thread_res?.await }
|
||||
}
|
||||
|
||||
/// Returns a function that, when called, calls `self`, passing `args` as the first set of
|
||||
@@ -281,7 +280,7 @@ impl Function {
|
||||
// Traverse upvalues until we find the _ENV one
|
||||
match ffi::lua_getupvalue(state, -1, i) {
|
||||
s if s.is_null() => break,
|
||||
s if std::ffi::CStr::from_ptr(s as _) == c"_ENV" => break,
|
||||
s if std::ffi::CStr::from_ptr(s as _).to_bytes() == b"_ENV" => break,
|
||||
_ => ffi::lua_pop(state, 1),
|
||||
}
|
||||
}
|
||||
@@ -320,7 +319,7 @@ impl Function {
|
||||
for i in 1..=255 {
|
||||
match ffi::lua_getupvalue(state, -1, i) {
|
||||
s if s.is_null() => return Ok(false),
|
||||
s if std::ffi::CStr::from_ptr(s as _) == c"_ENV" => {
|
||||
s if std::ffi::CStr::from_ptr(s as _).to_bytes() == b"_ENV" => {
|
||||
ffi::lua_pop(state, 1);
|
||||
// Create an anonymous function with the new environment
|
||||
let f_with_env = lua
|
||||
@@ -431,6 +430,8 @@ impl Function {
|
||||
///
|
||||
/// Recording of coverage information is controlled by [`Compiler::set_coverage_level`] option.
|
||||
///
|
||||
/// Requires `feature = "luau"`
|
||||
///
|
||||
/// [`Compiler::set_coverage_level`]: crate::chunk::Compiler::set_coverage_level
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
@@ -490,6 +491,8 @@ impl Function {
|
||||
/// Copies the function prototype and all its upvalues to the
|
||||
/// newly created function.
|
||||
/// This function returns shallow clone (same handle) for Rust/C functions.
|
||||
///
|
||||
/// Requires `feature = "luau"`
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
pub fn deep_clone(&self) -> Self {
|
||||
@@ -641,27 +644,6 @@ impl LuaType for Function {
|
||||
const TYPE_ID: c_int = ffi::LUA_TFUNCTION;
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||
pub struct AsyncCallFuture<R: FromLuaMulti>(Result<AsyncThread<R>>);
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
impl<R: FromLuaMulti> Future for AsyncCallFuture<R> {
|
||||
type Output = Result<R>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
// Safety: We're not moving any pinned data
|
||||
let this = unsafe { self.get_unchecked_mut() };
|
||||
match &mut this.0 {
|
||||
Ok(thread) => {
|
||||
let pinned_thread = unsafe { Pin::new_unchecked(thread) };
|
||||
pinned_thread.poll(cx)
|
||||
}
|
||||
Err(err) => Poll::Ready(Err(err.clone())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod assertions {
|
||||
use super::*;
|
||||
@@ -670,7 +652,4 @@ mod assertions {
|
||||
static_assertions::assert_not_impl_any!(Function: Send);
|
||||
#[cfg(feature = "send")]
|
||||
static_assertions::assert_impl_all!(Function: Send, Sync);
|
||||
|
||||
#[cfg(all(feature = "async", feature = "send"))]
|
||||
static_assertions::assert_impl_all!(AsyncCallFuture<()>: Send);
|
||||
}
|
||||
|
||||
+4
-8
@@ -265,18 +265,14 @@ pub struct DebugStack {
|
||||
/// Number of upvalues.
|
||||
pub num_ups: u8,
|
||||
/// Number of parameters.
|
||||
///
|
||||
/// Requires `feature = "lua54/lua53/lua52/luau"`
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "luau"))]
|
||||
#[cfg_attr(
|
||||
docsrs,
|
||||
doc(cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "luau")))
|
||||
)]
|
||||
pub num_params: u8,
|
||||
/// Whether the function is a vararg function.
|
||||
///
|
||||
/// Requires `feature = "lua54/lua53/lua52/luau"`
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "luau"))]
|
||||
#[cfg_attr(
|
||||
docsrs,
|
||||
doc(cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "luau")))
|
||||
)]
|
||||
pub is_vararg: bool,
|
||||
}
|
||||
|
||||
|
||||
+4
-11
@@ -67,7 +67,6 @@
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![cfg_attr(not(send), allow(clippy::arc_with_non_send_sync))]
|
||||
#![allow(clippy::ptr_eq)]
|
||||
#![allow(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
@@ -78,7 +77,7 @@ mod conversion;
|
||||
mod error;
|
||||
mod function;
|
||||
mod hook;
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg(feature = "luau")]
|
||||
mod luau;
|
||||
mod memory;
|
||||
mod multi;
|
||||
@@ -128,13 +127,7 @@ pub use crate::hook::HookTriggers;
|
||||
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
pub use crate::{
|
||||
buffer::Buffer,
|
||||
chunk::{CompileConstant, Compiler},
|
||||
function::CoverageInfo,
|
||||
luau::{NavigateError, Require},
|
||||
vector::Vector,
|
||||
};
|
||||
pub use crate::{buffer::Buffer, chunk::Compiler, function::CoverageInfo, vector::Vector};
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||
@@ -217,7 +210,7 @@ pub use mlua_derive::FromLua;
|
||||
///
|
||||
/// You can register multiple entrypoints as required.
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// use mlua::{Lua, Result, Table};
|
||||
///
|
||||
/// #[mlua::lua_module]
|
||||
@@ -254,7 +247,7 @@ pub use mlua_derive::FromLua;
|
||||
/// ...
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(any(feature = "module", docsrs))]
|
||||
#[cfg(all(feature = "mlua_derive", any(feature = "module", doc)))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "module")))]
|
||||
pub use mlua_derive::lua_module;
|
||||
|
||||
|
||||
+8
-16
@@ -2,22 +2,11 @@ use std::ffi::CStr;
|
||||
use std::os::raw::c_int;
|
||||
|
||||
use crate::error::Result;
|
||||
use crate::function::Function;
|
||||
use crate::state::Lua;
|
||||
|
||||
pub use require::{NavigateError, Require};
|
||||
|
||||
// Since Luau has some missing standard functions, we re-implement them here
|
||||
|
||||
impl Lua {
|
||||
/// Create a custom Luau `require` function using provided [`Require`] implementation to find
|
||||
/// and load modules.
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
pub fn create_require_function<R: Require + 'static>(&self, require: R) -> Result<Function> {
|
||||
require::create_require_function(self, require)
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn configure_luau(&self) -> Result<()> {
|
||||
let globals = self.globals();
|
||||
|
||||
@@ -29,10 +18,11 @@ impl Lua {
|
||||
globals.raw_set("_VERSION", format!("Luau {version}"))?;
|
||||
}
|
||||
|
||||
// Enable default `require` implementation
|
||||
let require = self.create_require_function(require::TextRequirer::new())?;
|
||||
self.globals().raw_set("require", require)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn disable_c_modules(&self) -> Result<()> {
|
||||
package::disable_dylibs(self);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -61,7 +51,7 @@ unsafe extern "C-unwind" fn lua_collectgarbage(state: *mut ffi::lua_State) -> c_
|
||||
1
|
||||
}
|
||||
Ok("step") => {
|
||||
let res = ffi::lua_gc(state, ffi::LUA_GCSTEP, arg as _);
|
||||
let res = ffi::lua_gc(state, ffi::LUA_GCSTEP, arg);
|
||||
ffi::lua_pushboolean(state, res);
|
||||
1
|
||||
}
|
||||
@@ -74,4 +64,6 @@ unsafe extern "C-unwind" fn lua_collectgarbage(state: *mut ffi::lua_State) -> c_
|
||||
}
|
||||
}
|
||||
|
||||
mod require;
|
||||
pub(crate) use package::register_package_module;
|
||||
|
||||
mod package;
|
||||
|
||||
@@ -0,0 +1,271 @@
|
||||
use std::ffi::CStr;
|
||||
use std::fmt::Write;
|
||||
use std::os::raw::c_int;
|
||||
use std::path::{PathBuf, MAIN_SEPARATOR_STR};
|
||||
use std::string::String as StdString;
|
||||
use std::{env, fs};
|
||||
|
||||
use crate::chunk::ChunkMode;
|
||||
use crate::error::Result;
|
||||
use crate::state::Lua;
|
||||
use crate::table::Table;
|
||||
use crate::traits::IntoLua;
|
||||
use crate::value::Value;
|
||||
|
||||
#[cfg(unix)]
|
||||
use {libloading::Library, rustc_hash::FxHashMap};
|
||||
|
||||
//
|
||||
// Luau package module
|
||||
//
|
||||
|
||||
#[cfg(unix)]
|
||||
const TARGET_MLUA_LUAU_ABI_VERSION: u32 = 3;
|
||||
|
||||
#[cfg(all(unix, feature = "module"))]
|
||||
#[no_mangle]
|
||||
#[used]
|
||||
pub static MLUA_LUAU_ABI_VERSION: u32 = TARGET_MLUA_LUAU_ABI_VERSION;
|
||||
|
||||
// We keep reference to the loaded dylibs in application data
|
||||
#[cfg(unix)]
|
||||
struct LoadedDylibs(FxHashMap<PathBuf, Library>);
|
||||
|
||||
#[cfg(unix)]
|
||||
impl std::ops::Deref for LoadedDylibs {
|
||||
type Target = FxHashMap<PathBuf, Library>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
impl std::ops::DerefMut for LoadedDylibs {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn register_package_module(lua: &Lua) -> Result<()> {
|
||||
// Create the package table
|
||||
let package = lua.create_table()?;
|
||||
|
||||
// Set `package.path`
|
||||
let mut search_path = env::var("LUAU_PATH")
|
||||
.or_else(|_| env::var("LUA_PATH"))
|
||||
.unwrap_or_default();
|
||||
if search_path.is_empty() {
|
||||
search_path = "?.luau;?.lua".to_string();
|
||||
}
|
||||
package.raw_set("path", search_path)?;
|
||||
|
||||
// Set `package.cpath`
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let mut search_cpath = env::var("LUAU_CPATH")
|
||||
.or_else(|_| env::var("LUA_CPATH"))
|
||||
.unwrap_or_default();
|
||||
if search_cpath.is_empty() {
|
||||
if cfg!(any(target_os = "macos", target_os = "ios")) {
|
||||
search_cpath = "?.dylib".to_string();
|
||||
} else {
|
||||
search_cpath = "?.so".to_string();
|
||||
}
|
||||
}
|
||||
package.raw_set("cpath", search_cpath)?;
|
||||
}
|
||||
|
||||
// Set `package.loaded` (table with a list of loaded modules)
|
||||
let loaded = if let Ok(Some(loaded)) = lua.named_registry_value::<Option<Table>>("_LOADED") {
|
||||
package.raw_set("loaded", &loaded)?;
|
||||
loaded
|
||||
} else {
|
||||
let loaded = lua.create_table()?;
|
||||
package.raw_set("loaded", &loaded)?;
|
||||
lua.set_named_registry_value("_LOADED", &loaded)?;
|
||||
loaded
|
||||
};
|
||||
|
||||
// Set `package.loaders`
|
||||
let loaders = lua.create_sequence_from([lua.create_function(lua_loader)?])?;
|
||||
package.raw_set("loaders", &loaders)?;
|
||||
#[cfg(unix)]
|
||||
{
|
||||
loaders.push(lua.create_function(dylib_loader)?)?;
|
||||
lua.set_app_data(LoadedDylibs(FxHashMap::default()));
|
||||
}
|
||||
lua.set_named_registry_value("_LOADERS", loaders)?;
|
||||
|
||||
// Register the module and `require` function in globals
|
||||
let globals = lua.globals();
|
||||
globals.raw_set("package", &package)?;
|
||||
loaded.raw_set("package", package)?;
|
||||
globals.raw_set("require", unsafe { lua.create_c_function(lua_require)? })?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
pub(crate) fn disable_dylibs(lua: &Lua) {
|
||||
// Presence of `LoadedDylibs` in app data is used as a flag
|
||||
// to check whether binary modules are enabled
|
||||
#[cfg(unix)]
|
||||
lua.remove_app_data::<LoadedDylibs>();
|
||||
}
|
||||
|
||||
unsafe extern "C-unwind" fn lua_require(state: *mut ffi::lua_State) -> c_int {
|
||||
ffi::lua_settop(state, 1);
|
||||
let name = ffi::luaL_checkstring(state, 1);
|
||||
ffi::luaL_getsubtable(state, ffi::LUA_REGISTRYINDEX, cstr!("_LOADED")); // _LOADED is at index 2
|
||||
if ffi::lua_rawgetfield(state, 2, name) != ffi::LUA_TNIL {
|
||||
return 1; // module is already loaded
|
||||
}
|
||||
ffi::lua_pop(state, 1); // remove nil
|
||||
|
||||
// load the module
|
||||
let err_buf = ffi::lua_newuserdata_t::<StdString>(state);
|
||||
err_buf.write(StdString::new());
|
||||
ffi::luaL_getsubtable(state, ffi::LUA_REGISTRYINDEX, cstr!("_LOADERS")); // _LOADERS is at index 3
|
||||
for i in 1.. {
|
||||
if ffi::lua_rawgeti(state, -1, i) == ffi::LUA_TNIL {
|
||||
// no more loaders?
|
||||
if (&*err_buf).is_empty() {
|
||||
ffi::luaL_error(state, cstr!("module '%s' not found"), name);
|
||||
} else {
|
||||
let bytes = (&*err_buf).as_bytes();
|
||||
let extra = ffi::lua_pushlstring(state, bytes.as_ptr() as *const _, bytes.len());
|
||||
ffi::luaL_error(state, cstr!("module '%s' not found:%s"), name, extra);
|
||||
}
|
||||
}
|
||||
ffi::lua_pushvalue(state, 1); // name arg
|
||||
ffi::lua_call(state, 1, 2); // call loader
|
||||
match ffi::lua_type(state, -2) {
|
||||
ffi::LUA_TFUNCTION => break, // loader found
|
||||
ffi::LUA_TSTRING => {
|
||||
// error message
|
||||
let msg = ffi::lua_tostring(state, -2);
|
||||
let msg = CStr::from_ptr(msg).to_string_lossy();
|
||||
_ = write!(&mut *err_buf, "\n\t{msg}");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
ffi::lua_pop(state, 2); // remove both results
|
||||
}
|
||||
ffi::lua_pushvalue(state, 1); // name is 1st argument to module loader
|
||||
ffi::lua_rotate(state, -2, 1); // loader data <-> name
|
||||
|
||||
// stack: ...; loader function; module name; loader data
|
||||
ffi::lua_call(state, 2, 1);
|
||||
// stack: ...; result from loader function
|
||||
if ffi::lua_isnil(state, -1) != 0 {
|
||||
ffi::lua_pop(state, 1);
|
||||
ffi::lua_pushboolean(state, 1); // use true as result
|
||||
}
|
||||
ffi::lua_pushvalue(state, -1); // make copy of entrypoint result
|
||||
ffi::lua_setfield(state, 2, name); /* _LOADED[name] = returned value */
|
||||
1
|
||||
}
|
||||
|
||||
/// Searches for the given `name` in the given `path`.
|
||||
///
|
||||
/// `path` is a string containing a sequence of templates separated by semicolons.
|
||||
fn package_searchpath(name: &str, search_path: &str, try_prefix: bool) -> Option<PathBuf> {
|
||||
let mut names = vec![name.replace('.', MAIN_SEPARATOR_STR)];
|
||||
if try_prefix && name.contains('.') {
|
||||
let prefix = name.split_once('.').map(|(prefix, _)| prefix).unwrap();
|
||||
names.push(prefix.to_string());
|
||||
}
|
||||
for path in search_path.split(';') {
|
||||
for name in &names {
|
||||
let file_path = PathBuf::from(path.replace('?', name));
|
||||
if let Ok(true) = fs::metadata(&file_path).map(|m| m.is_file()) {
|
||||
return Some(file_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
//
|
||||
// Module loaders
|
||||
//
|
||||
|
||||
/// Tries to load a lua (text) file
|
||||
fn lua_loader(lua: &Lua, modname: StdString) -> Result<Value> {
|
||||
let package = {
|
||||
let loaded = lua.named_registry_value::<Table>("_LOADED")?;
|
||||
loaded.raw_get::<Table>("package")
|
||||
}?;
|
||||
let search_path = package.get::<StdString>("path").unwrap_or_default();
|
||||
|
||||
if let Some(file_path) = package_searchpath(&modname, &search_path, false) {
|
||||
match fs::read(&file_path) {
|
||||
Ok(buf) => {
|
||||
return lua
|
||||
.load(buf)
|
||||
.set_name(format!("={}", file_path.display()))
|
||||
.set_mode(ChunkMode::Text)
|
||||
.into_function()
|
||||
.map(Value::Function);
|
||||
}
|
||||
Err(err) => {
|
||||
return format!("cannot open '{}': {err}", file_path.display()).into_lua(lua);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Value::Nil)
|
||||
}
|
||||
|
||||
/// Tries to load a dynamic library
|
||||
#[cfg(unix)]
|
||||
fn dylib_loader(lua: &Lua, modname: StdString) -> Result<Value> {
|
||||
let package = {
|
||||
let loaded = lua.named_registry_value::<Table>("_LOADED")?;
|
||||
loaded.raw_get::<Table>("package")
|
||||
}?;
|
||||
let search_cpath = package.get::<StdString>("cpath").unwrap_or_default();
|
||||
|
||||
let find_symbol = |lib: &Library| unsafe {
|
||||
if let Ok(entry) = lib.get::<ffi::lua_CFunction>(format!("luaopen_{modname}\0").as_bytes()) {
|
||||
return lua.create_c_function(*entry).map(Value::Function);
|
||||
}
|
||||
// Try all in one mode
|
||||
if let Ok(entry) =
|
||||
lib.get::<ffi::lua_CFunction>(format!("luaopen_{}\0", modname.replace('.', "_")).as_bytes())
|
||||
{
|
||||
return lua.create_c_function(*entry).map(Value::Function);
|
||||
}
|
||||
"cannot find module entrypoint".into_lua(lua)
|
||||
};
|
||||
|
||||
if let Some(file_path) = package_searchpath(&modname, &search_cpath, true) {
|
||||
let file_path = file_path.canonicalize()?;
|
||||
// Load the library and check for symbol
|
||||
unsafe {
|
||||
let mut loaded_dylibs = match lua.app_data_mut::<LoadedDylibs>() {
|
||||
Some(loaded_dylibs) => loaded_dylibs,
|
||||
None => return "dynamic libraries are disabled in safe mode".into_lua(lua),
|
||||
};
|
||||
// Check if it's already loaded
|
||||
if let Some(lib) = loaded_dylibs.get(&file_path) {
|
||||
return find_symbol(lib);
|
||||
}
|
||||
if let Ok(lib) = Library::new(&file_path) {
|
||||
// Check version
|
||||
let mod_version = lib.get::<*const u32>(b"MLUA_LUAU_ABI_VERSION");
|
||||
let mod_version = mod_version.map(|v| **v).unwrap_or_default();
|
||||
if mod_version != TARGET_MLUA_LUAU_ABI_VERSION {
|
||||
let err = format!("wrong module ABI version (expected {TARGET_MLUA_LUAU_ABI_VERSION}, got {mod_version})");
|
||||
return err.into_lua(lua);
|
||||
}
|
||||
let symbol = find_symbol(&lib);
|
||||
loaded_dylibs.insert(file_path, lib);
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Value::Nil)
|
||||
}
|
||||
@@ -1,644 +0,0 @@
|
||||
use std::cell::RefCell;
|
||||
use std::collections::VecDeque;
|
||||
use std::ffi::CStr;
|
||||
use std::io::Result as IoResult;
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
use std::path::{Component, Path, PathBuf};
|
||||
use std::result::Result as StdResult;
|
||||
use std::{env, fmt, fs, mem, ptr};
|
||||
|
||||
use crate::error::Result;
|
||||
use crate::function::Function;
|
||||
use crate::state::{callback_error_ext, Lua};
|
||||
use crate::table::Table;
|
||||
use crate::types::MaybeSend;
|
||||
|
||||
/// An error that can occur during navigation in the Luau `require` system.
|
||||
pub enum NavigateError {
|
||||
Ambiguous,
|
||||
NotFound,
|
||||
}
|
||||
|
||||
#[cfg(feature = "luau")]
|
||||
trait IntoNavigateResult {
|
||||
fn into_nav_result(self) -> ffi::luarequire_NavigateResult;
|
||||
}
|
||||
|
||||
#[cfg(feature = "luau")]
|
||||
impl IntoNavigateResult for StdResult<(), NavigateError> {
|
||||
fn into_nav_result(self) -> ffi::luarequire_NavigateResult {
|
||||
match self {
|
||||
Ok(()) => ffi::luarequire_NavigateResult::Success,
|
||||
Err(NavigateError::Ambiguous) => ffi::luarequire_NavigateResult::Ambiguous,
|
||||
Err(NavigateError::NotFound) => ffi::luarequire_NavigateResult::NotFound,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "luau")]
|
||||
type WriteResult = ffi::luarequire_WriteResult;
|
||||
|
||||
/// A trait for handling modules loading and navigation in the Luau `require` system.
|
||||
pub trait Require: MaybeSend {
|
||||
/// Returns `true` if "require" is permitted for the given chunk name.
|
||||
fn is_require_allowed(&self, chunk_name: &str) -> bool;
|
||||
|
||||
/// Resets the internal state to point at the requirer module.
|
||||
fn reset(&self, chunk_name: &str) -> StdResult<(), NavigateError>;
|
||||
|
||||
/// Resets the internal state to point at an aliased module.
|
||||
///
|
||||
/// This function received an exact path from a configuration file.
|
||||
/// It's only called when an alias's path cannot be resolved relative to its
|
||||
/// configuration file.
|
||||
fn jump_to_alias(&self, path: &str) -> StdResult<(), NavigateError>;
|
||||
|
||||
// Navigate to parent directory
|
||||
fn to_parent(&self) -> StdResult<(), NavigateError>;
|
||||
|
||||
/// Navigate to the given child directory.
|
||||
fn to_child(&self, name: &str) -> StdResult<(), NavigateError>;
|
||||
|
||||
/// Returns whether the context is currently pointing at a module
|
||||
fn is_module_present(&self) -> bool;
|
||||
|
||||
/// Returns the contents of the current module
|
||||
///
|
||||
/// This function is only called if `is_module_present` returns true.
|
||||
fn contents(&self) -> IoResult<Vec<u8>>;
|
||||
|
||||
/// Returns a chunk name for the current module.
|
||||
///
|
||||
/// This function is only called if `is_module_present` returns true.
|
||||
/// The chunk name is used to identify the module using the debug library.
|
||||
fn chunk_name(&self) -> String;
|
||||
|
||||
/// Provides a cache key representing the current module.
|
||||
///
|
||||
/// This function is only called if `is_module_present` returns true.
|
||||
fn cache_key(&self) -> Vec<u8>;
|
||||
|
||||
/// Returns whether a configuration file is present in the current context.
|
||||
fn is_config_present(&self) -> bool;
|
||||
|
||||
/// Returns the contents of the configuration file in the current context.
|
||||
///
|
||||
/// This function is only called if `is_config_present` returns true.
|
||||
fn config(&self) -> IoResult<Vec<u8>>;
|
||||
|
||||
/// Returns a loader that when called, loads the module and returns the result.
|
||||
///
|
||||
/// Loader can be sync or async.
|
||||
fn loader(&self, lua: &Lua, path: &str, chunk_name: &str, content: &[u8]) -> Result<Function> {
|
||||
let _ = path;
|
||||
lua.load(content).set_name(chunk_name).into_function()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for dyn Require {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "<dyn Require>")
|
||||
}
|
||||
}
|
||||
|
||||
/// The standard implementation of Luau `require` navigation.
|
||||
#[derive(Default)]
|
||||
pub(super) struct TextRequirer {
|
||||
abs_path: RefCell<PathBuf>,
|
||||
rel_path: RefCell<PathBuf>,
|
||||
module_path: RefCell<PathBuf>,
|
||||
}
|
||||
|
||||
impl TextRequirer {
|
||||
pub(super) fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
fn normalize_chunk_name(chunk_name: &str) -> &str {
|
||||
if let Some((path, line)) = chunk_name.split_once(':') {
|
||||
if line.parse::<u32>().is_ok() {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
chunk_name
|
||||
}
|
||||
|
||||
// Normalizes the path by removing unnecessary components
|
||||
fn normalize_path(path: &Path) -> PathBuf {
|
||||
let mut components = VecDeque::new();
|
||||
|
||||
for comp in path.components() {
|
||||
match comp {
|
||||
Component::Prefix(..) | Component::RootDir => {
|
||||
components.push_back(comp);
|
||||
}
|
||||
Component::CurDir => {}
|
||||
Component::ParentDir => {
|
||||
if matches!(components.back(), None | Some(Component::ParentDir)) {
|
||||
components.push_back(Component::ParentDir);
|
||||
} else if matches!(components.back(), Some(Component::Normal(..))) {
|
||||
components.pop_back();
|
||||
}
|
||||
}
|
||||
Component::Normal(..) => components.push_back(comp),
|
||||
}
|
||||
}
|
||||
|
||||
if matches!(components.front(), None | Some(Component::Normal(..))) {
|
||||
components.push_front(Component::CurDir);
|
||||
}
|
||||
|
||||
// Join the components back together
|
||||
components.into_iter().collect()
|
||||
}
|
||||
|
||||
fn find_module_path(path: &Path) -> StdResult<PathBuf, NavigateError> {
|
||||
let mut found_path = None;
|
||||
|
||||
let current_ext = (path.extension().and_then(|s| s.to_str()))
|
||||
.map(|s| format!("{s}."))
|
||||
.unwrap_or_default();
|
||||
for ext in ["luau", "lua"] {
|
||||
let candidate = path.with_extension(format!("{current_ext}{ext}"));
|
||||
if candidate.is_file() {
|
||||
if found_path.is_some() {
|
||||
return Err(NavigateError::Ambiguous);
|
||||
}
|
||||
found_path = Some(candidate);
|
||||
}
|
||||
}
|
||||
if path.is_dir() {
|
||||
if found_path.is_some() {
|
||||
return Err(NavigateError::Ambiguous);
|
||||
}
|
||||
|
||||
for component in ["init.luau", "init.lua"] {
|
||||
let candidate = path.join(component);
|
||||
if candidate.is_file() {
|
||||
if found_path.is_some() {
|
||||
return Err(NavigateError::Ambiguous);
|
||||
}
|
||||
found_path = Some(candidate);
|
||||
}
|
||||
}
|
||||
|
||||
if found_path.is_none() {
|
||||
found_path = Some(PathBuf::new());
|
||||
}
|
||||
}
|
||||
|
||||
found_path.ok_or(NavigateError::NotFound)
|
||||
}
|
||||
}
|
||||
|
||||
impl Require for TextRequirer {
|
||||
fn is_require_allowed(&self, chunk_name: &str) -> bool {
|
||||
chunk_name.starts_with('@')
|
||||
}
|
||||
|
||||
fn reset(&self, chunk_name: &str) -> StdResult<(), NavigateError> {
|
||||
if !chunk_name.starts_with('@') {
|
||||
return Err(NavigateError::NotFound);
|
||||
}
|
||||
let chunk_name = &Self::normalize_chunk_name(chunk_name)[1..];
|
||||
let path = Self::normalize_path(chunk_name.as_ref());
|
||||
|
||||
if path.extension() == Some("rs".as_ref()) {
|
||||
let cwd = match env::current_dir() {
|
||||
Ok(cwd) => cwd,
|
||||
Err(_) => return Err(NavigateError::NotFound),
|
||||
};
|
||||
self.abs_path.replace(Self::normalize_path(&cwd.join(&path)));
|
||||
self.rel_path.replace(path);
|
||||
self.module_path.replace(PathBuf::new());
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if path.is_absolute() {
|
||||
let module_path = Self::find_module_path(&path)?;
|
||||
self.abs_path.replace(path.clone());
|
||||
self.rel_path.replace(path);
|
||||
self.module_path.replace(module_path);
|
||||
} else {
|
||||
// Relative path
|
||||
let cwd = match env::current_dir() {
|
||||
Ok(cwd) => cwd,
|
||||
Err(_) => return Err(NavigateError::NotFound),
|
||||
};
|
||||
let abs_path = cwd.join(&path);
|
||||
let module_path = Self::find_module_path(&abs_path)?;
|
||||
self.abs_path.replace(Self::normalize_path(&abs_path));
|
||||
self.rel_path.replace(path);
|
||||
self.module_path.replace(module_path);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn jump_to_alias(&self, path: &str) -> StdResult<(), NavigateError> {
|
||||
let path = Self::normalize_path(path.as_ref());
|
||||
let module_path = Self::find_module_path(&path)?;
|
||||
|
||||
self.abs_path.replace(path.clone());
|
||||
self.rel_path.replace(path);
|
||||
self.module_path.replace(module_path);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn to_parent(&self) -> StdResult<(), NavigateError> {
|
||||
let mut abs_path = self.abs_path.borrow().clone();
|
||||
if !abs_path.pop() {
|
||||
return Err(NavigateError::NotFound);
|
||||
}
|
||||
let mut rel_parent = self.rel_path.borrow().clone();
|
||||
rel_parent.pop();
|
||||
let module_path = Self::find_module_path(&abs_path)?;
|
||||
|
||||
self.abs_path.replace(abs_path);
|
||||
self.rel_path.replace(Self::normalize_path(&rel_parent));
|
||||
self.module_path.replace(module_path);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn to_child(&self, name: &str) -> StdResult<(), NavigateError> {
|
||||
let abs_path = self.abs_path.borrow().join(name);
|
||||
let rel_path = self.rel_path.borrow().join(name);
|
||||
let module_path = Self::find_module_path(&abs_path)?;
|
||||
|
||||
self.abs_path.replace(abs_path);
|
||||
self.rel_path.replace(rel_path);
|
||||
self.module_path.replace(module_path);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn is_module_present(&self) -> bool {
|
||||
self.module_path.borrow().is_file()
|
||||
}
|
||||
|
||||
fn contents(&self) -> IoResult<Vec<u8>> {
|
||||
fs::read(&*self.module_path.borrow())
|
||||
}
|
||||
|
||||
fn chunk_name(&self) -> String {
|
||||
format!("@{}", self.rel_path.borrow().display())
|
||||
}
|
||||
|
||||
fn cache_key(&self) -> Vec<u8> {
|
||||
self.module_path.borrow().display().to_string().into_bytes()
|
||||
}
|
||||
|
||||
fn is_config_present(&self) -> bool {
|
||||
self.abs_path.borrow().join(".luaurc").is_file()
|
||||
}
|
||||
|
||||
fn config(&self) -> IoResult<Vec<u8>> {
|
||||
fs::read(self.abs_path.borrow().join(".luaurc"))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "luau")]
|
||||
pub(super) unsafe extern "C" fn init_config(config: *mut ffi::luarequire_Configuration) {
|
||||
if config.is_null() {
|
||||
return;
|
||||
}
|
||||
|
||||
unsafe extern "C" fn is_require_allowed(
|
||||
_state: *mut ffi::lua_State,
|
||||
ctx: *mut c_void,
|
||||
requirer_chunkname: *const c_char,
|
||||
) -> bool {
|
||||
if requirer_chunkname.is_null() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let this = &*(ctx as *const Box<dyn Require>);
|
||||
let chunk_name = CStr::from_ptr(requirer_chunkname).to_string_lossy();
|
||||
this.is_require_allowed(&chunk_name)
|
||||
}
|
||||
|
||||
unsafe extern "C" fn reset(
|
||||
_state: *mut ffi::lua_State,
|
||||
ctx: *mut c_void,
|
||||
requirer_chunkname: *const c_char,
|
||||
) -> ffi::luarequire_NavigateResult {
|
||||
let this = &*(ctx as *const Box<dyn Require>);
|
||||
let chunk_name = CStr::from_ptr(requirer_chunkname).to_string_lossy();
|
||||
this.reset(&chunk_name).into_nav_result()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn jump_to_alias(
|
||||
_state: *mut ffi::lua_State,
|
||||
ctx: *mut c_void,
|
||||
path: *const c_char,
|
||||
) -> ffi::luarequire_NavigateResult {
|
||||
let this = &*(ctx as *const Box<dyn Require>);
|
||||
let path = CStr::from_ptr(path).to_string_lossy();
|
||||
this.jump_to_alias(&path).into_nav_result()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn to_parent(
|
||||
_state: *mut ffi::lua_State,
|
||||
ctx: *mut c_void,
|
||||
) -> ffi::luarequire_NavigateResult {
|
||||
let this = &*(ctx as *const Box<dyn Require>);
|
||||
this.to_parent().into_nav_result()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn to_child(
|
||||
_state: *mut ffi::lua_State,
|
||||
ctx: *mut c_void,
|
||||
name: *const c_char,
|
||||
) -> ffi::luarequire_NavigateResult {
|
||||
let this = &*(ctx as *const Box<dyn Require>);
|
||||
let name = CStr::from_ptr(name).to_string_lossy();
|
||||
this.to_child(&name).into_nav_result()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn is_module_present(_state: *mut ffi::lua_State, ctx: *mut c_void) -> bool {
|
||||
let this = &*(ctx as *const Box<dyn Require>);
|
||||
this.is_module_present()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn get_contents(
|
||||
state: *mut ffi::lua_State,
|
||||
ctx: *mut c_void,
|
||||
buffer: *mut c_char,
|
||||
buffer_size: usize,
|
||||
size_out: *mut usize,
|
||||
) -> WriteResult {
|
||||
let this = &*(ctx as *const Box<dyn Require>);
|
||||
write_to_buffer(state, buffer, buffer_size, size_out, || this.contents())
|
||||
}
|
||||
|
||||
unsafe extern "C" fn get_chunkname(
|
||||
state: *mut ffi::lua_State,
|
||||
ctx: *mut c_void,
|
||||
buffer: *mut c_char,
|
||||
buffer_size: usize,
|
||||
size_out: *mut usize,
|
||||
) -> WriteResult {
|
||||
let this = &*(ctx as *const Box<dyn Require>);
|
||||
write_to_buffer(state, buffer, buffer_size, size_out, || {
|
||||
Ok(this.chunk_name().into_bytes())
|
||||
})
|
||||
}
|
||||
|
||||
unsafe extern "C" fn get_cache_key(
|
||||
state: *mut ffi::lua_State,
|
||||
ctx: *mut c_void,
|
||||
buffer: *mut c_char,
|
||||
buffer_size: usize,
|
||||
size_out: *mut usize,
|
||||
) -> WriteResult {
|
||||
let this = &*(ctx as *const Box<dyn Require>);
|
||||
write_to_buffer(state, buffer, buffer_size, size_out, || Ok(this.cache_key()))
|
||||
}
|
||||
|
||||
unsafe extern "C" fn is_config_present(_state: *mut ffi::lua_State, ctx: *mut c_void) -> bool {
|
||||
let this = &*(ctx as *const Box<dyn Require>);
|
||||
this.is_config_present()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn get_config(
|
||||
state: *mut ffi::lua_State,
|
||||
ctx: *mut c_void,
|
||||
buffer: *mut c_char,
|
||||
buffer_size: usize,
|
||||
size_out: *mut usize,
|
||||
) -> WriteResult {
|
||||
let this = &*(ctx as *const Box<dyn Require>);
|
||||
write_to_buffer(state, buffer, buffer_size, size_out, || this.config())
|
||||
}
|
||||
|
||||
unsafe extern "C-unwind" fn load(
|
||||
state: *mut ffi::lua_State,
|
||||
ctx: *mut c_void,
|
||||
path: *const c_char,
|
||||
chunk_name: *const c_char,
|
||||
contents: *const c_char,
|
||||
) -> c_int {
|
||||
let this = &*(ctx as *const Box<dyn Require>);
|
||||
let path = CStr::from_ptr(path).to_string_lossy();
|
||||
let chunk_name = CStr::from_ptr(chunk_name).to_string_lossy();
|
||||
let contents = CStr::from_ptr(contents).to_bytes();
|
||||
callback_error_ext(state, ptr::null_mut(), false, move |extra, _| {
|
||||
let rawlua = (*extra).raw_lua();
|
||||
rawlua.push(this.loader(rawlua.lua(), &path, &chunk_name, contents)?)?;
|
||||
Ok(1)
|
||||
})
|
||||
}
|
||||
|
||||
(*config).is_require_allowed = is_require_allowed;
|
||||
(*config).reset = reset;
|
||||
(*config).jump_to_alias = jump_to_alias;
|
||||
(*config).to_parent = to_parent;
|
||||
(*config).to_child = to_child;
|
||||
(*config).is_module_present = is_module_present;
|
||||
(*config).get_contents = get_contents;
|
||||
(*config).get_chunkname = get_chunkname;
|
||||
(*config).get_cache_key = get_cache_key;
|
||||
(*config).is_config_present = is_config_present;
|
||||
(*config).get_config = get_config;
|
||||
(*config).load = load;
|
||||
}
|
||||
|
||||
/// Helper function to write data to a buffer
|
||||
#[cfg(feature = "luau")]
|
||||
unsafe fn write_to_buffer(
|
||||
state: *mut ffi::lua_State,
|
||||
buffer: *mut c_char,
|
||||
buffer_size: usize,
|
||||
size_out: *mut usize,
|
||||
data_fetcher: impl Fn() -> IoResult<Vec<u8>>,
|
||||
) -> WriteResult {
|
||||
struct DataCache(Option<Vec<u8>>);
|
||||
|
||||
// The initial buffer size can be too small, to avoid making a second data fetch call,
|
||||
// we cache the content in the first call, and then re-use it.
|
||||
|
||||
let lua = Lua::get_or_init_from_ptr(state);
|
||||
match lua.try_app_data_mut::<DataCache>() {
|
||||
Ok(Some(mut data_cache)) => {
|
||||
if let Some(data) = data_cache.0.take() {
|
||||
mlua_assert!(data.len() <= buffer_size, "buffer is too small");
|
||||
*size_out = data.len();
|
||||
ptr::copy_nonoverlapping(data.as_ptr(), buffer as *mut _, data.len());
|
||||
return WriteResult::Success;
|
||||
}
|
||||
}
|
||||
Ok(None) => {
|
||||
// Init the cache
|
||||
_ = lua.try_set_app_data(DataCache(None));
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
|
||||
match data_fetcher() {
|
||||
Ok(data) => {
|
||||
*size_out = data.len();
|
||||
if *size_out > buffer_size {
|
||||
// Cache the data for the next call to avoid getting the contents again
|
||||
if let Ok(Some(mut data_cache)) = lua.try_app_data_mut::<DataCache>() {
|
||||
data_cache.0 = Some(data);
|
||||
}
|
||||
return WriteResult::BufferTooSmall;
|
||||
}
|
||||
ptr::copy_nonoverlapping(data.as_ptr(), buffer as *mut _, data.len());
|
||||
WriteResult::Success
|
||||
}
|
||||
Err(_) => WriteResult::Failure,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "luau")]
|
||||
pub fn create_require_function<R: Require + 'static>(lua: &Lua, require: R) -> Result<Function> {
|
||||
unsafe extern "C-unwind" fn find_current_file(state: *mut ffi::lua_State) -> c_int {
|
||||
let mut ar: ffi::lua_Debug = mem::zeroed();
|
||||
for level in 2.. {
|
||||
if ffi::lua_getinfo(state, level, cstr!("s"), &mut ar) == 0 {
|
||||
ffi::luaL_error(state, cstr!("require is not supported in this context"));
|
||||
}
|
||||
if CStr::from_ptr(ar.what) != c"C" {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ffi::lua_pushstring(state, ar.source);
|
||||
1
|
||||
}
|
||||
|
||||
unsafe extern "C-unwind" fn get_cache_key(state: *mut ffi::lua_State) -> c_int {
|
||||
let requirer = ffi::lua_touserdata(state, ffi::lua_upvalueindex(1)) as *const Box<dyn Require>;
|
||||
let cache_key = (*requirer).cache_key();
|
||||
ffi::lua_pushlstring(state, cache_key.as_ptr() as *const _, cache_key.len());
|
||||
1
|
||||
}
|
||||
|
||||
let (get_cache_key, find_current_file, proxyrequire, registered_modules, loader_cache) = unsafe {
|
||||
lua.exec_raw::<(Function, Function, Function, Table, Table)>((), move |state| {
|
||||
let requirer_ptr = ffi::lua_newuserdata_t::<Box<dyn Require>>(state, Box::new(require));
|
||||
ffi::lua_pushcclosured(state, get_cache_key, cstr!("get_cache_key"), 1);
|
||||
ffi::lua_pushcfunctiond(state, find_current_file, cstr!("find_current_file"));
|
||||
ffi::luarequire_pushproxyrequire(state, init_config, requirer_ptr as *mut _);
|
||||
ffi::luaL_getsubtable(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_REGISTERED_MODULES_TABLE);
|
||||
ffi::luaL_getsubtable(state, ffi::LUA_REGISTRYINDEX, cstr!("__MLUA_LOADER_CACHE"));
|
||||
})
|
||||
}?;
|
||||
|
||||
unsafe extern "C-unwind" fn error(state: *mut ffi::lua_State) -> c_int {
|
||||
ffi::luaL_where(state, 1);
|
||||
ffi::lua_pushvalue(state, 1);
|
||||
ffi::lua_concat(state, 2);
|
||||
ffi::lua_error(state);
|
||||
}
|
||||
|
||||
unsafe extern "C-unwind" fn r#type(state: *mut ffi::lua_State) -> c_int {
|
||||
ffi::lua_pushstring(state, ffi::lua_typename(state, ffi::lua_type(state, 1)));
|
||||
1
|
||||
}
|
||||
|
||||
let (error, r#type) = unsafe {
|
||||
lua.exec_raw::<(Function, Function)>((), move |state| {
|
||||
ffi::lua_pushcfunctiond(state, error, cstr!("error"));
|
||||
ffi::lua_pushcfunctiond(state, r#type, cstr!("type"));
|
||||
})
|
||||
}?;
|
||||
|
||||
// Prepare environment for the "require" function
|
||||
let env = lua.create_table_with_capacity(0, 7)?;
|
||||
env.raw_set("get_cache_key", get_cache_key)?;
|
||||
env.raw_set("find_current_file", find_current_file)?;
|
||||
env.raw_set("proxyrequire", proxyrequire)?;
|
||||
env.raw_set("REGISTERED_MODULES", registered_modules)?;
|
||||
env.raw_set("LOADER_CACHE", loader_cache)?;
|
||||
env.raw_set("error", error)?;
|
||||
env.raw_set("type", r#type)?;
|
||||
|
||||
lua.load(
|
||||
r#"
|
||||
local path = ...
|
||||
if type(path) ~= "string" then
|
||||
error("bad argument #1 to 'require' (string expected, got " .. type(path) .. ")")
|
||||
end
|
||||
|
||||
-- Check if the module (path) is explicitly registered
|
||||
local maybe_result = REGISTERED_MODULES[path]
|
||||
if maybe_result ~= nil then
|
||||
return maybe_result
|
||||
end
|
||||
|
||||
local loader = proxyrequire(path, find_current_file())
|
||||
local cache_key = get_cache_key()
|
||||
-- Check if the loader result is already cached
|
||||
local result = LOADER_CACHE[cache_key]
|
||||
if result ~= nil then
|
||||
return result
|
||||
end
|
||||
|
||||
-- Call the loader function and cache the result
|
||||
result = loader()
|
||||
if result == nil then
|
||||
result = true
|
||||
end
|
||||
LOADER_CACHE[cache_key] = result
|
||||
return result
|
||||
"#,
|
||||
)
|
||||
.try_cache()
|
||||
.set_name("=__mlua_require")
|
||||
.set_environment(env)
|
||||
.into_function()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::path::Path;
|
||||
|
||||
use super::TextRequirer;
|
||||
|
||||
#[test]
|
||||
fn test_path_normalize() {
|
||||
for (input, expected) in [
|
||||
// Basic formatting checks
|
||||
("", "./"),
|
||||
(".", "./"),
|
||||
("a/relative/path", "./a/relative/path"),
|
||||
// Paths containing extraneous '.' and '/' symbols
|
||||
("./remove/extraneous/symbols/", "./remove/extraneous/symbols"),
|
||||
("./remove/extraneous//symbols", "./remove/extraneous/symbols"),
|
||||
("./remove/extraneous/symbols/.", "./remove/extraneous/symbols"),
|
||||
("./remove/extraneous/./symbols", "./remove/extraneous/symbols"),
|
||||
("../remove/extraneous/symbols/", "../remove/extraneous/symbols"),
|
||||
("../remove/extraneous//symbols", "../remove/extraneous/symbols"),
|
||||
("../remove/extraneous/symbols/.", "../remove/extraneous/symbols"),
|
||||
("../remove/extraneous/./symbols", "../remove/extraneous/symbols"),
|
||||
("/remove/extraneous/symbols/", "/remove/extraneous/symbols"),
|
||||
("/remove/extraneous//symbols", "/remove/extraneous/symbols"),
|
||||
("/remove/extraneous/symbols/.", "/remove/extraneous/symbols"),
|
||||
("/remove/extraneous/./symbols", "/remove/extraneous/symbols"),
|
||||
// Paths containing '..'
|
||||
("./remove/me/..", "./remove"),
|
||||
("./remove/me/../", "./remove"),
|
||||
("../remove/me/..", "../remove"),
|
||||
("../remove/me/../", "../remove"),
|
||||
("/remove/me/..", "/remove"),
|
||||
("/remove/me/../", "/remove"),
|
||||
("./..", "../"),
|
||||
("./../", "../"),
|
||||
("../..", "../../"),
|
||||
("../../", "../../"),
|
||||
// '..' disappears if path is absolute and component is non-erasable
|
||||
("/../", "/"),
|
||||
] {
|
||||
let path = TextRequirer::normalize_path(input.as_ref());
|
||||
assert_eq!(
|
||||
&path,
|
||||
expected.as_ref() as &Path,
|
||||
"wrong normalization for {input}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -97,7 +97,7 @@ impl MemoryState {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn allocator(
|
||||
unsafe extern "C-unwind" fn allocator(
|
||||
extra: *mut c_void,
|
||||
ptr: *mut c_void,
|
||||
osize: usize,
|
||||
|
||||
+1
-4
@@ -22,10 +22,7 @@ pub use crate::HookTriggers as LuaHookTriggers;
|
||||
|
||||
#[cfg(feature = "luau")]
|
||||
#[doc(no_inline)]
|
||||
pub use crate::{
|
||||
CompileConstant as LuaCompileConstant, CoverageInfo as LuaCoverageInfo,
|
||||
NavigateError as LuaNavigateError, Require as LuaRequire, Vector as LuaVector,
|
||||
};
|
||||
pub use crate::{CoverageInfo as LuaCoverageInfo, Vector as LuaVector};
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[doc(no_inline)]
|
||||
|
||||
@@ -17,6 +17,8 @@ use crate::value::Value;
|
||||
pub trait LuaSerdeExt: Sealed {
|
||||
/// A special value (lightuserdata) to encode/decode optional (none) values.
|
||||
///
|
||||
/// Requires `feature = "serialize"`
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
@@ -40,6 +42,8 @@ pub trait LuaSerdeExt: Sealed {
|
||||
/// As result, encoded Array will contain only sequence part of the table, with the same length
|
||||
/// as the `#` operator on that table.
|
||||
///
|
||||
/// Requires `feature = "serialize"`
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
@@ -67,6 +71,8 @@ pub trait LuaSerdeExt: Sealed {
|
||||
|
||||
/// Converts `T` into a [`Value`] instance.
|
||||
///
|
||||
/// Requires `feature = "serialize"`
|
||||
///
|
||||
/// [`Value`]: crate::Value
|
||||
///
|
||||
/// # Example
|
||||
@@ -98,6 +104,8 @@ pub trait LuaSerdeExt: Sealed {
|
||||
|
||||
/// Converts `T` into a [`Value`] instance with options.
|
||||
///
|
||||
/// Requires `feature = "serialize"`
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
@@ -121,6 +129,8 @@ pub trait LuaSerdeExt: Sealed {
|
||||
|
||||
/// Deserializes a [`Value`] into any serde deserializable object.
|
||||
///
|
||||
/// Requires `feature = "serialize"`
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
@@ -148,6 +158,8 @@ pub trait LuaSerdeExt: Sealed {
|
||||
|
||||
/// Deserializes a [`Value`] into any serde deserializable object with options.
|
||||
///
|
||||
/// Requires `feature = "serialize"`
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
|
||||
+119
-240
@@ -2,7 +2,7 @@ use std::any::TypeId;
|
||||
use std::cell::{BorrowError, BorrowMutError, RefCell};
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Deref;
|
||||
use std::os::raw::{c_char, c_int};
|
||||
use std::os::raw::c_int;
|
||||
use std::panic::Location;
|
||||
use std::result::Result as StdResult;
|
||||
use std::{fmt, mem, ptr};
|
||||
@@ -30,7 +30,7 @@ use crate::util::{
|
||||
use crate::value::{Nil, Value};
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
use crate::{hook::HookTriggers, types::HookKind};
|
||||
use crate::hook::HookTriggers;
|
||||
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
use crate::{buffer::Buffer, chunk::Compiler};
|
||||
@@ -46,7 +46,7 @@ use serde::Serialize;
|
||||
|
||||
pub(crate) use extra::ExtraData;
|
||||
pub use raw::RawLua;
|
||||
pub(crate) use util::callback_error_ext;
|
||||
use util::callback_error_ext;
|
||||
|
||||
/// Top level Lua struct which represents an instance of Lua VM.
|
||||
pub struct Lua {
|
||||
@@ -74,6 +74,7 @@ pub(crate) struct LuaGuard(ArcReentrantMutexGuard<RawLua>);
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum GCMode {
|
||||
Incremental,
|
||||
/// Requires `feature = "lua54"`
|
||||
#[cfg(feature = "lua54")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "lua54")))]
|
||||
Generational,
|
||||
@@ -223,7 +224,6 @@ impl Lua {
|
||||
|
||||
let lua = unsafe { Self::inner_new(libs, options) };
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
if libs.contains(StdLib::PACKAGE) {
|
||||
mlua_expect!(lua.disable_c_modules(), "Error disabling C modules");
|
||||
}
|
||||
@@ -263,7 +263,7 @@ impl Lua {
|
||||
/// Creates a new Lua state with required `libs` and `options`
|
||||
unsafe fn inner_new(libs: StdLib, options: LuaOptions) -> Lua {
|
||||
let lua = Lua {
|
||||
raw: RawLua::new(libs, &options),
|
||||
raw: RawLua::new(libs, options),
|
||||
collect_garbage: true,
|
||||
};
|
||||
|
||||
@@ -273,23 +273,16 @@ impl Lua {
|
||||
lua
|
||||
}
|
||||
|
||||
/// Returns or constructs Lua instance from a raw state.
|
||||
/// Constructs a new Lua instance from an existing raw state.
|
||||
///
|
||||
/// Once initialized, the returned Lua instance is cached in the registry and can be retrieved
|
||||
/// Once called, a returned Lua state is cached in the registry and can be retrieved
|
||||
/// by calling this function again.
|
||||
///
|
||||
/// # Safety
|
||||
/// The `Lua` must outlive the chosen lifetime `'a`.
|
||||
#[allow(clippy::missing_safety_doc)]
|
||||
#[inline]
|
||||
pub unsafe fn get_or_init_from_ptr<'a>(state: *mut ffi::lua_State) -> &'a Lua {
|
||||
debug_assert!(!state.is_null(), "Lua state is null");
|
||||
match ExtraData::get(state) {
|
||||
extra if !extra.is_null() => (*extra).lua(),
|
||||
_ => {
|
||||
// The `owned` flag is set to `false` as we don't own the Lua state.
|
||||
RawLua::init_from_ptr(state, false);
|
||||
(*ExtraData::get(state)).lua()
|
||||
}
|
||||
pub unsafe fn init_from_ptr(state: *mut ffi::lua_State) -> Lua {
|
||||
Lua {
|
||||
raw: RawLua::init_from_ptr(state, false),
|
||||
collect_garbage: true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,6 +331,12 @@ impl Lua {
|
||||
R::from_stack_multi(nresults, &lua)
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[deprecated(since = "0.10.0", note = "please use `load_std_libs` instead")]
|
||||
pub fn load_from_std_lib(&self, libs: StdLib) -> Result<()> {
|
||||
self.load_std_libs(libs)
|
||||
}
|
||||
|
||||
/// Loads the specified subset of the standard libraries into an existing Lua state.
|
||||
///
|
||||
/// Use the [`StdLib`] flags to specify the libraries you want to load.
|
||||
@@ -345,78 +344,40 @@ impl Lua {
|
||||
unsafe { self.lock().load_std_libs(libs) }
|
||||
}
|
||||
|
||||
/// Registers module into an existing Lua state using the specified value.
|
||||
/// Loads module `modname` into an existing Lua state using the specified entrypoint
|
||||
/// function.
|
||||
///
|
||||
/// After registration, the given value will always be immediately returned when the
|
||||
/// given module is [required].
|
||||
/// Internally calls the Lua function `func` with the string `modname` as an argument,
|
||||
/// sets the call result to `package.loaded[modname]` and returns copy of the result.
|
||||
///
|
||||
/// [required]: https://www.lua.org/manual/5.4/manual.html#pdf-require
|
||||
pub fn register_module(&self, modname: &str, value: impl IntoLua) -> Result<()> {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
const LOADED_MODULES_KEY: *const c_char = ffi::LUA_LOADED_TABLE;
|
||||
#[cfg(feature = "luau")]
|
||||
const LOADED_MODULES_KEY: *const c_char = ffi::LUA_REGISTERED_MODULES_TABLE;
|
||||
|
||||
if cfg!(feature = "luau") && !modname.starts_with('@') {
|
||||
return Err(Error::runtime("module name must begin with '@'"));
|
||||
}
|
||||
unsafe {
|
||||
self.exec_raw::<()>(value, |state| {
|
||||
ffi::luaL_getsubtable(state, ffi::LUA_REGISTRYINDEX, LOADED_MODULES_KEY);
|
||||
ffi::lua_pushlstring(state, modname.as_ptr() as *const c_char, modname.len() as _);
|
||||
ffi::lua_pushvalue(state, -3);
|
||||
ffi::lua_rawset(state, -3);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Preloads module into an existing Lua state using the specified loader function.
|
||||
/// If `package.loaded[modname]` value is not nil, returns copy of the value without
|
||||
/// calling the function.
|
||||
///
|
||||
/// When the module is required, the loader function will be called with module name as the
|
||||
/// first argument.
|
||||
/// If the function does not return a non-nil value then this method assigns true to
|
||||
/// `package.loaded[modname]`.
|
||||
///
|
||||
/// This is similar to setting the [`package.preload[modname]`] field.
|
||||
/// Behavior is similar to Lua's [`require`] function.
|
||||
///
|
||||
/// [`package.preload[modname]`]: https://www.lua.org/manual/5.4/manual.html#pdf-package.preload
|
||||
#[cfg(not(feature = "luau"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
|
||||
pub fn preload_module(&self, modname: &str, func: Function) -> Result<()> {
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
let preload = unsafe {
|
||||
self.exec_raw::<Option<Table>>((), |state| {
|
||||
ffi::lua_getfield(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_PRELOAD_TABLE);
|
||||
})?
|
||||
};
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
let preload = unsafe {
|
||||
self.exec_raw::<Option<Table>>((), |state| {
|
||||
if ffi::lua_getfield(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_LOADED_TABLE) != ffi::LUA_TNIL {
|
||||
ffi::luaL_getsubtable(state, -1, ffi::LUA_LOADLIBNAME);
|
||||
ffi::luaL_getsubtable(state, -1, cstr!("preload"));
|
||||
ffi::lua_rotate(state, 1, 1);
|
||||
}
|
||||
})?
|
||||
};
|
||||
if let Some(preload) = preload {
|
||||
preload.raw_set(modname, func)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[deprecated(since = "0.11.0", note = "Use `register_module` instead")]
|
||||
#[cfg(not(feature = "luau"))]
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
pub fn load_from_function<T: FromLua>(&self, modname: &str, func: Function) -> Result<T> {
|
||||
/// [`require`]: https://www.lua.org/manual/5.4/manual.html#pdf-require
|
||||
pub fn load_from_function<T>(&self, modname: &str, func: Function) -> Result<T>
|
||||
where
|
||||
T: FromLua,
|
||||
{
|
||||
let lua = self.lock();
|
||||
let state = lua.state();
|
||||
let loaded = unsafe {
|
||||
self.exec_raw::<Table>((), |state| {
|
||||
ffi::luaL_getsubtable(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_LOADED_TABLE);
|
||||
})?
|
||||
let _sg = StackGuard::new(state);
|
||||
check_stack(state, 2)?;
|
||||
protect_lua!(state, 0, 1, fn(state) {
|
||||
ffi::luaL_getsubtable(state, ffi::LUA_REGISTRYINDEX, cstr!("_LOADED"));
|
||||
})?;
|
||||
Table(lua.pop_ref())
|
||||
};
|
||||
|
||||
let value = match loaded.raw_get(modname)? {
|
||||
let modname = unsafe { lua.create_string(modname)? };
|
||||
let value = match loaded.raw_get(&modname)? {
|
||||
Value::Nil => {
|
||||
let result = match func.call(modname)? {
|
||||
let result = match func.call(&modname)? {
|
||||
Value::Nil => Value::Boolean(true),
|
||||
res => res,
|
||||
};
|
||||
@@ -430,14 +391,24 @@ impl Lua {
|
||||
|
||||
/// Unloads module `modname`.
|
||||
///
|
||||
/// This method does not support unloading binary Lua modules since they are internally cached
|
||||
/// and can be unloaded only by closing Lua state.
|
||||
///
|
||||
/// This is similar to calling [`Lua::register_module`] with `Nil` value.
|
||||
/// Removes module from the [`package.loaded`] table which allows to load it again.
|
||||
/// It does not support unloading binary Lua modules since they are internally cached and can be
|
||||
/// unloaded only by closing Lua state.
|
||||
///
|
||||
/// [`package.loaded`]: https://www.lua.org/manual/5.4/manual.html#pdf-package.loaded
|
||||
pub fn unload_module(&self, modname: &str) -> Result<()> {
|
||||
self.register_module(modname, Nil)
|
||||
pub fn unload(&self, modname: &str) -> Result<()> {
|
||||
let lua = self.lock();
|
||||
let state = lua.state();
|
||||
let loaded = unsafe {
|
||||
let _sg = StackGuard::new(state);
|
||||
check_stack(state, 2)?;
|
||||
protect_lua!(state, 0, 1, fn(state) {
|
||||
ffi::luaL_getsubtable(state, ffi::LUA_REGISTRYINDEX, cstr!("_LOADED"));
|
||||
})?;
|
||||
Table(lua.pop_ref())
|
||||
};
|
||||
|
||||
loaded.raw_set(modname, Nil)
|
||||
}
|
||||
|
||||
// Executes module entrypoint function, which returns only one Value.
|
||||
@@ -451,9 +422,13 @@ impl Lua {
|
||||
R: IntoLua,
|
||||
{
|
||||
// Make sure that Lua is initialized
|
||||
let _ = Self::get_or_init_from_ptr(state);
|
||||
let mut lua = Self::init_from_ptr(state);
|
||||
lua.collect_garbage = false;
|
||||
// `Lua` is no longer needed and must be dropped at this point to avoid memory leak
|
||||
// in case of possible longjmp (lua_error) below
|
||||
drop(lua);
|
||||
|
||||
callback_error_ext(state, ptr::null_mut(), true, move |extra, nargs| {
|
||||
callback_error_ext(state, ptr::null_mut(), move |extra, nargs| {
|
||||
let rawlua = (*extra).raw_lua();
|
||||
let args = A::from_stack_args(nargs, 1, None, rawlua)?;
|
||||
func(rawlua.lua(), args)?.push_into_stack(rawlua)?;
|
||||
@@ -510,6 +485,8 @@ impl Lua {
|
||||
/// # #[cfg(not(feature = "luau"))]
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// Requires `feature = "luau"`
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
pub fn sandbox(&self, enabled: bool) -> Result<()> {
|
||||
@@ -535,26 +512,6 @@ impl Lua {
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets or replaces a global hook function that will periodically be called as Lua code
|
||||
/// executes.
|
||||
///
|
||||
/// All new threads created (by mlua) after this call will use the global hook function.
|
||||
///
|
||||
/// For more information see [`Lua::set_hook`].
|
||||
#[cfg(not(feature = "luau"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
|
||||
pub fn set_global_hook<F>(&self, triggers: HookTriggers, callback: F) -> Result<()>
|
||||
where
|
||||
F: Fn(&Lua, Debug) -> Result<VmState> + MaybeSend + 'static,
|
||||
{
|
||||
let lua = self.lock();
|
||||
unsafe {
|
||||
(*lua.extra.get()).hook_triggers = triggers;
|
||||
(*lua.extra.get()).hook_callback = Some(XRc::new(callback));
|
||||
lua.set_thread_hook(lua.state(), HookKind::Global)
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets a hook function that will periodically be called as Lua code executes.
|
||||
///
|
||||
/// When exactly the hook function is called depends on the contents of the `triggers`
|
||||
@@ -565,10 +522,12 @@ impl Lua {
|
||||
/// limited form of execution limits by setting [`HookTriggers.every_nth_instruction`] and
|
||||
/// erroring once an instruction limit has been reached.
|
||||
///
|
||||
/// This method sets a hook function for the *current* thread of this Lua instance.
|
||||
/// This method sets a hook function for the current thread of this Lua instance.
|
||||
/// If you want to set a hook function for another thread (coroutine), use
|
||||
/// [`Thread::set_hook`] instead.
|
||||
///
|
||||
/// Please note you cannot have more than one hook function set at a time for this Lua instance.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Shows each line number of code being executed by the Lua interpreter.
|
||||
@@ -593,28 +552,15 @@ impl Lua {
|
||||
/// [`HookTriggers.every_nth_instruction`]: crate::HookTriggers::every_nth_instruction
|
||||
#[cfg(not(feature = "luau"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
|
||||
pub fn set_hook<F>(&self, triggers: HookTriggers, callback: F) -> Result<()>
|
||||
pub fn set_hook<F>(&self, triggers: HookTriggers, callback: F)
|
||||
where
|
||||
F: Fn(&Lua, Debug) -> Result<VmState> + MaybeSend + 'static,
|
||||
{
|
||||
let lua = self.lock();
|
||||
unsafe { lua.set_thread_hook(lua.state(), HookKind::Thread(triggers, XRc::new(callback))) }
|
||||
unsafe { lua.set_thread_hook(lua.state(), triggers, callback) };
|
||||
}
|
||||
|
||||
/// Removes a global hook previously set by [`Lua::set_global_hook`].
|
||||
///
|
||||
/// This function has no effect if a hook was not previously set.
|
||||
#[cfg(not(feature = "luau"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
|
||||
pub fn remove_global_hook(&self) {
|
||||
let lua = self.lock();
|
||||
unsafe {
|
||||
(*lua.extra.get()).hook_callback = None;
|
||||
(*lua.extra.get()).hook_triggers = HookTriggers::default();
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes any hook from the current thread.
|
||||
/// Removes any hook previously set by [`Lua::set_hook`] or [`Thread::set_hook`].
|
||||
///
|
||||
/// This function has no effect if a hook was not previously set.
|
||||
#[cfg(not(feature = "luau"))]
|
||||
@@ -622,7 +568,17 @@ impl Lua {
|
||||
pub fn remove_hook(&self) {
|
||||
let lua = self.lock();
|
||||
unsafe {
|
||||
ffi::lua_sethook(lua.state(), None, 0, 0);
|
||||
let state = lua.state();
|
||||
ffi::lua_sethook(state, None, 0, 0);
|
||||
match lua.main_state {
|
||||
Some(main_state) if state != main_state.as_ptr() => {
|
||||
// If main_state is different from state, remove hook from it too
|
||||
ffi::lua_sethook(main_state.as_ptr(), None, 0, 0);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
(*lua.extra.get()).hook_callback = None;
|
||||
(*lua.extra.get()).hook_thread = ptr::null_mut();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -678,15 +634,17 @@ impl Lua {
|
||||
where
|
||||
F: Fn(&Lua) -> Result<VmState> + MaybeSend + 'static,
|
||||
{
|
||||
use std::rc::Rc;
|
||||
|
||||
unsafe extern "C-unwind" fn interrupt_proc(state: *mut ffi::lua_State, gc: c_int) {
|
||||
if gc >= 0 {
|
||||
// We don't support GC interrupts since they cannot survive Lua exceptions
|
||||
return;
|
||||
}
|
||||
let result = callback_error_ext(state, ptr::null_mut(), false, move |extra, _| {
|
||||
let result = callback_error_ext(state, ptr::null_mut(), move |extra, _| {
|
||||
let interrupt_cb = (*extra).interrupt_callback.clone();
|
||||
let interrupt_cb = mlua_expect!(interrupt_cb, "no interrupt callback set in interrupt_proc");
|
||||
if XRc::strong_count(&interrupt_cb) > 2 {
|
||||
if Rc::strong_count(&interrupt_cb) > 2 {
|
||||
return Ok(VmState::Continue); // Don't allow recursion
|
||||
}
|
||||
interrupt_cb((*extra).lua())
|
||||
@@ -702,7 +660,7 @@ impl Lua {
|
||||
// Set interrupt callback
|
||||
let lua = self.lock();
|
||||
unsafe {
|
||||
(*lua.extra.get()).interrupt_callback = Some(XRc::new(callback));
|
||||
(*lua.extra.get()).interrupt_callback = Some(Rc::new(callback));
|
||||
(*ffi::lua_callbacks(lua.main_state())).interrupt = Some(interrupt_proc);
|
||||
}
|
||||
}
|
||||
@@ -720,95 +678,9 @@ impl Lua {
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets a thread creation callback that will be called when a thread is created.
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
pub fn set_thread_creation_callback<F>(&self, callback: F)
|
||||
where
|
||||
F: Fn(&Lua, Thread) -> Result<()> + MaybeSend + 'static,
|
||||
{
|
||||
let lua = self.lock();
|
||||
unsafe {
|
||||
(*lua.extra.get()).thread_creation_callback = Some(XRc::new(callback));
|
||||
(*ffi::lua_callbacks(lua.main_state())).userthread = Some(Self::userthread_proc);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets a thread collection callback that will be called when a thread is destroyed.
|
||||
///
|
||||
/// Luau GC does not support exceptions during collection, so the callback must be
|
||||
/// non-panicking. If the callback panics, the program will be aborted.
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
pub fn set_thread_collection_callback<F>(&self, callback: F)
|
||||
where
|
||||
F: Fn(crate::LightUserData) + MaybeSend + 'static,
|
||||
{
|
||||
let lua = self.lock();
|
||||
unsafe {
|
||||
(*lua.extra.get()).thread_collection_callback = Some(XRc::new(callback));
|
||||
(*ffi::lua_callbacks(lua.main_state())).userthread = Some(Self::userthread_proc);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "luau")]
|
||||
unsafe extern "C-unwind" fn userthread_proc(parent: *mut ffi::lua_State, child: *mut ffi::lua_State) {
|
||||
let extra = ExtraData::get(child);
|
||||
if !parent.is_null() {
|
||||
// Thread is created
|
||||
let callback = match (*extra).thread_creation_callback {
|
||||
Some(ref cb) => cb.clone(),
|
||||
None => return,
|
||||
};
|
||||
if XRc::strong_count(&callback) > 2 {
|
||||
return; // Don't allow recursion
|
||||
}
|
||||
ffi::lua_pushthread(child);
|
||||
ffi::lua_xmove(child, (*extra).ref_thread, 1);
|
||||
let value = Thread((*extra).raw_lua().pop_ref_thread(), child);
|
||||
callback_error_ext(parent, extra, false, move |extra, _| {
|
||||
callback((*extra).lua(), value)
|
||||
})
|
||||
} else {
|
||||
// Thread is about to be collected
|
||||
let callback = match (*extra).thread_collection_callback {
|
||||
Some(ref cb) => cb.clone(),
|
||||
None => return,
|
||||
};
|
||||
|
||||
// We need to wrap the callback call in non-unwind function as it's not safe to unwind when
|
||||
// Luau GC is running.
|
||||
// This will trigger `abort()` if the callback panics.
|
||||
unsafe extern "C" fn run_callback(
|
||||
callback: *const crate::types::ThreadCollectionCallback,
|
||||
value: *mut ffi::lua_State,
|
||||
) {
|
||||
(*callback)(crate::LightUserData(value as _));
|
||||
}
|
||||
|
||||
(*extra).running_gc = true;
|
||||
run_callback(&callback, child);
|
||||
(*extra).running_gc = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes any thread creation or collection callbacks previously set by
|
||||
/// [`Lua::set_thread_creation_callback`] or [`Lua::set_thread_collection_callback`].
|
||||
///
|
||||
/// This function has no effect if a thread callbacks were not previously set.
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
pub fn remove_thread_callbacks(&self) {
|
||||
let lua = self.lock();
|
||||
unsafe {
|
||||
let extra = lua.extra.get();
|
||||
(*extra).thread_creation_callback = None;
|
||||
(*extra).thread_collection_callback = None;
|
||||
(*ffi::lua_callbacks(lua.main_state())).userthread = None;
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the warning function to be used by Lua to emit warnings.
|
||||
///
|
||||
/// Requires `feature = "lua54"`
|
||||
#[cfg(feature = "lua54")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "lua54")))]
|
||||
pub fn set_warning_function<F>(&self, callback: F)
|
||||
@@ -821,7 +693,7 @@ impl Lua {
|
||||
|
||||
unsafe extern "C-unwind" fn warn_proc(ud: *mut c_void, msg: *const c_char, tocont: c_int) {
|
||||
let extra = ud as *mut ExtraData;
|
||||
callback_error_ext((*extra).raw_lua().state(), extra, false, |extra, _| {
|
||||
callback_error_ext((*extra).raw_lua().state(), extra, |extra, _| {
|
||||
let warn_callback = (*extra).warn_callback.clone();
|
||||
let warn_callback = mlua_expect!(warn_callback, "no warning callback set in warn_proc");
|
||||
if XRc::strong_count(&warn_callback) > 2 {
|
||||
@@ -842,6 +714,8 @@ impl Lua {
|
||||
/// Removes warning function previously set by `set_warning_function`.
|
||||
///
|
||||
/// This function has no effect if a warning function was not previously set.
|
||||
///
|
||||
/// Requires `feature = "lua54"`
|
||||
#[cfg(feature = "lua54")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "lua54")))]
|
||||
pub fn remove_warning_function(&self) {
|
||||
@@ -856,6 +730,8 @@ impl Lua {
|
||||
///
|
||||
/// A message in a call with `incomplete` set to `true` should be continued in
|
||||
/// another call to this function.
|
||||
///
|
||||
/// Requires `feature = "lua54"`
|
||||
#[cfg(feature = "lua54")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "lua54")))]
|
||||
pub fn warning(&self, msg: impl AsRef<str>, incomplete: bool) {
|
||||
@@ -930,6 +806,8 @@ impl Lua {
|
||||
}
|
||||
|
||||
/// Returns `true` if the garbage collector is currently running automatically.
|
||||
///
|
||||
/// Requires `feature = "lua54/lua53/lua52/luau"`
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "luau"))]
|
||||
pub fn gc_is_running(&self) -> bool {
|
||||
let lua = self.lock();
|
||||
@@ -1067,6 +945,8 @@ impl Lua {
|
||||
/// Returns the previous mode. More information about the generational GC
|
||||
/// can be found in the Lua 5.4 [documentation][lua_doc].
|
||||
///
|
||||
/// Requires `feature = "lua54"`
|
||||
///
|
||||
/// [lua_doc]: https://www.lua.org/manual/5.4/manual.html#2.5.2
|
||||
#[cfg(feature = "lua54")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "lua54")))]
|
||||
@@ -1087,6 +967,8 @@ impl Lua {
|
||||
/// including via `require` function.
|
||||
///
|
||||
/// See [`Compiler`] for details and possible options.
|
||||
///
|
||||
/// Requires `feature = "luau"`
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
pub fn set_compiler(&self, compiler: Compiler) {
|
||||
@@ -1128,20 +1010,18 @@ impl Lua {
|
||||
///
|
||||
/// [`Chunk::exec`]: crate::Chunk::exec
|
||||
#[track_caller]
|
||||
pub fn load<'a>(&self, chunk: impl AsChunk + 'a) -> Chunk<'a> {
|
||||
pub fn load<'a>(&self, chunk: impl AsChunk<'a>) -> Chunk<'a> {
|
||||
self.load_with_location(chunk, Location::caller())
|
||||
}
|
||||
|
||||
pub(crate) fn load_with_location<'a>(
|
||||
&self,
|
||||
chunk: impl AsChunk + 'a,
|
||||
chunk: impl AsChunk<'a>,
|
||||
location: &'static Location<'static>,
|
||||
) -> Chunk<'a> {
|
||||
Chunk {
|
||||
lua: self.weak(),
|
||||
name: chunk
|
||||
.name()
|
||||
.unwrap_or_else(|| format!("@{}:{}", location.file(), location.line())),
|
||||
name: chunk.name().unwrap_or_else(|| location.to_string()),
|
||||
env: chunk.environment(self),
|
||||
mode: chunk.mode(),
|
||||
source: chunk.source(),
|
||||
@@ -1161,6 +1041,8 @@ impl Lua {
|
||||
|
||||
/// Create and return a Luau [buffer] object from a byte slice of data.
|
||||
///
|
||||
/// Requires `feature = "luau"`
|
||||
///
|
||||
/// [buffer]: https://luau.org/library#buffer-library
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
@@ -1325,6 +1207,8 @@ impl Lua {
|
||||
///
|
||||
/// The family of `call_async()` functions takes care about creating [`Thread`].
|
||||
///
|
||||
/// Requires `feature = "async"`
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Non blocking sleep:
|
||||
@@ -1390,6 +1274,8 @@ impl Lua {
|
||||
}
|
||||
|
||||
/// Creates a Lua userdata object from a custom serializable userdata type.
|
||||
///
|
||||
/// Requires `feature = "serialize"`
|
||||
#[cfg(feature = "serialize")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
|
||||
#[inline]
|
||||
@@ -1418,6 +1304,8 @@ impl Lua {
|
||||
/// Creates a Lua userdata object from a custom serializable Rust type.
|
||||
///
|
||||
/// See [`Lua::create_any_userdata`] for more details.
|
||||
///
|
||||
/// Requires `feature = "serialize"`
|
||||
#[cfg(feature = "serialize")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
|
||||
#[inline]
|
||||
@@ -1542,7 +1430,7 @@ impl Lua {
|
||||
Err(_) => return,
|
||||
},
|
||||
ffi::LUA_TTHREAD => {
|
||||
ffi::lua_pushthread(state);
|
||||
ffi::lua_newthread(state);
|
||||
}
|
||||
#[cfg(feature = "luau")]
|
||||
ffi::LUA_TBUFFER => {
|
||||
@@ -1600,9 +1488,10 @@ impl Lua {
|
||||
/// lifetimes only outlive the scope lifetime.
|
||||
pub fn scope<'env, R>(
|
||||
&self,
|
||||
f: impl for<'scope> FnOnce(&'scope Scope<'scope, 'env>) -> Result<R>,
|
||||
f: impl for<'scope> FnOnce(&'scope mut Scope<'scope, 'env>) -> Result<R>,
|
||||
) -> Result<R> {
|
||||
f(&Scope::new(self.lock_arc()))
|
||||
// TODO: Update to `&Scope` in next major release
|
||||
f(&mut Scope::new(self.lock_arc()))
|
||||
}
|
||||
|
||||
/// Attempts to coerce a Lua value into a String in a manner consistent with Lua's internal
|
||||
@@ -2075,12 +1964,7 @@ impl Lua {
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn lock(&self) -> ReentrantMutexGuard<RawLua> {
|
||||
let rawlua = self.raw.lock();
|
||||
#[cfg(feature = "luau")]
|
||||
if unsafe { (*rawlua.extra.get()).running_gc } {
|
||||
panic!("Luau VM is suspended while GC is running");
|
||||
}
|
||||
rawlua
|
||||
self.raw.lock()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@@ -2102,12 +1986,7 @@ impl WeakLua {
|
||||
#[track_caller]
|
||||
#[inline(always)]
|
||||
pub(crate) fn lock(&self) -> LuaGuard {
|
||||
let guard = LuaGuard::new(self.0.upgrade().expect("Lua instance is destroyed"));
|
||||
#[cfg(feature = "luau")]
|
||||
if unsafe { (*guard.extra.get()).running_gc } {
|
||||
panic!("Luau VM is suspended while GC is running");
|
||||
}
|
||||
guard
|
||||
LuaGuard::new(self.0.upgrade().expect("Lua instance is destroyed"))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
||||
+6
-15
@@ -75,18 +75,12 @@ pub(crate) struct ExtraData {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
pub(super) hook_callback: Option<crate::types::HookCallback>,
|
||||
#[cfg(not(feature = "luau"))]
|
||||
pub(super) hook_triggers: crate::hook::HookTriggers,
|
||||
pub(super) hook_thread: *mut ffi::lua_State,
|
||||
#[cfg(feature = "lua54")]
|
||||
pub(super) warn_callback: Option<crate::types::WarnCallback>,
|
||||
#[cfg(feature = "luau")]
|
||||
pub(super) interrupt_callback: Option<crate::types::InterruptCallback>,
|
||||
#[cfg(feature = "luau")]
|
||||
pub(super) thread_creation_callback: Option<crate::types::ThreadCreationCallback>,
|
||||
#[cfg(feature = "luau")]
|
||||
pub(super) thread_collection_callback: Option<crate::types::ThreadCollectionCallback>,
|
||||
|
||||
#[cfg(feature = "luau")]
|
||||
pub(crate) running_gc: bool,
|
||||
#[cfg(feature = "luau")]
|
||||
pub(super) sandboxed: bool,
|
||||
#[cfg(feature = "luau")]
|
||||
@@ -177,23 +171,17 @@ impl ExtraData {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
hook_callback: None,
|
||||
#[cfg(not(feature = "luau"))]
|
||||
hook_triggers: Default::default(),
|
||||
hook_thread: ptr::null_mut(),
|
||||
#[cfg(feature = "lua54")]
|
||||
warn_callback: None,
|
||||
#[cfg(feature = "luau")]
|
||||
interrupt_callback: None,
|
||||
#[cfg(feature = "luau")]
|
||||
thread_creation_callback: None,
|
||||
#[cfg(feature = "luau")]
|
||||
thread_collection_callback: None,
|
||||
#[cfg(feature = "luau")]
|
||||
sandboxed: false,
|
||||
#[cfg(feature = "luau")]
|
||||
compiler: None,
|
||||
#[cfg(feature = "luau-jit")]
|
||||
enable_jit: true,
|
||||
#[cfg(feature = "luau")]
|
||||
running_gc: false,
|
||||
}));
|
||||
|
||||
// Store it in the registry
|
||||
@@ -207,6 +195,9 @@ impl ExtraData {
|
||||
raw: XRc::clone(raw),
|
||||
collect_garbage: false,
|
||||
});
|
||||
if self.owned {
|
||||
XRc::decrement_strong_count(XRc::as_ptr(raw));
|
||||
}
|
||||
self.weak.write(WeakLua(XRc::downgrade(raw)));
|
||||
}
|
||||
|
||||
@@ -249,7 +240,7 @@ impl ExtraData {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) unsafe fn raw_lua(&self) -> &RawLua {
|
||||
pub(super) unsafe fn raw_lua(&self) -> &RawLua {
|
||||
&*self.lua.assume_init_ref().raw.data_ptr()
|
||||
}
|
||||
|
||||
|
||||
+71
-140
@@ -1,6 +1,6 @@
|
||||
use std::any::TypeId;
|
||||
use std::cell::{Cell, UnsafeCell};
|
||||
use std::ffi::CStr;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::mem;
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
use std::panic::resume_unwind;
|
||||
@@ -38,10 +38,7 @@ use super::extra::ExtraData;
|
||||
use super::{Lua, LuaOptions, WeakLua};
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
use crate::{
|
||||
hook::Debug,
|
||||
types::{HookCallback, HookKind, VmState},
|
||||
};
|
||||
use crate::hook::{Debug, HookTriggers};
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
use {
|
||||
@@ -58,25 +55,17 @@ pub struct RawLua {
|
||||
pub(super) state: Cell<*mut ffi::lua_State>,
|
||||
pub(super) main_state: Option<NonNull<ffi::lua_State>>,
|
||||
pub(super) extra: XRc<UnsafeCell<ExtraData>>,
|
||||
owned: bool,
|
||||
}
|
||||
|
||||
impl Drop for RawLua {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if !self.owned {
|
||||
if !(*self.extra.get()).owned {
|
||||
return;
|
||||
}
|
||||
|
||||
let mem_state = MemoryState::get(self.main_state());
|
||||
|
||||
#[cfg(feature = "luau")]
|
||||
{
|
||||
// Reset any callbacks
|
||||
(*ffi::lua_callbacks(self.main_state())).interrupt = None;
|
||||
(*ffi::lua_callbacks(self.main_state())).userthread = None;
|
||||
}
|
||||
|
||||
ffi::lua_close(self.main_state());
|
||||
|
||||
// Deallocate `MemoryState`
|
||||
@@ -121,7 +110,7 @@ impl RawLua {
|
||||
unsafe { (*self.extra.get()).ref_thread }
|
||||
}
|
||||
|
||||
pub(super) unsafe fn new(libs: StdLib, options: &LuaOptions) -> XRc<ReentrantMutex<Self>> {
|
||||
pub(super) unsafe fn new(libs: StdLib, options: LuaOptions) -> XRc<ReentrantMutex<Self>> {
|
||||
let mem_state: *mut MemoryState = Box::into_raw(Box::default());
|
||||
let mut state = ffi::lua_newstate(ALLOCATOR, mem_state as *mut c_void);
|
||||
// If state is null then switch to Lua internal allocator
|
||||
@@ -198,8 +187,6 @@ impl RawLua {
|
||||
init_internal_metatable::<XRc<UnsafeCell<ExtraData>>>(state, None)?;
|
||||
init_internal_metatable::<Callback>(state, None)?;
|
||||
init_internal_metatable::<CallbackUpvalue>(state, None)?;
|
||||
#[cfg(not(feature = "luau"))]
|
||||
init_internal_metatable::<HookCallback>(state, None)?;
|
||||
#[cfg(feature = "async")]
|
||||
{
|
||||
init_internal_metatable::<AsyncCallback>(state, None)?;
|
||||
@@ -241,17 +228,8 @@ impl RawLua {
|
||||
// Make sure that we don't store current state as main state (if it's not available)
|
||||
main_state: get_main_state(state).and_then(NonNull::new),
|
||||
extra: XRc::clone(&extra),
|
||||
owned,
|
||||
}));
|
||||
(*extra.get()).set_lua(&rawlua);
|
||||
if owned {
|
||||
// If Lua state is managed by us, then make internal `RawLua` reference "weak"
|
||||
XRc::decrement_strong_count(XRc::as_ptr(&rawlua));
|
||||
} else {
|
||||
// If Lua state is not managed by us, then keep internal `RawLua` reference "strong"
|
||||
// but `Extra` reference weak (it will be collected from registry at lua_close time)
|
||||
XRc::decrement_strong_count(XRc::as_ptr(&extra));
|
||||
}
|
||||
|
||||
rawlua
|
||||
}
|
||||
@@ -293,15 +271,10 @@ impl RawLua {
|
||||
let res = load_std_libs(self.main_state(), libs);
|
||||
|
||||
// If `package` library loaded into a safe lua state then disable C modules
|
||||
#[cfg(not(feature = "luau"))]
|
||||
if is_safe {
|
||||
let curr_libs = (*self.extra.get()).libs;
|
||||
if (curr_libs ^ (curr_libs | libs)).contains(StdLib::PACKAGE) {
|
||||
mlua_expect!(self.lua().disable_c_modules(), "Error during disabling C modules");
|
||||
}
|
||||
let curr_libs = (*self.extra.get()).libs;
|
||||
if is_safe && (curr_libs ^ (curr_libs | libs)).contains(StdLib::PACKAGE) {
|
||||
mlua_expect!(self.lua().disable_c_modules(), "Error during disabling C modules");
|
||||
}
|
||||
#[cfg(feature = "luau")]
|
||||
let _ = is_safe;
|
||||
unsafe { (*self.extra.get()).libs |= libs };
|
||||
|
||||
res
|
||||
@@ -401,29 +374,48 @@ impl RawLua {
|
||||
status
|
||||
}
|
||||
|
||||
/// Sets a hook for a thread (coroutine).
|
||||
/// Sets a 'hook' function for a thread (coroutine).
|
||||
#[cfg(not(feature = "luau"))]
|
||||
pub(crate) unsafe fn set_thread_hook(
|
||||
pub(crate) unsafe fn set_thread_hook<F>(
|
||||
&self,
|
||||
thread_state: *mut ffi::lua_State,
|
||||
hook: HookKind,
|
||||
) -> Result<()> {
|
||||
// Key to store hooks in the registry
|
||||
const HOOKS_KEY: *const c_char = cstr!("__mlua_hooks");
|
||||
state: *mut ffi::lua_State,
|
||||
triggers: HookTriggers,
|
||||
callback: F,
|
||||
) where
|
||||
F: Fn(&Lua, Debug) -> Result<crate::VmState> + MaybeSend + 'static,
|
||||
{
|
||||
use crate::types::VmState;
|
||||
use std::rc::Rc;
|
||||
|
||||
unsafe fn process_status(state: *mut ffi::lua_State, event: c_int, status: VmState) {
|
||||
match status {
|
||||
unsafe extern "C-unwind" fn hook_proc(state: *mut ffi::lua_State, ar: *mut ffi::lua_Debug) {
|
||||
let extra = ExtraData::get(state);
|
||||
if (*extra).hook_thread != state {
|
||||
// Hook was destined for a different thread, ignore
|
||||
ffi::lua_sethook(state, None, 0, 0);
|
||||
return;
|
||||
}
|
||||
let result = callback_error_ext(state, extra, move |extra, _| {
|
||||
let hook_cb = (*extra).hook_callback.clone();
|
||||
let hook_cb = mlua_expect!(hook_cb, "no hook callback set in hook_proc");
|
||||
if Rc::strong_count(&hook_cb) > 2 {
|
||||
return Ok(VmState::Continue); // Don't allow recursion
|
||||
}
|
||||
let rawlua = (*extra).raw_lua();
|
||||
let debug = Debug::new(rawlua, ar);
|
||||
hook_cb((*extra).lua(), debug)
|
||||
});
|
||||
match result {
|
||||
VmState::Continue => {}
|
||||
VmState::Yield => {
|
||||
// Only count and line events can yield
|
||||
if event == ffi::LUA_HOOKCOUNT || event == ffi::LUA_HOOKLINE {
|
||||
if (*ar).event == ffi::LUA_HOOKCOUNT || (*ar).event == ffi::LUA_HOOKLINE {
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
if ffi::lua_isyieldable(state) != 0 {
|
||||
ffi::lua_yield(state, 0);
|
||||
}
|
||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||
{
|
||||
ffi::lua_pushliteral(state, c"attempt to yield from a hook");
|
||||
ffi::lua_pushliteral(state, "attempt to yield from a hook");
|
||||
ffi::lua_error(state);
|
||||
}
|
||||
}
|
||||
@@ -431,83 +423,9 @@ impl RawLua {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C-unwind" fn global_hook_proc(state: *mut ffi::lua_State, ar: *mut ffi::lua_Debug) {
|
||||
let status = callback_error_ext(state, ptr::null_mut(), false, move |extra, _| {
|
||||
match (*extra).hook_callback.clone() {
|
||||
Some(hook_callback) => {
|
||||
let rawlua = (*extra).raw_lua();
|
||||
let debug = Debug::new(rawlua, ar);
|
||||
hook_callback((*extra).lua(), debug)
|
||||
}
|
||||
None => {
|
||||
ffi::lua_sethook(state, None, 0, 0);
|
||||
Ok(VmState::Continue)
|
||||
}
|
||||
}
|
||||
});
|
||||
process_status(state, (*ar).event, status);
|
||||
}
|
||||
|
||||
unsafe extern "C-unwind" fn hook_proc(state: *mut ffi::lua_State, ar: *mut ffi::lua_Debug) {
|
||||
let top = ffi::lua_gettop(state);
|
||||
let mut hook_callback_ptr = ptr::null();
|
||||
ffi::luaL_checkstack(state, 3, ptr::null());
|
||||
if ffi::lua_getfield(state, ffi::LUA_REGISTRYINDEX, HOOKS_KEY) == ffi::LUA_TTABLE {
|
||||
ffi::lua_pushthread(state);
|
||||
if ffi::lua_rawget(state, -2) == ffi::LUA_TUSERDATA {
|
||||
hook_callback_ptr = get_internal_userdata::<HookCallback>(state, -1, ptr::null());
|
||||
}
|
||||
}
|
||||
ffi::lua_settop(state, top);
|
||||
if hook_callback_ptr.is_null() {
|
||||
ffi::lua_sethook(state, None, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
let status = callback_error_ext(state, ptr::null_mut(), false, |extra, _| {
|
||||
let rawlua = (*extra).raw_lua();
|
||||
let debug = Debug::new(rawlua, ar);
|
||||
let hook_callback = (*hook_callback_ptr).clone();
|
||||
hook_callback((*extra).lua(), debug)
|
||||
});
|
||||
process_status(state, (*ar).event, status)
|
||||
}
|
||||
|
||||
let (triggers, callback) = match hook {
|
||||
HookKind::Global if (*self.extra.get()).hook_callback.is_none() => {
|
||||
return Ok(());
|
||||
}
|
||||
HookKind::Global => {
|
||||
let triggers = (*self.extra.get()).hook_triggers;
|
||||
let (mask, count) = (triggers.mask(), triggers.count());
|
||||
ffi::lua_sethook(thread_state, Some(global_hook_proc), mask, count);
|
||||
return Ok(());
|
||||
}
|
||||
HookKind::Thread(triggers, callback) => (triggers, callback),
|
||||
};
|
||||
|
||||
// Hooks for threads stored in the registry (in a weak table)
|
||||
let state = self.state();
|
||||
let _sg = StackGuard::new(state);
|
||||
check_stack(state, 3)?;
|
||||
protect_lua!(state, 0, 0, |state| {
|
||||
if ffi::luaL_getsubtable(state, ffi::LUA_REGISTRYINDEX, HOOKS_KEY) == 0 {
|
||||
// Table just created, initialize it
|
||||
ffi::lua_pushliteral(state, c"k");
|
||||
ffi::lua_setfield(state, -2, cstr!("__mode")); // hooktable.__mode = "k"
|
||||
ffi::lua_pushvalue(state, -1);
|
||||
ffi::lua_setmetatable(state, -2); // metatable(hooktable) = hooktable
|
||||
}
|
||||
|
||||
ffi::lua_pushthread(thread_state);
|
||||
ffi::lua_xmove(thread_state, state, 1); // key (thread)
|
||||
let _ = push_internal_userdata(state, callback, false); // value (hook callback)
|
||||
ffi::lua_rawset(state, -3); // hooktable[thread] = hook callback
|
||||
})?;
|
||||
|
||||
ffi::lua_sethook(thread_state, Some(hook_proc), triggers.mask(), triggers.count());
|
||||
|
||||
Ok(())
|
||||
(*self.extra.get()).hook_callback = Some(Rc::new(callback));
|
||||
(*self.extra.get()).hook_thread = state; // Mark for what thread the hook is set
|
||||
ffi::lua_sethook(state, Some(hook_proc), triggers.mask(), triggers.count());
|
||||
}
|
||||
|
||||
/// See [`Lua::create_string`]
|
||||
@@ -574,20 +492,11 @@ impl RawLua {
|
||||
let _sg = StackGuard::new(state);
|
||||
check_stack(state, 3)?;
|
||||
|
||||
let protect = !self.unlikely_memory_error();
|
||||
#[cfg(feature = "luau")]
|
||||
let protect = protect || (*self.extra.get()).thread_creation_callback.is_some();
|
||||
|
||||
let thread_state = if !protect {
|
||||
let thread_state = if self.unlikely_memory_error() {
|
||||
ffi::lua_newthread(state)
|
||||
} else {
|
||||
protect_lua!(state, 0, 1, |state| ffi::lua_newthread(state))?
|
||||
};
|
||||
|
||||
// Inherit global hook if set
|
||||
#[cfg(not(feature = "luau"))]
|
||||
self.set_thread_hook(thread_state, HookKind::Global)?;
|
||||
|
||||
let thread = Thread(self.pop_ref(), thread_state);
|
||||
ffi::lua_xpush(self.ref_thread(), thread_state, func.0.index);
|
||||
Ok(thread)
|
||||
@@ -1191,7 +1100,7 @@ impl RawLua {
|
||||
pub(crate) fn create_callback(&self, func: Callback) -> Result<Function> {
|
||||
unsafe extern "C-unwind" fn call_callback(state: *mut ffi::lua_State) -> c_int {
|
||||
let upvalue = get_userdata::<CallbackUpvalue>(state, ffi::lua_upvalueindex(1));
|
||||
callback_error_ext(state, (*upvalue).extra.get(), true, |extra, nargs| {
|
||||
callback_error_ext(state, (*upvalue).extra.get(), |extra, nargs| {
|
||||
// Lua ensures that `LUA_MINSTACK` stack spaces are available (after pushing arguments)
|
||||
// The lock must be already held as the callback is executed
|
||||
let rawlua = (*extra).raw_lua();
|
||||
@@ -1238,7 +1147,7 @@ impl RawLua {
|
||||
// Async functions cannot be scoped and therefore destroyed,
|
||||
// so the first upvalue is always valid
|
||||
let upvalue = get_userdata::<AsyncCallbackUpvalue>(state, ffi::lua_upvalueindex(1));
|
||||
callback_error_ext(state, (*upvalue).extra.get(), true, |extra, nargs| {
|
||||
callback_error_ext(state, (*upvalue).extra.get(), |extra, nargs| {
|
||||
// Lua ensures that `LUA_MINSTACK` stack spaces are available (after pushing arguments)
|
||||
// The lock must be already held as the callback is executed
|
||||
let rawlua = (*extra).raw_lua();
|
||||
@@ -1262,7 +1171,7 @@ impl RawLua {
|
||||
|
||||
unsafe extern "C-unwind" fn poll_future(state: *mut ffi::lua_State) -> c_int {
|
||||
let upvalue = get_userdata::<AsyncPollUpvalue>(state, ffi::lua_upvalueindex(1));
|
||||
callback_error_ext(state, (*upvalue).extra.get(), true, |extra, _| {
|
||||
callback_error_ext(state, (*upvalue).extra.get(), |extra, _| {
|
||||
// Lua ensures that `LUA_MINSTACK` stack spaces are available (after pushing arguments)
|
||||
// The lock must be already held as the future is polled
|
||||
let rawlua = (*extra).raw_lua();
|
||||
@@ -1356,7 +1265,7 @@ impl RawLua {
|
||||
"#,
|
||||
)
|
||||
.try_cache()
|
||||
.set_name("=__mlua_async_poll")
|
||||
.set_name("__mlua_async_poll")
|
||||
.set_environment(env)
|
||||
.into_function()
|
||||
}
|
||||
@@ -1376,14 +1285,16 @@ impl RawLua {
|
||||
|
||||
// Uses 3 stack spaces
|
||||
unsafe fn load_std_libs(state: *mut ffi::lua_State, libs: StdLib) -> Result<()> {
|
||||
unsafe fn requiref(
|
||||
#[inline(always)]
|
||||
pub unsafe fn requiref(
|
||||
state: *mut ffi::lua_State,
|
||||
modname: *const c_char,
|
||||
modname: &str,
|
||||
openf: ffi::lua_CFunction,
|
||||
glb: c_int,
|
||||
) -> Result<()> {
|
||||
protect_lua!(state, 0, 0, |state| {
|
||||
ffi::luaL_requiref(state, modname, openf, glb)
|
||||
let modname = mlua_expect!(CString::new(modname), "modname contains nil byte");
|
||||
protect_lua!(state, 0, 1, |state| {
|
||||
ffi::luaL_requiref(state, modname.as_ptr() as *const c_char, openf, glb)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1414,30 +1325,36 @@ unsafe fn load_std_libs(state: *mut ffi::lua_State, libs: StdLib) -> Result<()>
|
||||
{
|
||||
if libs.contains(StdLib::COROUTINE) {
|
||||
requiref(state, ffi::LUA_COLIBNAME, ffi::luaopen_coroutine, 1)?;
|
||||
ffi::lua_pop(state, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if libs.contains(StdLib::TABLE) {
|
||||
requiref(state, ffi::LUA_TABLIBNAME, ffi::luaopen_table, 1)?;
|
||||
ffi::lua_pop(state, 1);
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
if libs.contains(StdLib::IO) {
|
||||
requiref(state, ffi::LUA_IOLIBNAME, ffi::luaopen_io, 1)?;
|
||||
ffi::lua_pop(state, 1);
|
||||
}
|
||||
|
||||
if libs.contains(StdLib::OS) {
|
||||
requiref(state, ffi::LUA_OSLIBNAME, ffi::luaopen_os, 1)?;
|
||||
ffi::lua_pop(state, 1);
|
||||
}
|
||||
|
||||
if libs.contains(StdLib::STRING) {
|
||||
requiref(state, ffi::LUA_STRLIBNAME, ffi::luaopen_string, 1)?;
|
||||
ffi::lua_pop(state, 1);
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "luau"))]
|
||||
{
|
||||
if libs.contains(StdLib::UTF8) {
|
||||
requiref(state, ffi::LUA_UTF8LIBNAME, ffi::luaopen_utf8, 1)?;
|
||||
ffi::lua_pop(state, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1445,6 +1362,7 @@ unsafe fn load_std_libs(state: *mut ffi::lua_State, libs: StdLib) -> Result<()>
|
||||
{
|
||||
if libs.contains(StdLib::BIT) {
|
||||
requiref(state, ffi::LUA_BITLIBNAME, ffi::luaopen_bit32, 1)?;
|
||||
ffi::lua_pop(state, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1452,40 +1370,53 @@ unsafe fn load_std_libs(state: *mut ffi::lua_State, libs: StdLib) -> Result<()>
|
||||
{
|
||||
if libs.contains(StdLib::BIT) {
|
||||
requiref(state, ffi::LUA_BITLIBNAME, ffi::luaopen_bit, 1)?;
|
||||
ffi::lua_pop(state, 1);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "luau")]
|
||||
if libs.contains(StdLib::BUFFER) {
|
||||
requiref(state, ffi::LUA_BUFFERLIBNAME, ffi::luaopen_buffer, 1)?;
|
||||
ffi::lua_pop(state, 1);
|
||||
}
|
||||
|
||||
#[cfg(feature = "luau")]
|
||||
if libs.contains(StdLib::VECTOR) {
|
||||
requiref(state, ffi::LUA_VECLIBNAME, ffi::luaopen_vector, 1)?;
|
||||
ffi::lua_pop(state, 1);
|
||||
}
|
||||
|
||||
if libs.contains(StdLib::MATH) {
|
||||
requiref(state, ffi::LUA_MATHLIBNAME, ffi::luaopen_math, 1)?;
|
||||
ffi::lua_pop(state, 1);
|
||||
}
|
||||
|
||||
if libs.contains(StdLib::DEBUG) {
|
||||
requiref(state, ffi::LUA_DBLIBNAME, ffi::luaopen_debug, 1)?;
|
||||
ffi::lua_pop(state, 1);
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
if libs.contains(StdLib::PACKAGE) {
|
||||
requiref(state, ffi::LUA_LOADLIBNAME, ffi::luaopen_package, 1)?;
|
||||
ffi::lua_pop(state, 1);
|
||||
}
|
||||
#[cfg(feature = "luau")]
|
||||
if libs.contains(StdLib::PACKAGE) {
|
||||
let lua = (*ExtraData::get(state)).lua();
|
||||
crate::luau::register_package_module(lua)?;
|
||||
}
|
||||
|
||||
#[cfg(feature = "luajit")]
|
||||
if libs.contains(StdLib::JIT) {
|
||||
requiref(state, ffi::LUA_JITLIBNAME, ffi::luaopen_jit, 1)?;
|
||||
ffi::lua_pop(state, 1);
|
||||
}
|
||||
|
||||
#[cfg(feature = "luajit")]
|
||||
if libs.contains(StdLib::FFI) {
|
||||
requiref(state, ffi::LUA_FFILIBNAME, ffi::luaopen_ffi, 1)?;
|
||||
ffi::lua_pop(state, 1);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
+1
-9
@@ -24,10 +24,9 @@ impl Drop for StateGuard<'_> {
|
||||
|
||||
// An optimized version of `callback_error` that does not allocate `WrappedFailure` userdata
|
||||
// and instead reuses unused values from previous calls (or allocates new).
|
||||
pub(crate) unsafe fn callback_error_ext<F, R>(
|
||||
pub(super) unsafe fn callback_error_ext<F, R>(
|
||||
state: *mut ffi::lua_State,
|
||||
mut extra: *mut ExtraData,
|
||||
wrap_error: bool,
|
||||
f: F,
|
||||
) -> R
|
||||
where
|
||||
@@ -115,13 +114,6 @@ where
|
||||
Ok(Err(err)) => {
|
||||
let wrapped_error = prealloc_failure.r#use(state, extra);
|
||||
|
||||
if !wrap_error {
|
||||
ptr::write(wrapped_error, WrappedFailure::Error(err));
|
||||
get_internal_metatable::<WrappedFailure>(state);
|
||||
ffi::lua_setmetatable(state, -2);
|
||||
ffi::lua_error(state)
|
||||
}
|
||||
|
||||
// Build `CallbackError` with traceback
|
||||
let traceback = if ffi::lua_checkstack(state, ffi::LUA_TRACEBACK_STACK) != 0 {
|
||||
ffi::luaL_traceback(state, state, ptr::null(), 0);
|
||||
|
||||
+10
-11
@@ -6,11 +6,9 @@ pub struct StdLib(u32);
|
||||
|
||||
impl StdLib {
|
||||
/// [`coroutine`](https://www.lua.org/manual/5.4/manual.html#6.2) library
|
||||
///
|
||||
/// Requires `feature = "lua54/lua53/lua52/luau"`
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "luau"))]
|
||||
#[cfg_attr(
|
||||
docsrs,
|
||||
doc(cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "luau")))
|
||||
)]
|
||||
pub const COROUTINE: StdLib = StdLib(1);
|
||||
|
||||
/// [`table`](https://www.lua.org/manual/5.4/manual.html#6.6) library
|
||||
@@ -28,24 +26,21 @@ impl StdLib {
|
||||
pub const STRING: StdLib = StdLib(1 << 4);
|
||||
|
||||
/// [`utf8`](https://www.lua.org/manual/5.4/manual.html#6.5) library
|
||||
///
|
||||
/// Requires `feature = "lua54/lua53/luau"`
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "luau"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "lua54", feature = "lua53", feature = "luau"))))]
|
||||
pub const UTF8: StdLib = StdLib(1 << 5);
|
||||
|
||||
/// [`bit`](https://www.lua.org/manual/5.2/manual.html#6.7) library
|
||||
///
|
||||
/// Requires `feature = "lua52/luajit/luau"`
|
||||
#[cfg(any(feature = "lua52", feature = "luajit", feature = "luau", doc))]
|
||||
#[cfg_attr(
|
||||
docsrs,
|
||||
doc(cfg(any(feature = "lua52", feature = "luajit", feature = "luau")))
|
||||
)]
|
||||
pub const BIT: StdLib = StdLib(1 << 6);
|
||||
|
||||
/// [`math`](https://www.lua.org/manual/5.4/manual.html#6.7) library
|
||||
pub const MATH: StdLib = StdLib(1 << 7);
|
||||
|
||||
/// [`package`](https://www.lua.org/manual/5.4/manual.html#6.3) library
|
||||
#[cfg(not(feature = "luau"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
|
||||
pub const PACKAGE: StdLib = StdLib(1 << 8);
|
||||
|
||||
/// [`buffer`](https://luau.org/library#buffer-library) library
|
||||
@@ -59,11 +54,15 @@ impl StdLib {
|
||||
pub const VECTOR: StdLib = StdLib(1 << 10);
|
||||
|
||||
/// [`jit`](http://luajit.org/ext_jit.html) library
|
||||
///
|
||||
/// Requires `feature = "luajit"`
|
||||
#[cfg(any(feature = "luajit", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luajit")))]
|
||||
pub const JIT: StdLib = StdLib(1 << 11);
|
||||
|
||||
/// (**unsafe**) [`ffi`](http://luajit.org/ext_ffi.html) library
|
||||
///
|
||||
/// Requires `feature = "luajit"`
|
||||
#[cfg(any(feature = "luajit", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luajit")))]
|
||||
pub const FFI: StdLib = StdLib(1 << 30);
|
||||
|
||||
@@ -501,6 +501,13 @@ impl Table {
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[deprecated(since = "0.10.0", note = "please use `metatable` instead")]
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
pub fn get_metatable(&self) -> Option<Table> {
|
||||
self.metatable()
|
||||
}
|
||||
|
||||
/// Sets or removes the metatable of this table.
|
||||
///
|
||||
/// If `metatable` is `None`, the metatable is removed (if no metatable is set, this does
|
||||
@@ -537,6 +544,8 @@ impl Table {
|
||||
}
|
||||
|
||||
/// Sets `readonly` attribute on the table.
|
||||
///
|
||||
/// Requires `feature = "luau"`
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
pub fn set_readonly(&self, enabled: bool) {
|
||||
@@ -552,6 +561,8 @@ impl Table {
|
||||
}
|
||||
|
||||
/// Returns `readonly` attribute of the table.
|
||||
///
|
||||
/// Requires `feature = "luau"`
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
pub fn is_readonly(&self) -> bool {
|
||||
@@ -569,6 +580,8 @@ impl Table {
|
||||
/// - Fast-path for some built-in functions (fastcall).
|
||||
///
|
||||
/// For `safeenv` environments, monkey patching or modifying values may not work as expected.
|
||||
///
|
||||
/// Requires `feature = "luau"`
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
pub fn set_safeenv(&self, enabled: bool) {
|
||||
|
||||
+87
-151
@@ -11,7 +11,7 @@ use crate::util::{check_stack, error_traceback_thread, pop_error, StackGuard};
|
||||
#[cfg(not(feature = "luau"))]
|
||||
use crate::{
|
||||
hook::{Debug, HookTriggers},
|
||||
types::HookKind,
|
||||
types::MaybeSend,
|
||||
};
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
@@ -47,24 +47,17 @@ pub enum ThreadStatus {
|
||||
/// to the thread stack.
|
||||
#[derive(Clone, Copy)]
|
||||
enum ThreadStatusInner {
|
||||
New(c_int),
|
||||
New,
|
||||
Running,
|
||||
Yielded(c_int),
|
||||
Yielded,
|
||||
Finished,
|
||||
Error,
|
||||
}
|
||||
|
||||
impl ThreadStatusInner {
|
||||
#[cfg(feature = "async")]
|
||||
#[inline(always)]
|
||||
fn is_resumable(self) -> bool {
|
||||
matches!(self, ThreadStatusInner::New(_) | ThreadStatusInner::Yielded(_))
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[inline(always)]
|
||||
fn is_yielded(self) -> bool {
|
||||
matches!(self, ThreadStatusInner::Yielded(_))
|
||||
matches!(self, ThreadStatusInner::New | ThreadStatusInner::Yielded)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,13 +72,16 @@ unsafe impl Sync for Thread {}
|
||||
|
||||
/// Thread (coroutine) representation as an async [`Future`] or [`Stream`].
|
||||
///
|
||||
/// Requires `feature = "async"`
|
||||
///
|
||||
/// [`Future`]: std::future::Future
|
||||
/// [`Stream`]: futures_util::stream::Stream
|
||||
#[cfg(feature = "async")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||
pub struct AsyncThread<R> {
|
||||
pub struct AsyncThread<A, R> {
|
||||
thread: Thread,
|
||||
init_args: Option<A>,
|
||||
ret: PhantomData<R>,
|
||||
recycle: bool,
|
||||
}
|
||||
@@ -145,46 +141,9 @@ impl Thread {
|
||||
R: FromLuaMulti,
|
||||
{
|
||||
let lua = self.0.lua.lock();
|
||||
let mut pushed_nargs = match self.status_inner(&lua) {
|
||||
ThreadStatusInner::New(nargs) | ThreadStatusInner::Yielded(nargs) => nargs,
|
||||
_ => return Err(Error::CoroutineUnresumable),
|
||||
};
|
||||
|
||||
let state = lua.state();
|
||||
let thread_state = self.state();
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(state);
|
||||
let _thread_sg = StackGuard::with_top(thread_state, 0);
|
||||
|
||||
let nargs = args.push_into_stack_multi(&lua)?;
|
||||
if nargs > 0 {
|
||||
check_stack(thread_state, nargs)?;
|
||||
ffi::lua_xmove(state, thread_state, nargs);
|
||||
pushed_nargs += nargs;
|
||||
}
|
||||
|
||||
let (_, nresults) = self.resume_inner(&lua, pushed_nargs)?;
|
||||
check_stack(state, nresults + 1)?;
|
||||
ffi::lua_xmove(thread_state, state, nresults);
|
||||
|
||||
R::from_stack_multi(nresults, &lua)
|
||||
if !self.status_inner(&lua).is_resumable() {
|
||||
return Err(Error::CoroutineUnresumable);
|
||||
}
|
||||
}
|
||||
|
||||
/// Resumes execution of this thread, immediately raising an error.
|
||||
///
|
||||
/// This is a Luau specific extension.
|
||||
#[cfg(feature = "luau")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
pub fn resume_error<R>(&self, error: impl crate::IntoLua) -> Result<R>
|
||||
where
|
||||
R: FromLuaMulti,
|
||||
{
|
||||
let lua = self.0.lua.lock();
|
||||
match self.status_inner(&lua) {
|
||||
ThreadStatusInner::New(_) | ThreadStatusInner::Yielded(_) => {}
|
||||
_ => return Err(Error::CoroutineUnresumable),
|
||||
};
|
||||
|
||||
let state = lua.state();
|
||||
let thread_state = self.state();
|
||||
@@ -192,11 +151,7 @@ impl Thread {
|
||||
let _sg = StackGuard::new(state);
|
||||
let _thread_sg = StackGuard::with_top(thread_state, 0);
|
||||
|
||||
check_stack(state, 1)?;
|
||||
error.push_into_stack(&lua)?;
|
||||
ffi::lua_xmove(state, thread_state, 1);
|
||||
|
||||
let (_, nresults) = self.resume_inner(&lua, ffi::LUA_RESUMEERROR)?;
|
||||
let nresults = self.resume_inner(&lua, args)?;
|
||||
check_stack(state, nresults + 1)?;
|
||||
ffi::lua_xmove(thread_state, state, nresults);
|
||||
|
||||
@@ -207,33 +162,35 @@ impl Thread {
|
||||
/// Resumes execution of this thread.
|
||||
///
|
||||
/// It's similar to `resume()` but leaves `nresults` values on the thread stack.
|
||||
unsafe fn resume_inner(&self, lua: &RawLua, nargs: c_int) -> Result<(ThreadStatusInner, c_int)> {
|
||||
unsafe fn resume_inner(&self, lua: &RawLua, args: impl IntoLuaMulti) -> Result<c_int> {
|
||||
let state = lua.state();
|
||||
let thread_state = self.state();
|
||||
let mut nresults = 0;
|
||||
#[cfg(not(feature = "luau"))]
|
||||
let ret = ffi::lua_resume(thread_state, state, nargs, &mut nresults as *mut c_int);
|
||||
#[cfg(feature = "luau")]
|
||||
let ret = ffi::lua_resumex(thread_state, state, nargs, &mut nresults as *mut c_int);
|
||||
match ret {
|
||||
ffi::LUA_OK => Ok((ThreadStatusInner::Finished, nresults)),
|
||||
ffi::LUA_YIELD => Ok((ThreadStatusInner::Yielded(0), nresults)),
|
||||
ffi::LUA_ERRMEM => {
|
||||
// Don't call error handler for memory errors
|
||||
Err(pop_error(thread_state, ret))
|
||||
}
|
||||
_ => {
|
||||
check_stack(state, 3)?;
|
||||
protect_lua!(state, 0, 1, |state| error_traceback_thread(state, thread_state))?;
|
||||
Err(pop_error(state, ret))
|
||||
}
|
||||
|
||||
let nargs = args.push_into_stack_multi(lua)?;
|
||||
if nargs > 0 {
|
||||
check_stack(thread_state, nargs)?;
|
||||
ffi::lua_xmove(state, thread_state, nargs);
|
||||
}
|
||||
|
||||
let mut nresults = 0;
|
||||
let ret = ffi::lua_resume(thread_state, state, nargs, &mut nresults as *mut c_int);
|
||||
if ret != ffi::LUA_OK && ret != ffi::LUA_YIELD {
|
||||
if ret == ffi::LUA_ERRMEM {
|
||||
// Don't call error handler for memory errors
|
||||
return Err(pop_error(thread_state, ret));
|
||||
}
|
||||
check_stack(state, 3)?;
|
||||
protect_lua!(state, 0, 1, |state| error_traceback_thread(state, thread_state))?;
|
||||
return Err(pop_error(state, ret));
|
||||
}
|
||||
|
||||
Ok(nresults)
|
||||
}
|
||||
|
||||
/// Gets the status of the thread.
|
||||
pub fn status(&self) -> ThreadStatus {
|
||||
match self.status_inner(&self.0.lua.lock()) {
|
||||
ThreadStatusInner::New(_) | ThreadStatusInner::Yielded(_) => ThreadStatus::Resumable,
|
||||
ThreadStatusInner::New | ThreadStatusInner::Yielded => ThreadStatus::Resumable,
|
||||
ThreadStatusInner::Running => ThreadStatus::Running,
|
||||
ThreadStatusInner::Finished => ThreadStatus::Finished,
|
||||
ThreadStatusInner::Error => ThreadStatus::Error,
|
||||
@@ -248,10 +205,9 @@ impl Thread {
|
||||
return ThreadStatusInner::Running;
|
||||
}
|
||||
let status = unsafe { ffi::lua_status(thread_state) };
|
||||
let top = unsafe { ffi::lua_gettop(thread_state) };
|
||||
match status {
|
||||
ffi::LUA_YIELD => ThreadStatusInner::Yielded(top),
|
||||
ffi::LUA_OK if top > 0 => ThreadStatusInner::New(top - 1),
|
||||
ffi::LUA_YIELD => ThreadStatusInner::Yielded,
|
||||
ffi::LUA_OK if unsafe { ffi::lua_gettop(thread_state) } > 0 => ThreadStatusInner::New,
|
||||
ffi::LUA_OK => ThreadStatusInner::Finished,
|
||||
_ => ThreadStatusInner::Error,
|
||||
}
|
||||
@@ -260,31 +216,16 @@ impl Thread {
|
||||
/// Sets a hook function that will periodically be called as Lua code executes.
|
||||
///
|
||||
/// This function is similar or [`Lua::set_hook`] except that it sets for the thread.
|
||||
/// You can have multiple hooks for different threads.
|
||||
///
|
||||
/// To remove a hook call [`Thread::remove_hook`].
|
||||
/// To remove a hook call [`Lua::remove_hook`].
|
||||
#[cfg(not(feature = "luau"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
|
||||
pub fn set_hook<F>(&self, triggers: HookTriggers, callback: F) -> Result<()>
|
||||
pub fn set_hook<F>(&self, triggers: HookTriggers, callback: F)
|
||||
where
|
||||
F: Fn(&crate::Lua, Debug) -> Result<crate::VmState> + crate::MaybeSend + 'static,
|
||||
F: Fn(&crate::Lua, Debug) -> Result<crate::VmState> + MaybeSend + 'static,
|
||||
{
|
||||
let lua = self.0.lua.lock();
|
||||
unsafe {
|
||||
lua.set_thread_hook(
|
||||
self.state(),
|
||||
HookKind::Thread(triggers, crate::types::XRc::new(callback)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes any hook function from this thread.
|
||||
#[cfg(not(feature = "luau"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
|
||||
pub fn remove_hook(&self) {
|
||||
let _lua = self.0.lua.lock();
|
||||
unsafe {
|
||||
ffi::lua_sethook(self.state(), None, 0, 0);
|
||||
lua.set_thread_hook(self.state(), triggers, callback);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,7 +249,7 @@ impl Thread {
|
||||
match self.status_inner(&lua) {
|
||||
ThreadStatusInner::Running => return Err(Error::runtime("cannot reset a running thread")),
|
||||
// Any Lua can reuse new or finished thread
|
||||
ThreadStatusInner::New(_) => unsafe { ffi::lua_settop(thread_state, 0) },
|
||||
ThreadStatusInner::New => unsafe { ffi::lua_settop(thread_state, 0) },
|
||||
ThreadStatusInner::Finished => {}
|
||||
#[cfg(not(any(feature = "lua54", feature = "luau")))]
|
||||
_ => return Err(Error::runtime("cannot reset non-finished thread")),
|
||||
@@ -344,9 +285,7 @@ impl Thread {
|
||||
|
||||
/// Converts [`Thread`] to an [`AsyncThread`] which implements [`Future`] and [`Stream`] traits.
|
||||
///
|
||||
/// Only resumable threads can be converted to [`AsyncThread`].
|
||||
///
|
||||
/// `args` are pushed to the thread stack and will be used when the thread is resumed.
|
||||
/// `args` are passed as arguments to the thread function for first call.
|
||||
/// The object calls [`resume`] while polling and also allow to run Rust futures
|
||||
/// to completion using an executor.
|
||||
///
|
||||
@@ -354,6 +293,8 @@ impl Thread {
|
||||
/// values whereas [`Future`] version discards that values and poll until the final
|
||||
/// one (returned from the thread function).
|
||||
///
|
||||
/// Requires `feature = "async"`
|
||||
///
|
||||
/// [`Future`]: std::future::Future
|
||||
/// [`Stream`]: futures_util::stream::Stream
|
||||
/// [`resume`]: https://www.lua.org/manual/5.4/manual.html#lua_resume
|
||||
@@ -377,7 +318,7 @@ impl Thread {
|
||||
/// end)
|
||||
/// "#).eval()?;
|
||||
///
|
||||
/// let mut stream = thread.into_async::<i64>(1)?;
|
||||
/// let mut stream = thread.into_async::<i64>(1);
|
||||
/// let mut sum = 0;
|
||||
/// while let Some(n) = stream.try_next().await? {
|
||||
/// sum += n;
|
||||
@@ -390,31 +331,15 @@ impl Thread {
|
||||
/// ```
|
||||
#[cfg(feature = "async")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||
pub fn into_async<R>(self, args: impl IntoLuaMulti) -> Result<AsyncThread<R>>
|
||||
pub fn into_async<R>(self, args: impl IntoLuaMulti) -> AsyncThread<impl IntoLuaMulti, R>
|
||||
where
|
||||
R: FromLuaMulti,
|
||||
{
|
||||
let lua = self.0.lua.lock();
|
||||
if !self.status_inner(&lua).is_resumable() {
|
||||
return Err(Error::CoroutineUnresumable);
|
||||
}
|
||||
|
||||
let state = lua.state();
|
||||
let thread_state = self.state();
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(state);
|
||||
|
||||
let nargs = args.push_into_stack_multi(&lua)?;
|
||||
if nargs > 0 {
|
||||
check_stack(thread_state, nargs)?;
|
||||
ffi::lua_xmove(state, thread_state, nargs);
|
||||
}
|
||||
|
||||
Ok(AsyncThread {
|
||||
thread: self,
|
||||
ret: PhantomData,
|
||||
recycle: false,
|
||||
})
|
||||
AsyncThread {
|
||||
thread: self,
|
||||
init_args: Some(args),
|
||||
ret: PhantomData,
|
||||
recycle: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,6 +376,8 @@ impl Thread {
|
||||
/// # #[cfg(not(feature = "luau"))]
|
||||
/// # fn main() { }
|
||||
/// ```
|
||||
///
|
||||
/// Requires `feature = "luau"`
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
#[doc(hidden)]
|
||||
@@ -493,7 +420,7 @@ impl LuaType for Thread {
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
impl<R> AsyncThread<R> {
|
||||
impl<A, R> AsyncThread<A, R> {
|
||||
#[inline(always)]
|
||||
pub(crate) fn set_recyclable(&mut self, recyclable: bool) {
|
||||
self.recycle = recyclable;
|
||||
@@ -501,7 +428,7 @@ impl<R> AsyncThread<R> {
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
impl<R> Drop for AsyncThread<R> {
|
||||
impl<A, R> Drop for AsyncThread<A, R> {
|
||||
fn drop(&mut self) {
|
||||
if self.recycle {
|
||||
if let Some(lua) = self.thread.0.lua.try_lock() {
|
||||
@@ -513,15 +440,14 @@ impl<R> Drop for AsyncThread<R> {
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
impl<R: FromLuaMulti> Stream for AsyncThread<R> {
|
||||
impl<A: IntoLuaMulti, R: FromLuaMulti> Stream for AsyncThread<A, R> {
|
||||
type Item = Result<R>;
|
||||
|
||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
let lua = self.thread.0.lua.lock();
|
||||
let nargs = match self.thread.status_inner(&lua) {
|
||||
ThreadStatusInner::New(nargs) | ThreadStatusInner::Yielded(nargs) => nargs,
|
||||
_ => return Poll::Ready(None),
|
||||
};
|
||||
if !self.thread.status_inner(&lua).is_resumable() {
|
||||
return Poll::Ready(None);
|
||||
}
|
||||
|
||||
let state = lua.state();
|
||||
let thread_state = self.thread.state();
|
||||
@@ -530,34 +456,36 @@ impl<R: FromLuaMulti> Stream for AsyncThread<R> {
|
||||
let _thread_sg = StackGuard::with_top(thread_state, 0);
|
||||
let _wg = WakerGuard::new(&lua, cx.waker());
|
||||
|
||||
let (status, nresults) = (self.thread).resume_inner(&lua, nargs)?;
|
||||
// This is safe as we are not moving the whole struct
|
||||
let this = self.get_unchecked_mut();
|
||||
let nresults = if let Some(args) = this.init_args.take() {
|
||||
this.thread.resume_inner(&lua, args)?
|
||||
} else {
|
||||
this.thread.resume_inner(&lua, ())?
|
||||
};
|
||||
|
||||
if status.is_yielded() {
|
||||
if nresults == 1 && is_poll_pending(thread_state) {
|
||||
return Poll::Pending;
|
||||
}
|
||||
// Continue polling
|
||||
cx.waker().wake_by_ref();
|
||||
if nresults == 1 && is_poll_pending(thread_state) {
|
||||
return Poll::Pending;
|
||||
}
|
||||
|
||||
check_stack(state, nresults + 1)?;
|
||||
ffi::lua_xmove(thread_state, state, nresults);
|
||||
|
||||
cx.waker().wake_by_ref();
|
||||
Poll::Ready(Some(R::from_stack_multi(nresults, &lua)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
impl<R: FromLuaMulti> Future for AsyncThread<R> {
|
||||
impl<A: IntoLuaMulti, R: FromLuaMulti> Future for AsyncThread<A, R> {
|
||||
type Output = Result<R>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let lua = self.thread.0.lua.lock();
|
||||
let nargs = match self.thread.status_inner(&lua) {
|
||||
ThreadStatusInner::New(nargs) | ThreadStatusInner::Yielded(nargs) => nargs,
|
||||
_ => return Poll::Ready(Err(Error::CoroutineUnresumable)),
|
||||
};
|
||||
if !self.thread.status_inner(&lua).is_resumable() {
|
||||
return Poll::Ready(Err(Error::CoroutineUnresumable));
|
||||
}
|
||||
|
||||
let state = lua.state();
|
||||
let thread_state = self.thread.state();
|
||||
@@ -566,13 +494,21 @@ impl<R: FromLuaMulti> Future for AsyncThread<R> {
|
||||
let _thread_sg = StackGuard::with_top(thread_state, 0);
|
||||
let _wg = WakerGuard::new(&lua, cx.waker());
|
||||
|
||||
let (status, nresults) = self.thread.resume_inner(&lua, nargs)?;
|
||||
// This is safe as we are not moving the whole struct
|
||||
let this = self.get_unchecked_mut();
|
||||
let nresults = if let Some(args) = this.init_args.take() {
|
||||
this.thread.resume_inner(&lua, args)?
|
||||
} else {
|
||||
this.thread.resume_inner(&lua, ())?
|
||||
};
|
||||
|
||||
if status.is_yielded() {
|
||||
if !(nresults == 1 && is_poll_pending(thread_state)) {
|
||||
// Ignore value returned via yield()
|
||||
cx.waker().wake_by_ref();
|
||||
}
|
||||
if nresults == 1 && is_poll_pending(thread_state) {
|
||||
return Poll::Pending;
|
||||
}
|
||||
|
||||
if ffi::lua_status(thread_state) == ffi::LUA_YIELD {
|
||||
// Ignore value returned via yield()
|
||||
cx.waker().wake_by_ref();
|
||||
return Poll::Pending;
|
||||
}
|
||||
|
||||
@@ -626,7 +562,7 @@ mod assertions {
|
||||
#[cfg(feature = "send")]
|
||||
static_assertions::assert_impl_all!(Thread: Send, Sync);
|
||||
#[cfg(all(feature = "async", not(feature = "send")))]
|
||||
static_assertions::assert_not_impl_any!(AsyncThread<()>: Send);
|
||||
static_assertions::assert_not_impl_any!(AsyncThread<(), ()>: Send);
|
||||
#[cfg(all(feature = "async", feature = "send"))]
|
||||
static_assertions::assert_impl_all!(AsyncThread<()>: Send, Sync);
|
||||
static_assertions::assert_impl_all!(AsyncThread<(), ()>: Send, Sync);
|
||||
}
|
||||
|
||||
@@ -175,6 +175,8 @@ pub trait ObjectLike: Sealed {
|
||||
/// Gets the function associated to key `name` from the object and asynchronously calls it,
|
||||
/// passing the object itself along with `args` as function arguments.
|
||||
///
|
||||
/// Requires `feature = "async"`
|
||||
///
|
||||
/// This might invoke the `__index` metamethod.
|
||||
#[cfg(feature = "async")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||
@@ -193,6 +195,8 @@ pub trait ObjectLike: Sealed {
|
||||
/// Gets the function associated to key `name` from the object and asynchronously calls it,
|
||||
/// passing `args` as function arguments.
|
||||
///
|
||||
/// Requires `feature = "async"`
|
||||
///
|
||||
/// This might invoke the `__index` metamethod.
|
||||
#[cfg(feature = "async")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||
|
||||
+6
-23
@@ -1,9 +1,10 @@
|
||||
use std::cell::UnsafeCell;
|
||||
use std::os::raw::{c_int, c_void};
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::error::Result;
|
||||
#[cfg(not(feature = "luau"))]
|
||||
use crate::hook::{Debug, HookTriggers};
|
||||
use crate::hook::Debug;
|
||||
use crate::state::{ExtraData, Lua, RawLua};
|
||||
|
||||
// Re-export mutex wrappers
|
||||
@@ -72,35 +73,17 @@ pub enum VmState {
|
||||
Yield,
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
pub(crate) enum HookKind {
|
||||
Global,
|
||||
Thread(HookTriggers, HookCallback),
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "send", not(feature = "luau")))]
|
||||
pub(crate) type HookCallback = XRc<dyn Fn(&Lua, Debug) -> Result<VmState> + Send>;
|
||||
pub(crate) type HookCallback = Rc<dyn Fn(&Lua, Debug) -> Result<VmState> + Send>;
|
||||
|
||||
#[cfg(all(not(feature = "send"), not(feature = "luau")))]
|
||||
pub(crate) type HookCallback = XRc<dyn Fn(&Lua, Debug) -> Result<VmState>>;
|
||||
pub(crate) type HookCallback = Rc<dyn Fn(&Lua, Debug) -> Result<VmState>>;
|
||||
|
||||
#[cfg(all(feature = "send", feature = "luau"))]
|
||||
pub(crate) type InterruptCallback = XRc<dyn Fn(&Lua) -> Result<VmState> + Send>;
|
||||
pub(crate) type InterruptCallback = Rc<dyn Fn(&Lua) -> Result<VmState> + Send>;
|
||||
|
||||
#[cfg(all(not(feature = "send"), feature = "luau"))]
|
||||
pub(crate) type InterruptCallback = XRc<dyn Fn(&Lua) -> Result<VmState>>;
|
||||
|
||||
#[cfg(all(feature = "send", feature = "luau"))]
|
||||
pub(crate) type ThreadCreationCallback = XRc<dyn Fn(&Lua, crate::Thread) -> Result<()> + Send>;
|
||||
|
||||
#[cfg(all(not(feature = "send"), feature = "luau"))]
|
||||
pub(crate) type ThreadCreationCallback = XRc<dyn Fn(&Lua, crate::Thread) -> Result<()>>;
|
||||
|
||||
#[cfg(all(feature = "send", feature = "luau"))]
|
||||
pub(crate) type ThreadCollectionCallback = XRc<dyn Fn(crate::LightUserData) + Send>;
|
||||
|
||||
#[cfg(all(not(feature = "send"), feature = "luau"))]
|
||||
pub(crate) type ThreadCollectionCallback = XRc<dyn Fn(crate::LightUserData)>;
|
||||
pub(crate) type InterruptCallback = Rc<dyn Fn(&Lua) -> Result<VmState>>;
|
||||
|
||||
#[cfg(all(feature = "send", feature = "lua54"))]
|
||||
pub(crate) type WarnCallback = XRc<dyn Fn(&Lua, &str, bool) -> Result<()> + Send>;
|
||||
|
||||
+37
-21
@@ -56,32 +56,30 @@ pub enum MetaMethod {
|
||||
/// The unary minus (`-`) operator.
|
||||
Unm,
|
||||
/// The floor division (//) operator.
|
||||
/// Requires `feature = "lua54/lua53/luau"`
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "luau"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "lua54", feature = "lua53", feature = "luau"))))]
|
||||
IDiv,
|
||||
/// The bitwise AND (&) operator.
|
||||
/// Requires `feature = "lua54/lua53"`
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "lua54", feature = "lua53"))))]
|
||||
BAnd,
|
||||
/// The bitwise OR (|) operator.
|
||||
/// Requires `feature = "lua54/lua53"`
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "lua54", feature = "lua53"))))]
|
||||
BOr,
|
||||
/// The bitwise XOR (binary ~) operator.
|
||||
/// Requires `feature = "lua54/lua53"`
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "lua54", feature = "lua53"))))]
|
||||
BXor,
|
||||
/// The bitwise NOT (unary ~) operator.
|
||||
/// Requires `feature = "lua54/lua53"`
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "lua54", feature = "lua53"))))]
|
||||
BNot,
|
||||
/// The bitwise left shift (<<) operator.
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "lua54", feature = "lua53"))))]
|
||||
Shl,
|
||||
/// The bitwise right shift (>>) operator.
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "lua54", feature = "lua53"))))]
|
||||
Shr,
|
||||
/// The string concatenation operator `..`.
|
||||
Concat,
|
||||
@@ -106,16 +104,16 @@ pub enum MetaMethod {
|
||||
/// The `__pairs` metamethod.
|
||||
///
|
||||
/// This is not an operator, but it will be called by the built-in `pairs` function.
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "luajit52"))]
|
||||
#[cfg_attr(
|
||||
docsrs,
|
||||
doc(cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "luajit52")))
|
||||
)]
|
||||
///
|
||||
/// Requires `feature = "lua54/lua53/lua52"`
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "luajit52",))]
|
||||
Pairs,
|
||||
/// The `__ipairs` metamethod.
|
||||
///
|
||||
/// This is not an operator, but it will be called by the built-in [`ipairs`] function.
|
||||
///
|
||||
/// Requires `feature = "lua52"`
|
||||
///
|
||||
/// [`ipairs`]: https://www.lua.org/manual/5.2/manual.html#pdf-ipairs
|
||||
#[cfg(any(feature = "lua52", feature = "luajit52", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "lua52", feature = "luajit52"))))]
|
||||
@@ -124,6 +122,8 @@ pub enum MetaMethod {
|
||||
///
|
||||
/// Executed before the iteration begins, and should return an iterator function like `next`
|
||||
/// (or a custom one).
|
||||
///
|
||||
/// Requires `feature = "lua"`
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
Iter,
|
||||
@@ -134,6 +134,8 @@ pub enum MetaMethod {
|
||||
/// More information about to-be-closed variables can be found in the Lua 5.4
|
||||
/// [documentation][lua_doc].
|
||||
///
|
||||
/// Requires `feature = "lua54"`
|
||||
///
|
||||
/// [lua_doc]: https://www.lua.org/manual/5.4/manual.html#3.3.8
|
||||
#[cfg(feature = "lua54")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "lua54")))]
|
||||
@@ -219,7 +221,9 @@ impl MetaMethod {
|
||||
pub(crate) const fn as_cstr(self) -> &'static CStr {
|
||||
match self {
|
||||
#[rustfmt::skip]
|
||||
MetaMethod::Type => if cfg!(feature = "luau") { c"__type" } else { c"__name" },
|
||||
MetaMethod::Type => unsafe {
|
||||
CStr::from_bytes_with_nul_unchecked(if cfg!(feature = "luau") { b"__type\0" } else { b"__name\0" })
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
@@ -270,6 +274,8 @@ pub trait UserDataMethods<T> {
|
||||
///
|
||||
/// Refer to [`add_method`] for more information about the implementation.
|
||||
///
|
||||
/// Requires `feature = "async"`
|
||||
///
|
||||
/// [`add_method`]: UserDataMethods::add_method
|
||||
#[cfg(feature = "async")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||
@@ -285,6 +291,8 @@ pub trait UserDataMethods<T> {
|
||||
///
|
||||
/// Refer to [`add_method`] for more information about the implementation.
|
||||
///
|
||||
/// Requires `feature = "async"`
|
||||
///
|
||||
/// [`add_method`]: UserDataMethods::add_method
|
||||
#[cfg(feature = "async")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||
@@ -323,6 +331,8 @@ pub trait UserDataMethods<T> {
|
||||
///
|
||||
/// This is an async version of [`add_function`].
|
||||
///
|
||||
/// Requires `feature = "async"`
|
||||
///
|
||||
/// [`add_function`]: UserDataMethods::add_function
|
||||
#[cfg(feature = "async")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||
@@ -365,12 +375,11 @@ pub trait UserDataMethods<T> {
|
||||
///
|
||||
/// This is an async version of [`add_meta_method`].
|
||||
///
|
||||
/// Requires `feature = "async"`
|
||||
///
|
||||
/// [`add_meta_method`]: UserDataMethods::add_meta_method
|
||||
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
|
||||
#[cfg_attr(
|
||||
docsrs,
|
||||
doc(cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau")))))
|
||||
)]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||
fn add_async_meta_method<M, A, MR, R>(&mut self, name: impl ToString, method: M)
|
||||
where
|
||||
T: 'static,
|
||||
@@ -384,6 +393,8 @@ pub trait UserDataMethods<T> {
|
||||
///
|
||||
/// This is an async version of [`add_meta_method_mut`].
|
||||
///
|
||||
/// Requires `feature = "async"`
|
||||
///
|
||||
/// [`add_meta_method_mut`]: UserDataMethods::add_meta_method_mut
|
||||
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||
@@ -421,12 +432,11 @@ pub trait UserDataMethods<T> {
|
||||
///
|
||||
/// This is an async version of [`add_meta_function`].
|
||||
///
|
||||
/// Requires `feature = "async"`
|
||||
///
|
||||
/// [`add_meta_function`]: UserDataMethods::add_meta_function
|
||||
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
|
||||
#[cfg_attr(
|
||||
docsrs,
|
||||
doc(cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau")))))
|
||||
)]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||
fn add_async_meta_function<F, A, FR, R>(&mut self, name: impl ToString, function: F)
|
||||
where
|
||||
F: Fn(Lua, A) -> FR + MaybeSend + 'static,
|
||||
@@ -887,6 +897,12 @@ impl AnyUserData {
|
||||
self.raw_metatable().map(UserDataMetatable)
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[deprecated(since = "0.10.0", note = "please use `metatable` instead")]
|
||||
pub fn get_metatable(&self) -> Result<UserDataMetatable> {
|
||||
self.metatable()
|
||||
}
|
||||
|
||||
fn raw_metatable(&self) -> Result<Table> {
|
||||
let lua = self.0.lua.lock();
|
||||
let state = lua.state();
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
use std::any::{type_name, TypeId};
|
||||
use std::any::TypeId;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::os::raw::c_int;
|
||||
use std::{fmt, mem};
|
||||
@@ -7,7 +7,7 @@ use crate::error::{Error, Result};
|
||||
use crate::state::{Lua, RawLua};
|
||||
use crate::traits::FromLua;
|
||||
use crate::userdata::AnyUserData;
|
||||
use crate::util::get_userdata;
|
||||
use crate::util::{get_userdata, short_type_name};
|
||||
use crate::value::Value;
|
||||
|
||||
use super::cell::{UserDataStorage, UserDataVariant};
|
||||
@@ -449,7 +449,7 @@ fn try_value_to_userdata<T>(value: Value) -> Result<AnyUserData> {
|
||||
_ => Err(Error::FromLuaConversionError {
|
||||
from: value.type_name(),
|
||||
to: "userdata".to_string(),
|
||||
message: Some(format!("expected userdata of type {}", type_name::<T>())),
|
||||
message: Some(format!("expected userdata of type {}", short_type_name::<T>())),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
+4
-13
@@ -354,7 +354,7 @@ unsafe fn init_userdata_metatable_index(state: *mut ffi::lua_State) -> Result<()
|
||||
end
|
||||
"#;
|
||||
protect_lua!(state, 0, 1, |state| {
|
||||
let ret = ffi::luaL_loadbuffer(state, code.as_ptr(), code.count_bytes(), cstr!("__mlua_index"));
|
||||
let ret = ffi::luaL_loadbuffer(state, code.as_ptr(), code.count_bytes(), cstr!("=__mlua_index"));
|
||||
if ret != ffi::LUA_OK {
|
||||
ffi::lua_error(state);
|
||||
}
|
||||
@@ -405,7 +405,8 @@ unsafe fn init_userdata_metatable_newindex(state: *mut ffi::lua_State) -> Result
|
||||
end
|
||||
"#;
|
||||
protect_lua!(state, 0, 1, |state| {
|
||||
let ret = ffi::luaL_loadbuffer(state, code.as_ptr(), code.count_bytes(), cstr!("__mlua_newindex"));
|
||||
let code_len = code.count_bytes();
|
||||
let ret = ffi::luaL_loadbuffer(state, code.as_ptr(), code_len, cstr!("=__mlua_newindex"));
|
||||
if ret != ffi::LUA_OK {
|
||||
ffi::lua_error(state);
|
||||
}
|
||||
@@ -436,18 +437,8 @@ pub(crate) unsafe extern "C-unwind" fn collect_userdata<T>(state: *mut ffi::lua_
|
||||
|
||||
// This method is called by Luau GC when it's time to collect the userdata.
|
||||
#[cfg(feature = "luau")]
|
||||
pub(crate) unsafe extern "C" fn collect_userdata<T>(
|
||||
state: *mut ffi::lua_State,
|
||||
ud: *mut std::os::raw::c_void,
|
||||
) {
|
||||
// Almost none Lua operations are allowed when destructor is running,
|
||||
// so we need to set a flag to prevent calling any Lua functions
|
||||
let extra = (*ffi::lua_callbacks(state)).userdata as *mut crate::state::ExtraData;
|
||||
(*extra).running_gc = true;
|
||||
// Luau does not support _any_ panics in destructors (they are declared as "C", NOT as "C-unwind"),
|
||||
// so any panics will trigger `abort()`.
|
||||
pub(crate) unsafe extern "C-unwind" fn collect_userdata<T>(ud: *mut std::os::raw::c_void) {
|
||||
ptr::drop_in_place(ud as *mut T);
|
||||
(*extra).running_gc = false;
|
||||
}
|
||||
|
||||
// This method can be called by user or Lua GC to destroy the userdata.
|
||||
|
||||
+1
-1
@@ -315,7 +315,7 @@ pub(crate) unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<(
|
||||
let _ = write!(&mut (*err_buf), "{error}");
|
||||
Ok(err_buf)
|
||||
}
|
||||
Some(WrappedFailure::Panic(Some(panic))) => {
|
||||
Some(WrappedFailure::Panic(Some(ref panic))) => {
|
||||
let err_buf_key = &ERROR_PRINT_BUFFER_KEY as *const u8 as *const c_void;
|
||||
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, err_buf_key);
|
||||
let err_buf = ffi::lua_touserdata(state, -1) as *mut String;
|
||||
|
||||
+17
-15
@@ -10,71 +10,73 @@ pub(crate) trait TypeKey: Any {
|
||||
fn type_key() -> *const c_void;
|
||||
}
|
||||
|
||||
static STRING_TYPE_KEY: u8 = 0;
|
||||
|
||||
impl TypeKey for String {
|
||||
#[inline(always)]
|
||||
fn type_key() -> *const c_void {
|
||||
static STRING_TYPE_KEY: u8 = 0;
|
||||
&STRING_TYPE_KEY as *const u8 as *const c_void
|
||||
}
|
||||
}
|
||||
|
||||
static CALLBACK_TYPE_KEY: u8 = 0;
|
||||
|
||||
impl TypeKey for Callback {
|
||||
#[inline(always)]
|
||||
fn type_key() -> *const c_void {
|
||||
static CALLBACK_TYPE_KEY: u8 = 0;
|
||||
&CALLBACK_TYPE_KEY as *const u8 as *const c_void
|
||||
}
|
||||
}
|
||||
|
||||
static CALLBACK_UPVALUE_TYPE_KEY: u8 = 0;
|
||||
|
||||
impl TypeKey for CallbackUpvalue {
|
||||
#[inline(always)]
|
||||
fn type_key() -> *const c_void {
|
||||
static CALLBACK_UPVALUE_TYPE_KEY: u8 = 0;
|
||||
&CALLBACK_UPVALUE_TYPE_KEY as *const u8 as *const c_void
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
impl TypeKey for crate::types::HookCallback {
|
||||
#[inline(always)]
|
||||
fn type_key() -> *const c_void {
|
||||
static HOOK_CALLBACK_TYPE_KEY: u8 = 0;
|
||||
&HOOK_CALLBACK_TYPE_KEY as *const u8 as *const c_void
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "async")]
|
||||
static ASYNC_CALLBACK_TYPE_KEY: u8 = 0;
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
impl TypeKey for AsyncCallback {
|
||||
#[inline(always)]
|
||||
fn type_key() -> *const c_void {
|
||||
static ASYNC_CALLBACK_TYPE_KEY: u8 = 0;
|
||||
&ASYNC_CALLBACK_TYPE_KEY as *const u8 as *const c_void
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
static ASYNC_CALLBACK_UPVALUE_TYPE_KEY: u8 = 0;
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
impl TypeKey for AsyncCallbackUpvalue {
|
||||
#[inline(always)]
|
||||
fn type_key() -> *const c_void {
|
||||
static ASYNC_CALLBACK_UPVALUE_TYPE_KEY: u8 = 0;
|
||||
&ASYNC_CALLBACK_UPVALUE_TYPE_KEY as *const u8 as *const c_void
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
static ASYNC_POLL_UPVALUE_TYPE_KEY: u8 = 0;
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
impl TypeKey for AsyncPollUpvalue {
|
||||
#[inline(always)]
|
||||
fn type_key() -> *const c_void {
|
||||
static ASYNC_POLL_UPVALUE_TYPE_KEY: u8 = 0;
|
||||
&ASYNC_POLL_UPVALUE_TYPE_KEY as *const u8 as *const c_void
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
static WAKER_TYPE_KEY: u8 = 0;
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
impl TypeKey for Option<std::task::Waker> {
|
||||
#[inline(always)]
|
||||
fn type_key() -> *const c_void {
|
||||
static WAKER_TYPE_KEY: u8 = 0;
|
||||
&WAKER_TYPE_KEY as *const u8 as *const c_void
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,23 +15,20 @@ pub(crate) unsafe fn push_internal_userdata<T: TypeKey>(
|
||||
#[cfg(not(feature = "luau"))]
|
||||
let ud_ptr = if protect {
|
||||
protect_lua!(state, 0, 1, move |state| {
|
||||
let ud_ptr = ffi::lua_newuserdata(state, const { mem::size_of::<T>() }) as *mut T;
|
||||
ptr::write(ud_ptr, t);
|
||||
ud_ptr
|
||||
ffi::lua_newuserdata(state, const { mem::size_of::<T>() }) as *mut T
|
||||
})?
|
||||
} else {
|
||||
let ud_ptr = ffi::lua_newuserdata(state, const { mem::size_of::<T>() }) as *mut T;
|
||||
ptr::write(ud_ptr, t);
|
||||
ud_ptr
|
||||
ffi::lua_newuserdata(state, const { mem::size_of::<T>() }) as *mut T
|
||||
};
|
||||
|
||||
#[cfg(feature = "luau")]
|
||||
let ud_ptr = if protect {
|
||||
protect_lua!(state, 0, 1, move |state| ffi::lua_newuserdata_t::<T>(state, t))?
|
||||
protect_lua!(state, 0, 1, move |state| ffi::lua_newuserdata_t::<T>(state))?
|
||||
} else {
|
||||
ffi::lua_newuserdata_t::<T>(state, t)
|
||||
ffi::lua_newuserdata_t::<T>(state)
|
||||
};
|
||||
|
||||
ptr::write(ud_ptr, t);
|
||||
get_internal_metatable::<T>(state);
|
||||
ffi::lua_setmetatable(state, -2);
|
||||
Ok(ud_ptr)
|
||||
|
||||
+1
-4
@@ -272,10 +272,7 @@ impl Value {
|
||||
/// If the value is a Lua [`Integer`], try to convert it to `i64` or return `None` otherwise.
|
||||
#[inline]
|
||||
pub fn as_i64(&self) -> Option<i64> {
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
return self.as_integer();
|
||||
#[cfg(not(target_pointer_width = "64"))]
|
||||
return self.as_integer().map(i64::from);
|
||||
self.as_integer().map(i64::from)
|
||||
}
|
||||
|
||||
/// Cast the value to `u64`.
|
||||
|
||||
+3
-61
@@ -273,7 +273,7 @@ async fn test_async_lua54_to_be_closed() -> Result<()> {
|
||||
|
||||
// Don't close by default when awaiting async threads
|
||||
let co = lua.create_thread(f.clone())?;
|
||||
let _ = co.clone().into_async::<()>(())?.await;
|
||||
let _ = co.clone().into_async::<()>(()).await;
|
||||
assert_eq!(globals.get::<usize>("close_count")?, 1);
|
||||
let _ = co.reset(f);
|
||||
assert_eq!(globals.get::<usize>("close_count")?, 2);
|
||||
@@ -300,7 +300,7 @@ async fn test_async_thread_stream() -> Result<()> {
|
||||
.eval()?,
|
||||
)?;
|
||||
|
||||
let mut stream = thread.into_async::<i64>(1)?;
|
||||
let mut stream = thread.into_async::<i64>(1);
|
||||
let mut sum = 0;
|
||||
while let Some(n) = stream.try_next().await? {
|
||||
sum += n;
|
||||
@@ -325,7 +325,7 @@ async fn test_async_thread() -> Result<()> {
|
||||
}
|
||||
})?;
|
||||
|
||||
let res: String = lua.create_thread(f)?.into_async(())?.await?;
|
||||
let res: String = lua.create_thread(f)?.into_async(()).await?;
|
||||
|
||||
assert_eq!(res, "done");
|
||||
|
||||
@@ -567,61 +567,3 @@ async fn test_async_terminate() -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_async_task() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let delay = lua.create_function(|lua, (secs, f, args): (f32, Function, MultiValue)| {
|
||||
let thread = lua.create_thread(f)?;
|
||||
let thread2 = thread.clone().into_async::<()>(args)?;
|
||||
tokio::task::spawn_local(async move {
|
||||
tokio::time::sleep(Duration::from_secs_f32(secs)).await;
|
||||
_ = thread2.await;
|
||||
});
|
||||
Ok(thread)
|
||||
})?;
|
||||
|
||||
lua.globals().set("delay", delay)?;
|
||||
let local = tokio::task::LocalSet::new();
|
||||
local
|
||||
.run_until(async {
|
||||
_ = lua
|
||||
.load("delay(0.1, function(msg) global_msg = msg end, 'done')")
|
||||
.exec_async()
|
||||
.await;
|
||||
})
|
||||
.await;
|
||||
local.await;
|
||||
assert_eq!(lua.globals().get::<String>("global_msg")?, "done");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[cfg(not(feature = "luau"))]
|
||||
async fn test_async_hook() -> Result<()> {
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
let lua = Lua::new();
|
||||
|
||||
static HOOK_CALLED: AtomicBool = AtomicBool::new(false);
|
||||
lua.set_global_hook(mlua::HookTriggers::new().every_line(), move |_, _| {
|
||||
if !HOOK_CALLED.swap(true, Ordering::Relaxed) {
|
||||
#[cfg(any(feature = "lu53", feature = "lua54"))]
|
||||
return Ok(mlua::VmState::Yield);
|
||||
}
|
||||
Ok(mlua::VmState::Continue)
|
||||
})?;
|
||||
|
||||
let sleep = lua.create_async_function(move |_lua, n: u64| async move {
|
||||
sleep_ms(n).await;
|
||||
Ok(())
|
||||
})?;
|
||||
lua.globals().set("sleep", sleep)?;
|
||||
|
||||
lua.load(r"sleep(100)").exec_async().await?;
|
||||
assert!(HOOK_CALLED.load(Ordering::Relaxed));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+6
-31
@@ -7,7 +7,7 @@ fn test_chunk_methods() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
#[cfg(unix)]
|
||||
assert!(lua.load("return 123").name().starts_with("@tests/chunk.rs"));
|
||||
assert!(lua.load("return 123").name().contains("tests/chunk.rs"));
|
||||
let chunk2 = lua.load("return 123").set_name("@new_name");
|
||||
assert_eq!(chunk2.name(), "@new_name");
|
||||
|
||||
@@ -114,6 +114,8 @@ fn test_chunk_macro() -> Result<()> {
|
||||
#[cfg(feature = "luau")]
|
||||
#[test]
|
||||
fn test_compiler() -> Result<()> {
|
||||
use std::vec;
|
||||
|
||||
let compiler = mlua::Compiler::new()
|
||||
.set_optimization_level(2)
|
||||
.set_debug_level(2)
|
||||
@@ -122,11 +124,10 @@ fn test_compiler() -> Result<()> {
|
||||
.set_vector_lib("vector")
|
||||
.set_vector_ctor("new")
|
||||
.set_vector_type("vector")
|
||||
.set_mutable_globals(vec!["mutable_global"])
|
||||
.set_userdata_types(vec!["MyUserdata"])
|
||||
.set_disabled_builtins(vec!["tostring"]);
|
||||
.set_mutable_globals(vec!["mutable_global".into()])
|
||||
.set_userdata_types(vec!["MyUserdata".into()]);
|
||||
|
||||
assert!(compiler.compile("return tostring(vector.new(1, 2, 3))").is_ok());
|
||||
assert!(compiler.compile("return vector.new(1, 2, 3)").is_ok());
|
||||
|
||||
// Error
|
||||
match compiler.compile("%") {
|
||||
@@ -139,32 +140,6 @@ fn test_compiler() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "luau")]
|
||||
#[test]
|
||||
fn test_compiler_library_constants() {
|
||||
use mlua::{CompileConstant, Compiler, Vector};
|
||||
|
||||
let compiler = Compiler::new()
|
||||
.set_optimization_level(2)
|
||||
.set_library_constants(vec![
|
||||
("mylib", "const_bool", CompileConstant::Boolean(true)),
|
||||
("mylib", "const_num", CompileConstant::Number(123.0)),
|
||||
("mylib", "const_vec", CompileConstant::Vector(Vector::zero())),
|
||||
("mylib", "const_str", "value1".into()),
|
||||
]);
|
||||
|
||||
let lua = Lua::new();
|
||||
lua.set_compiler(compiler);
|
||||
let const_bool = lua.load("return mylib.const_bool").eval::<bool>().unwrap();
|
||||
assert_eq!(const_bool, true);
|
||||
let const_num = lua.load("return mylib.const_num").eval::<f64>().unwrap();
|
||||
assert_eq!(const_num, 123.0);
|
||||
let const_vec = lua.load("return mylib.const_vec").eval::<Vector>().unwrap();
|
||||
assert_eq!(const_vec, Vector::zero());
|
||||
let const_str = lua.load("return mylib.const_str").eval::<String>();
|
||||
assert_eq!(const_str.unwrap(), "value1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_chunk_wrap() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
@@ -1,32 +1,28 @@
|
||||
error[E0277]: the type `UnsafeCell<mlua::state::raw::RawLua>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
error[E0277]: the type `UnsafeCell<*mut lua_State>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
--> tests/compile/lua_norefunwindsafe.rs:7:18
|
||||
|
|
||||
7 | catch_unwind(|| lua.create_table().unwrap());
|
||||
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<mlua::state::raw::RawLua>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<*mut lua_State>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: within `Lua`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<mlua::state::raw::RawLua>`, which is required by `{closure@$DIR/tests/compile/lua_norefunwindsafe.rs:7:18: 7:20}: UnwindSafe`
|
||||
note: required because it appears within the type `lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>`
|
||||
--> $CARGO/lock_api-0.4.12/src/remutex.rs
|
||||
= help: within `mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<*mut lua_State>`
|
||||
note: required because it appears within the type `Cell<*mut lua_State>`
|
||||
--> $RUST/core/src/cell.rs
|
||||
|
|
||||
| pub struct ReentrantMutex<R, G, T: ?Sized> {
|
||||
| ^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/sync.rs
|
||||
| pub struct Cell<T: ?Sized> {
|
||||
| ^^^^
|
||||
note: required because it appears within the type `mlua::state::raw::RawLua`
|
||||
--> src/state/raw.rs
|
||||
|
|
||||
| struct ArcInner<T: ?Sized> {
|
||||
| ^^^^^^^^
|
||||
note: required because it appears within the type `PhantomData<alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>>`
|
||||
--> $RUST/core/src/marker.rs
|
||||
| pub struct RawLua {
|
||||
| ^^^^^^
|
||||
note: required because it appears within the type `mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>`
|
||||
--> src/types/sync.rs
|
||||
|
|
||||
| pub struct PhantomData<T: ?Sized>;
|
||||
| ^^^^^^^^^^^
|
||||
note: required because it appears within the type `Arc<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/sync.rs
|
||||
|
|
||||
| pub struct Arc<
|
||||
| ^^^
|
||||
| pub(crate) struct ReentrantMutex<T>(T);
|
||||
| ^^^^^^^^^^^^^^
|
||||
= note: required for `Rc<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>` to implement `RefUnwindSafe`
|
||||
note: required because it appears within the type `Lua`
|
||||
--> src/state.rs
|
||||
|
|
||||
@@ -44,45 +40,27 @@ note: required by a bound in `std::panic::catch_unwind`
|
||||
| pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
|
||||
| ^^^^^^^^^^ required by this bound in `catch_unwind`
|
||||
|
||||
error[E0277]: the type `UnsafeCell<usize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
error[E0277]: the type `UnsafeCell<mlua::state::extra::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
--> tests/compile/lua_norefunwindsafe.rs:7:18
|
||||
|
|
||||
7 | catch_unwind(|| lua.create_table().unwrap());
|
||||
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<usize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<mlua::state::extra::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: within `Lua`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<usize>`, which is required by `{closure@$DIR/tests/compile/lua_norefunwindsafe.rs:7:18: 7:20}: UnwindSafe`
|
||||
note: required because it appears within the type `Cell<usize>`
|
||||
--> $RUST/core/src/cell.rs
|
||||
= help: the trait `RefUnwindSafe` is not implemented for `UnsafeCell<mlua::state::extra::ExtraData>`
|
||||
= note: required for `Rc<UnsafeCell<mlua::state::extra::ExtraData>>` to implement `RefUnwindSafe`
|
||||
note: required because it appears within the type `mlua::state::raw::RawLua`
|
||||
--> src/state/raw.rs
|
||||
|
|
||||
| pub struct Cell<T: ?Sized> {
|
||||
| ^^^^
|
||||
note: required because it appears within the type `lock_api::remutex::RawReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId>`
|
||||
--> $CARGO/lock_api-0.4.12/src/remutex.rs
|
||||
| pub struct RawLua {
|
||||
| ^^^^^^
|
||||
note: required because it appears within the type `mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>`
|
||||
--> src/types/sync.rs
|
||||
|
|
||||
| pub struct RawReentrantMutex<R, G> {
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>`
|
||||
--> $CARGO/lock_api-0.4.12/src/remutex.rs
|
||||
|
|
||||
| pub struct ReentrantMutex<R, G, T: ?Sized> {
|
||||
| ^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/sync.rs
|
||||
|
|
||||
| struct ArcInner<T: ?Sized> {
|
||||
| ^^^^^^^^
|
||||
note: required because it appears within the type `PhantomData<alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>>`
|
||||
--> $RUST/core/src/marker.rs
|
||||
|
|
||||
| pub struct PhantomData<T: ?Sized>;
|
||||
| ^^^^^^^^^^^
|
||||
note: required because it appears within the type `Arc<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/sync.rs
|
||||
|
|
||||
| pub struct Arc<
|
||||
| ^^^
|
||||
| pub(crate) struct ReentrantMutex<T>(T);
|
||||
| ^^^^^^^^^^^^^^
|
||||
= note: required for `Rc<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>` to implement `RefUnwindSafe`
|
||||
note: required because it appears within the type `Lua`
|
||||
--> src/state.rs
|
||||
|
|
||||
|
||||
@@ -8,7 +8,7 @@ error[E0277]: `Rc<Cell<i32>>` cannot be sent between threads safely
|
||||
| | within this `{closure@$DIR/tests/compile/non_send.rs:11:25: 11:37}`
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: within `{closure@$DIR/tests/compile/non_send.rs:11:25: 11:37}`, the trait `Send` is not implemented for `Rc<Cell<i32>>`, which is required by `{closure@$DIR/tests/compile/non_send.rs:11:25: 11:37}: MaybeSend`
|
||||
= help: within `{closure@$DIR/tests/compile/non_send.rs:11:25: 11:37}`, the trait `Send` is not implemented for `Rc<Cell<i32>>`
|
||||
note: required because it's used within this closure
|
||||
--> tests/compile/non_send.rs:11:25
|
||||
|
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
error[E0277]: the type `UnsafeCell<mlua::state::raw::RawLua>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
error[E0277]: the type `UnsafeCell<usize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
--> tests/compile/ref_nounwindsafe.rs:8:18
|
||||
|
|
||||
8 | catch_unwind(move || table.set("a", "b").unwrap());
|
||||
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<mlua::state::raw::RawLua>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<usize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: within `alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<mlua::state::raw::RawLua>`, which is required by `{closure@$DIR/tests/compile/ref_nounwindsafe.rs:8:18: 8:25}: UnwindSafe`
|
||||
note: required because it appears within the type `lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>`
|
||||
--> $CARGO/lock_api-0.4.12/src/remutex.rs
|
||||
= help: within `rc::RcInner<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<usize>`
|
||||
note: required because it appears within the type `Cell<usize>`
|
||||
--> $RUST/core/src/cell.rs
|
||||
|
|
||||
| pub struct ReentrantMutex<R, G, T: ?Sized> {
|
||||
| ^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/sync.rs
|
||||
| pub struct Cell<T: ?Sized> {
|
||||
| ^^^^
|
||||
note: required because it appears within the type `rc::RcInner<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/rc.rs
|
||||
|
|
||||
| struct ArcInner<T: ?Sized> {
|
||||
| ^^^^^^^^
|
||||
= note: required for `NonNull<alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>>` to implement `UnwindSafe`
|
||||
note: required because it appears within the type `std::sync::Weak<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/sync.rs
|
||||
| struct RcInner<T: ?Sized> {
|
||||
| ^^^^^^^
|
||||
= note: required for `NonNull<rc::RcInner<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>>` to implement `UnwindSafe`
|
||||
note: required because it appears within the type `std::rc::Weak<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/rc.rs
|
||||
|
|
||||
| pub struct Weak<
|
||||
| ^^^^
|
||||
note: required because it appears within the type `mlua::state::WeakLua`
|
||||
note: required because it appears within the type `WeakLua`
|
||||
--> src/state.rs
|
||||
|
|
||||
| pub(crate) struct WeakLua(XWeak<ReentrantMutex<RawLua>>);
|
||||
| ^^^^^^^
|
||||
note: required because it appears within the type `mlua::types::ValueRef`
|
||||
--> src/types.rs
|
||||
| pub struct WeakLua(XWeak<ReentrantMutex<RawLua>>);
|
||||
| ^^^^^^^
|
||||
note: required because it appears within the type `mlua::types::value_ref::ValueRef`
|
||||
--> src/types/value_ref.rs
|
||||
|
|
||||
| pub(crate) struct ValueRef {
|
||||
| ^^^^^^^^
|
||||
| pub struct ValueRef {
|
||||
| ^^^^^^^^
|
||||
note: required because it appears within the type `LuaTable`
|
||||
--> src/table.rs
|
||||
|
|
||||
@@ -49,51 +49,108 @@ note: required by a bound in `std::panic::catch_unwind`
|
||||
| pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
|
||||
| ^^^^^^^^^^ required by this bound in `catch_unwind`
|
||||
|
||||
error[E0277]: the type `UnsafeCell<usize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
error[E0277]: the type `UnsafeCell<*mut lua_State>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
--> tests/compile/ref_nounwindsafe.rs:8:18
|
||||
|
|
||||
8 | catch_unwind(move || table.set("a", "b").unwrap());
|
||||
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<usize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<*mut lua_State>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: within `alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<usize>`, which is required by `{closure@$DIR/tests/compile/ref_nounwindsafe.rs:8:18: 8:25}: UnwindSafe`
|
||||
note: required because it appears within the type `Cell<usize>`
|
||||
= help: within `rc::RcInner<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<*mut lua_State>`
|
||||
note: required because it appears within the type `Cell<*mut lua_State>`
|
||||
--> $RUST/core/src/cell.rs
|
||||
|
|
||||
| pub struct Cell<T: ?Sized> {
|
||||
| ^^^^
|
||||
note: required because it appears within the type `lock_api::remutex::RawReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId>`
|
||||
--> $CARGO/lock_api-0.4.12/src/remutex.rs
|
||||
note: required because it appears within the type `mlua::state::raw::RawLua`
|
||||
--> src/state/raw.rs
|
||||
|
|
||||
| pub struct RawReentrantMutex<R, G> {
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>`
|
||||
--> $CARGO/lock_api-0.4.12/src/remutex.rs
|
||||
| pub struct RawLua {
|
||||
| ^^^^^^
|
||||
note: required because it appears within the type `mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>`
|
||||
--> src/types/sync.rs
|
||||
|
|
||||
| pub struct ReentrantMutex<R, G, T: ?Sized> {
|
||||
| ^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/sync.rs
|
||||
| pub(crate) struct ReentrantMutex<T>(T);
|
||||
| ^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `rc::RcInner<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/rc.rs
|
||||
|
|
||||
| struct ArcInner<T: ?Sized> {
|
||||
| ^^^^^^^^
|
||||
= note: required for `NonNull<alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>>` to implement `UnwindSafe`
|
||||
note: required because it appears within the type `std::sync::Weak<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/sync.rs
|
||||
| struct RcInner<T: ?Sized> {
|
||||
| ^^^^^^^
|
||||
= note: required for `NonNull<rc::RcInner<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>>` to implement `UnwindSafe`
|
||||
note: required because it appears within the type `std::rc::Weak<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/rc.rs
|
||||
|
|
||||
| pub struct Weak<
|
||||
| ^^^^
|
||||
note: required because it appears within the type `mlua::state::WeakLua`
|
||||
note: required because it appears within the type `WeakLua`
|
||||
--> src/state.rs
|
||||
|
|
||||
| pub(crate) struct WeakLua(XWeak<ReentrantMutex<RawLua>>);
|
||||
| ^^^^^^^
|
||||
note: required because it appears within the type `mlua::types::ValueRef`
|
||||
--> src/types.rs
|
||||
| pub struct WeakLua(XWeak<ReentrantMutex<RawLua>>);
|
||||
| ^^^^^^^
|
||||
note: required because it appears within the type `mlua::types::value_ref::ValueRef`
|
||||
--> src/types/value_ref.rs
|
||||
|
|
||||
| pub(crate) struct ValueRef {
|
||||
| ^^^^^^^^
|
||||
| pub struct ValueRef {
|
||||
| ^^^^^^^^
|
||||
note: required because it appears within the type `LuaTable`
|
||||
--> src/table.rs
|
||||
|
|
||||
| pub struct Table(pub(crate) ValueRef);
|
||||
| ^^^^^
|
||||
note: required because it's used within this closure
|
||||
--> tests/compile/ref_nounwindsafe.rs:8:18
|
||||
|
|
||||
8 | catch_unwind(move || table.set("a", "b").unwrap());
|
||||
| ^^^^^^^
|
||||
note: required by a bound in `std::panic::catch_unwind`
|
||||
--> $RUST/std/src/panic.rs
|
||||
|
|
||||
| pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
|
||||
| ^^^^^^^^^^ required by this bound in `catch_unwind`
|
||||
|
||||
error[E0277]: the type `UnsafeCell<mlua::state::extra::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
--> tests/compile/ref_nounwindsafe.rs:8:18
|
||||
|
|
||||
8 | catch_unwind(move || table.set("a", "b").unwrap());
|
||||
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<mlua::state::extra::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: the trait `RefUnwindSafe` is not implemented for `UnsafeCell<mlua::state::extra::ExtraData>`
|
||||
= note: required for `Rc<UnsafeCell<mlua::state::extra::ExtraData>>` to implement `RefUnwindSafe`
|
||||
note: required because it appears within the type `mlua::state::raw::RawLua`
|
||||
--> src/state/raw.rs
|
||||
|
|
||||
| pub struct RawLua {
|
||||
| ^^^^^^
|
||||
note: required because it appears within the type `mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>`
|
||||
--> src/types/sync.rs
|
||||
|
|
||||
| pub(crate) struct ReentrantMutex<T>(T);
|
||||
| ^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `rc::RcInner<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/rc.rs
|
||||
|
|
||||
| struct RcInner<T: ?Sized> {
|
||||
| ^^^^^^^
|
||||
= note: required for `NonNull<rc::RcInner<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>>` to implement `UnwindSafe`
|
||||
note: required because it appears within the type `std::rc::Weak<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/rc.rs
|
||||
|
|
||||
| pub struct Weak<
|
||||
| ^^^^
|
||||
note: required because it appears within the type `WeakLua`
|
||||
--> src/state.rs
|
||||
|
|
||||
| pub struct WeakLua(XWeak<ReentrantMutex<RawLua>>);
|
||||
| ^^^^^^^
|
||||
note: required because it appears within the type `mlua::types::value_ref::ValueRef`
|
||||
--> src/types/value_ref.rs
|
||||
|
|
||||
| pub struct ValueRef {
|
||||
| ^^^^^^^^
|
||||
note: required because it appears within the type `LuaTable`
|
||||
--> src/table.rs
|
||||
|
|
||||
|
||||
@@ -2,7 +2,7 @@ error[E0373]: closure may outlive the current function, but it borrows `inner`,
|
||||
--> tests/compile/scope_callback_capture.rs:7:43
|
||||
|
|
||||
5 | lua.scope(|scope| {
|
||||
| ----- has type `&'1 mut mlua::scope::Scope<'1, '_>`
|
||||
| ----- has type `&'1 mlua::Scope<'1, '_>`
|
||||
6 | let mut inner: Option<Table> = None;
|
||||
7 | let f = scope.create_function_mut(|_, t: Table| {
|
||||
| ^^^^^^^^^^^^^ may outlive borrowed value `inner`
|
||||
|
||||
@@ -2,7 +2,7 @@ error[E0373]: closure may outlive the current function, but it borrows `test.fie
|
||||
--> tests/compile/scope_invariance.rs:13:39
|
||||
|
|
||||
9 | lua.scope(|scope| {
|
||||
| ----- has type `&'1 mut mlua::scope::Scope<'1, '_>`
|
||||
| ----- has type `&'1 mlua::Scope<'1, '_>`
|
||||
...
|
||||
13 | scope.create_function_mut(|_, ()| {
|
||||
| ^^^^^^^ may outlive borrowed value `test.field`
|
||||
|
||||
@@ -2,7 +2,7 @@ error[E0499]: cannot borrow `i` as mutable more than once at a time
|
||||
--> tests/compile/scope_mutable_aliasing.rs:12:51
|
||||
|
|
||||
10 | lua.scope(|scope| {
|
||||
| ----- has type `&mut mlua::scope::Scope<'_, '1>`
|
||||
| ----- has type `&mlua::Scope<'_, '1>`
|
||||
11 | let _a = scope.create_userdata(MyUserData(&mut i)).unwrap();
|
||||
| -----------------------------------------
|
||||
| | |
|
||||
|
||||
@@ -2,7 +2,7 @@ error[E0597]: `ibad` does not live long enough
|
||||
--> tests/compile/scope_userdata_borrow.rs:15:46
|
||||
|
|
||||
11 | lua.scope(|scope| {
|
||||
| ----- has type `&mut mlua::scope::Scope<'_, '1>`
|
||||
| ----- has type `&mlua::Scope<'_, '1>`
|
||||
...
|
||||
14 | let ibad = 42;
|
||||
| ---- binding `ibad` declared here
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
use std::borrow::Cow;
|
||||
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
||||
use std::ffi::{CString, OsString};
|
||||
use std::ffi::{CStr, CString, OsString};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use bstr::BString;
|
||||
@@ -450,8 +450,8 @@ fn test_conv_cstring() -> Result<()> {
|
||||
let s2: CString = lua.globals().get("s")?;
|
||||
assert_eq!(s, s2);
|
||||
|
||||
let cs = c"hello";
|
||||
lua.globals().set("cs", c"hello")?;
|
||||
let cs = CStr::from_bytes_with_nul(b"hello\0").unwrap();
|
||||
lua.globals().set("cs", cs)?;
|
||||
let cs2: CString = lua.globals().get("cs")?;
|
||||
assert_eq!(cs, cs2.as_c_str());
|
||||
|
||||
|
||||
+17
-45
@@ -1,5 +1,6 @@
|
||||
#![cfg(not(feature = "luau"))]
|
||||
|
||||
use std::ops::Deref;
|
||||
use std::sync::atomic::{AtomicI64, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
@@ -26,7 +27,7 @@ fn test_line_counts() -> Result<()> {
|
||||
assert_eq!(debug.event(), DebugEvent::Line);
|
||||
hook_output.lock().unwrap().push(debug.curr_line());
|
||||
Ok(VmState::Continue)
|
||||
})?;
|
||||
});
|
||||
lua.load(
|
||||
r#"
|
||||
local x = 2 + 3
|
||||
@@ -61,7 +62,7 @@ fn test_function_calls() -> Result<()> {
|
||||
let name = names.name.map(|s| s.into_owned());
|
||||
hook_output.lock().unwrap().push((name, source.what));
|
||||
Ok(VmState::Continue)
|
||||
})?;
|
||||
});
|
||||
|
||||
lua.load(
|
||||
r#"
|
||||
@@ -100,13 +101,17 @@ fn test_error_within_hook() -> Result<()> {
|
||||
|
||||
lua.set_hook(HookTriggers::EVERY_LINE, |_lua, _debug| {
|
||||
Err(Error::runtime("Something happened in there!"))
|
||||
})?;
|
||||
});
|
||||
|
||||
let err = lua.load("x = 1").exec().expect_err("panic didn't propagate");
|
||||
|
||||
match err {
|
||||
Error::RuntimeError(msg) => assert_eq!(msg, "Something happened in there!"),
|
||||
err => panic!("expected `RuntimeError` with a specific message, got {err:?}"),
|
||||
}
|
||||
Error::CallbackError { cause, .. } => match cause.deref() {
|
||||
Error::RuntimeError(s) => assert_eq!(s, "Something happened in there!"),
|
||||
_ => panic!("wrong callback error kind caught"),
|
||||
},
|
||||
_ => panic!("wrong error kind caught"),
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -130,7 +135,7 @@ fn test_limit_execution_instructions() -> Result<()> {
|
||||
Ok(VmState::Continue)
|
||||
}
|
||||
},
|
||||
)?;
|
||||
);
|
||||
|
||||
lua.globals().set("x", Value::Integer(0))?;
|
||||
let _ = lua
|
||||
@@ -153,7 +158,7 @@ fn test_hook_removal() -> Result<()> {
|
||||
|
||||
lua.set_hook(HookTriggers::new().every_nth_instruction(1), |_lua, _debug| {
|
||||
Err(Error::runtime("this hook should've been removed by this time"))
|
||||
})?;
|
||||
});
|
||||
|
||||
assert!(lua.load("local x = 1").exec().is_err());
|
||||
lua.remove_hook();
|
||||
@@ -200,10 +205,10 @@ fn test_hook_swap_within_hook() -> Result<()> {
|
||||
});
|
||||
Ok(VmState::Continue)
|
||||
})
|
||||
})?;
|
||||
});
|
||||
Ok(VmState::Continue)
|
||||
})
|
||||
})?;
|
||||
});
|
||||
|
||||
TL_LUA.with(|tl| {
|
||||
let tl = tl.borrow();
|
||||
@@ -242,7 +247,7 @@ fn test_hook_threads() -> Result<()> {
|
||||
assert_eq!(debug.event(), DebugEvent::Line);
|
||||
hook_output.lock().unwrap().push(debug.curr_line());
|
||||
Ok(VmState::Continue)
|
||||
})?;
|
||||
});
|
||||
|
||||
co.resume::<()>(())?;
|
||||
lua.remove_hook();
|
||||
@@ -272,7 +277,7 @@ fn test_hook_yield() -> Result<()> {
|
||||
.into_function()?;
|
||||
let co = lua.create_thread(func)?;
|
||||
|
||||
co.set_hook(HookTriggers::EVERY_LINE, move |_lua, _debug| Ok(VmState::Yield))?;
|
||||
co.set_hook(HookTriggers::EVERY_LINE, move |_lua, _debug| Ok(VmState::Yield));
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
{
|
||||
@@ -292,36 +297,3 @@ fn test_hook_yield() -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_global_hook() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let counter = Arc::new(AtomicI64::new(0));
|
||||
let hook_counter = counter.clone();
|
||||
lua.set_global_hook(HookTriggers::EVERY_LINE, move |_lua, debug| {
|
||||
assert_eq!(debug.event(), DebugEvent::Line);
|
||||
hook_counter.fetch_add(1, Ordering::Relaxed);
|
||||
Ok(VmState::Continue)
|
||||
})?;
|
||||
|
||||
let thread = lua.create_thread(
|
||||
lua.load(
|
||||
r#"
|
||||
local x = 2 + 3
|
||||
local y = x * 63
|
||||
coroutine.yield()
|
||||
local z = string.len(x..", "..y)
|
||||
"#,
|
||||
)
|
||||
.into_function()?,
|
||||
)?;
|
||||
|
||||
thread.resume::<()>(()).unwrap();
|
||||
lua.remove_global_hook();
|
||||
thread.resume::<()>(()).unwrap();
|
||||
assert_eq!(thread.status(), ThreadStatus::Finished);
|
||||
assert_eq!(counter.load(Ordering::Relaxed), 3);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+84
-89
@@ -1,10 +1,9 @@
|
||||
#![cfg(feature = "luau")]
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::fmt::Debug;
|
||||
use std::os::raw::c_void;
|
||||
use std::fs;
|
||||
use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||
use std::sync::atomic::{AtomicBool, AtomicPtr, AtomicU64, Ordering};
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
use mlua::{Compiler, Error, Lua, LuaOptions, Result, StdLib, Table, ThreadStatus, Value, Vector, VmState};
|
||||
@@ -16,6 +15,83 @@ fn test_version() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_require() -> Result<()> {
|
||||
// Ensure that require() is not available if package module is not loaded
|
||||
let mut lua = Lua::new_with(StdLib::NONE, LuaOptions::default())?;
|
||||
assert!(lua.globals().get::<Option<Value>>("require")?.is_none());
|
||||
assert!(lua.globals().get::<Option<Value>>("package")?.is_none());
|
||||
|
||||
if cfg!(target_arch = "wasm32") {
|
||||
// TODO: figure out why emscripten fails on file operations
|
||||
// Also see https://github.com/rust-lang/rust/issues/119250
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
lua = Lua::new();
|
||||
|
||||
// Check that require() can load stdlib modules (including `package`)
|
||||
lua.load(
|
||||
r#"
|
||||
local math = require("math")
|
||||
assert(math == _G.math, "math module does not match _G.math")
|
||||
local package = require("package")
|
||||
assert(package == _G.package, "package module does not match _G.package")
|
||||
"#,
|
||||
)
|
||||
.exec()?;
|
||||
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
fs::write(
|
||||
temp_dir.path().join("module.luau"),
|
||||
r#"
|
||||
counter = (counter or 0) + 1
|
||||
return {
|
||||
counter = counter,
|
||||
error = function() error("test") end,
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
|
||||
lua.globals()
|
||||
.get::<Table>("package")?
|
||||
.set("path", temp_dir.path().join("?.luau").to_string_lossy())?;
|
||||
|
||||
lua.load(
|
||||
r#"
|
||||
local module = require("module")
|
||||
assert(module.counter == 1)
|
||||
module = require("module")
|
||||
assert(module.counter == 1)
|
||||
|
||||
local ok, err = pcall(module.error)
|
||||
assert(not ok and string.find(err, "module.luau") ~= nil)
|
||||
"#,
|
||||
)
|
||||
.exec()?;
|
||||
|
||||
// Require non-existent module
|
||||
match lua.load("require('non-existent')").exec() {
|
||||
Err(Error::RuntimeError(e)) if e.contains("module 'non-existent' not found") => {}
|
||||
r => panic!("expected RuntimeError(...) with a specific message, got {r:?}"),
|
||||
}
|
||||
|
||||
// Require binary module in safe mode
|
||||
lua.globals()
|
||||
.get::<Table>("package")?
|
||||
.set("cpath", temp_dir.path().join("?.so").to_string_lossy())?;
|
||||
fs::write(temp_dir.path().join("dylib.so"), "")?;
|
||||
match lua.load("require('dylib')").exec() {
|
||||
Err(Error::RuntimeError(e)) if cfg!(unix) && e.contains("module 'dylib' not found") => {
|
||||
assert!(e.contains("dynamic libraries are disabled in safe mode"))
|
||||
}
|
||||
Err(Error::RuntimeError(e)) if e.contains("module 'dylib' not found") => {}
|
||||
r => panic!("expected RuntimeError(...) with a specific message, got {r:?}"),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "luau-vector4"))]
|
||||
#[test]
|
||||
fn test_vectors() -> Result<()> {
|
||||
@@ -319,8 +395,11 @@ fn test_interrupts() -> Result<()> {
|
||||
//
|
||||
lua.set_interrupt(|_| Err(Error::runtime("error from interrupt")));
|
||||
match f.call::<()>(()) {
|
||||
Err(Error::RuntimeError(ref msg)) => assert_eq!(msg, "error from interrupt"),
|
||||
res => panic!("expected `RuntimeError` with a specific message, got {res:?}"),
|
||||
Err(Error::CallbackError { cause, .. }) => match *cause {
|
||||
Error::RuntimeError(ref m) if m == "error from interrupt" => {}
|
||||
ref e => panic!("expected RuntimeError with a specific message, got {:?}", e),
|
||||
},
|
||||
r => panic!("expected CallbackError, got {:?}", r),
|
||||
}
|
||||
|
||||
lua.remove_interrupt();
|
||||
@@ -333,87 +412,3 @@ fn test_fflags() {
|
||||
// We cannot really on any particular feature flag to be present
|
||||
assert!(Lua::set_fflag("UnknownFlag", true).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_thread_events() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let count = Arc::new(AtomicU64::new(0));
|
||||
let thread_data: Arc<(AtomicPtr<c_void>, AtomicBool)> = Arc::new(Default::default());
|
||||
|
||||
let (count2, thread_data2) = (count.clone(), thread_data.clone());
|
||||
lua.set_thread_creation_callback(move |_, thread| {
|
||||
count2.fetch_add(1, Ordering::Relaxed);
|
||||
(thread_data2.0).store(thread.to_pointer() as *mut _, Ordering::Relaxed);
|
||||
thread_data2.1.store(false, Ordering::Relaxed);
|
||||
Ok(())
|
||||
});
|
||||
let (count3, thread_data3) = (count.clone(), thread_data.clone());
|
||||
lua.set_thread_collection_callback(move |thread_ptr| {
|
||||
count3.fetch_add(1, Ordering::Relaxed);
|
||||
if thread_data3.0.load(Ordering::Relaxed) == thread_ptr.0 {
|
||||
thread_data3.1.store(true, Ordering::Relaxed);
|
||||
}
|
||||
});
|
||||
|
||||
let t = lua.create_thread(lua.load("return 123").into_function()?)?;
|
||||
assert_eq!(count.load(Ordering::Relaxed), 1);
|
||||
let t_ptr = t.to_pointer();
|
||||
assert_eq!(t_ptr, thread_data.0.load(Ordering::Relaxed));
|
||||
assert!(!thread_data.1.load(Ordering::Relaxed));
|
||||
|
||||
// Thead will be destroyed after GC cycle
|
||||
drop(t);
|
||||
lua.gc_collect()?;
|
||||
assert_eq!(count.load(Ordering::Relaxed), 2);
|
||||
assert_eq!(t_ptr, thread_data.0.load(Ordering::Relaxed));
|
||||
assert!(thread_data.1.load(Ordering::Relaxed));
|
||||
|
||||
// Check that recursion is not allowed
|
||||
let count4 = count.clone();
|
||||
lua.set_thread_creation_callback(move |lua, _value| {
|
||||
count4.fetch_add(1, Ordering::Relaxed);
|
||||
let _ = lua.create_thread(lua.load("return 123").into_function().unwrap())?;
|
||||
Ok(())
|
||||
});
|
||||
let t = lua.create_thread(lua.load("return 123").into_function()?)?;
|
||||
assert_eq!(count.load(Ordering::Relaxed), 3);
|
||||
|
||||
lua.remove_thread_callbacks();
|
||||
drop(t);
|
||||
lua.gc_collect()?;
|
||||
assert_eq!(count.load(Ordering::Relaxed), 3);
|
||||
|
||||
// Test error inside callback
|
||||
lua.set_thread_creation_callback(move |_, _| Err(Error::runtime("error when processing thread event")));
|
||||
let result = lua.create_thread(lua.load("return 123").into_function()?);
|
||||
assert!(result.is_err());
|
||||
assert!(
|
||||
matches!(result, Err(Error::RuntimeError(err)) if err.contains("error when processing thread event"))
|
||||
);
|
||||
|
||||
// Test context switch when running Lua script
|
||||
let count = Cell::new(0);
|
||||
lua.set_thread_creation_callback(move |_, _| {
|
||||
count.set(count.get() + 1);
|
||||
if count.get() == 2 {
|
||||
return Err(Error::runtime("thread limit exceeded"));
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
let result = lua
|
||||
.load(
|
||||
r#"
|
||||
local co = coroutine.wrap(function() return coroutine.create(print) end)
|
||||
co()
|
||||
"#,
|
||||
)
|
||||
.exec();
|
||||
assert!(result.is_err());
|
||||
assert!(matches!(result, Err(Error::RuntimeError(err)) if err.contains("thread limit exceeded")));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[path = "luau/require.rs"]
|
||||
mod require;
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
use mlua::{IntoLua, Lua, Result, Value};
|
||||
|
||||
fn run_require(lua: &Lua, path: impl IntoLua) -> Result<Value> {
|
||||
lua.load(r#"return require(...)"#).call(path)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn get_str(value: &Value, key: impl IntoLua) -> String {
|
||||
value.as_table().unwrap().get::<String>(key).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_require_errors() {
|
||||
let lua = Lua::new();
|
||||
|
||||
// RequireAbsolutePath
|
||||
let res = run_require(&lua, "/an/absolute/path");
|
||||
assert!(res.is_err());
|
||||
assert!(
|
||||
(res.unwrap_err().to_string()).contains("require path must start with a valid prefix: ./, ../, or @")
|
||||
);
|
||||
|
||||
// RequireUnprefixedPath
|
||||
let res = run_require(&lua, "an/unprefixed/path");
|
||||
assert!(res.is_err());
|
||||
assert!(
|
||||
(res.unwrap_err().to_string()).contains("require path must start with a valid prefix: ./, ../, or @")
|
||||
);
|
||||
|
||||
// Pass non-string to require
|
||||
let res = run_require(&lua, true);
|
||||
assert!(res.is_err());
|
||||
assert!((res.unwrap_err().to_string())
|
||||
.contains("bad argument #1 to 'require' (string expected, got boolean)"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_require_without_config() {
|
||||
let lua = Lua::new();
|
||||
|
||||
// RequireSimpleRelativePath
|
||||
let res = run_require(&lua, "./require/without_config/dependency").unwrap();
|
||||
assert_eq!("result from dependency", get_str(&res, 1));
|
||||
|
||||
// RequireRelativeToRequiringFile
|
||||
let res = run_require(&lua, "./require/without_config/module").unwrap();
|
||||
assert_eq!("result from dependency", get_str(&res, 1));
|
||||
assert_eq!("required into module", get_str(&res, 2));
|
||||
|
||||
// RequireLua
|
||||
let res = run_require(&lua, "./require/without_config/lua_dependency").unwrap();
|
||||
assert_eq!("result from lua_dependency", get_str(&res, 1));
|
||||
|
||||
// RequireInitLuau
|
||||
let res = run_require(&lua, "./require/without_config/luau").unwrap();
|
||||
assert_eq!("result from init.luau", get_str(&res, 1));
|
||||
|
||||
// RequireInitLua
|
||||
let res = run_require(&lua, "./require/without_config/lua").unwrap();
|
||||
assert_eq!("result from init.lua", get_str(&res, 1));
|
||||
|
||||
// RequireSubmoduleUsingSelf
|
||||
let res = run_require(&lua, "./require/without_config/nested_module_requirer").unwrap();
|
||||
assert_eq!("result from submodule", get_str(&res, 1));
|
||||
|
||||
// RequireWithFileAmbiguity
|
||||
let res = run_require(&lua, "./require/without_config/ambiguous_file_requirer");
|
||||
assert!(res.is_err());
|
||||
assert!((res.unwrap_err().to_string())
|
||||
.contains("could not resolve child component \"dependency\" (ambiguous)"));
|
||||
|
||||
// RequireWithDirectoryAmbiguity
|
||||
let res = run_require(&lua, "./require/without_config/ambiguous_directory_requirer");
|
||||
assert!(res.is_err());
|
||||
assert!((res.unwrap_err().to_string())
|
||||
.contains("could not resolve child component \"dependency\" (ambiguous)"));
|
||||
|
||||
// CheckCachedResult
|
||||
let res = run_require(&lua, "./require/without_config/validate_cache").unwrap();
|
||||
assert!(res.is_table());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_require_with_config() {
|
||||
let lua = Lua::new();
|
||||
|
||||
// RequirePathWithAlias
|
||||
let res = run_require(&lua, "./require/with_config/src/alias_requirer").unwrap();
|
||||
assert_eq!("result from dependency", get_str(&res, 1));
|
||||
|
||||
// RequirePathWithParentAlias
|
||||
let res = run_require(&lua, "./require/with_config/src/parent_alias_requirer").unwrap();
|
||||
assert_eq!("result from other_dependency", get_str(&res, 1));
|
||||
|
||||
// RequirePathWithAliasPointingToDirectory
|
||||
let res = run_require(&lua, "./require/with_config/src/directory_alias_requirer").unwrap();
|
||||
assert_eq!("result from subdirectory_dependency", get_str(&res, 1));
|
||||
|
||||
// RequireAliasThatDoesNotExist
|
||||
let res = run_require(&lua, "@this.alias.does.not.exist");
|
||||
assert!(res.is_err());
|
||||
assert!((res.unwrap_err().to_string()).contains("@this.alias.does.not.exist is not a valid alias"));
|
||||
|
||||
// IllegalAlias
|
||||
let res = run_require(&lua, "@");
|
||||
assert!(res.is_err());
|
||||
assert!((res.unwrap_err().to_string()).contains("@ is not a valid alias"));
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[tokio::test]
|
||||
async fn test_async_require() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let temp_path = temp_dir.path().join("async_chunk.luau");
|
||||
std::fs::write(
|
||||
&temp_path,
|
||||
r#"
|
||||
sleep_ms(10)
|
||||
return "result_after_async_sleep"
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
lua.globals().set(
|
||||
"sleep_ms",
|
||||
lua.create_async_function(|_, ms: u64| async move {
|
||||
tokio::time::sleep(std::time::Duration::from_millis(ms)).await;
|
||||
Ok(())
|
||||
})?,
|
||||
)?;
|
||||
|
||||
lua.load(
|
||||
r#"
|
||||
local result = require("./async_chunk")
|
||||
assert(result == "result_after_async_sleep")
|
||||
"#,
|
||||
)
|
||||
.set_name(format!("@{}", temp_dir.path().join("require.rs").display()))
|
||||
.exec_async()
|
||||
.await
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"aliases": {
|
||||
"dep": "./this_should_be_overwritten_by_child_luaurc",
|
||||
"otherdep": "./src/other_dependency"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"aliases": {
|
||||
"dep": "./dependency",
|
||||
"subdir": "./subdirectory"
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
return require("@dep")
|
||||
@@ -1 +0,0 @@
|
||||
return {"result from dependency"}
|
||||
@@ -1 +0,0 @@
|
||||
return(require("@subdir/subdirectory_dependency"))
|
||||
@@ -1 +0,0 @@
|
||||
return {"result from other_dependency"}
|
||||
@@ -1 +0,0 @@
|
||||
return require("@otherdep")
|
||||
@@ -1 +0,0 @@
|
||||
return {"result from subdirectory_dependency"}
|
||||
@@ -1 +0,0 @@
|
||||
return {"result from dependency"}
|
||||
@@ -1 +0,0 @@
|
||||
return {"result from dependency"}
|
||||
@@ -1 +0,0 @@
|
||||
return {"result from dependency"}
|
||||
@@ -1 +0,0 @@
|
||||
return {"result from dependency"}
|
||||
@@ -1,3 +0,0 @@
|
||||
local result = require("./ambiguous/directory/dependency")
|
||||
result[#result+1] = "required into module"
|
||||
return result
|
||||
@@ -1,3 +0,0 @@
|
||||
local result = require("./ambiguous/file/dependency")
|
||||
result[#result+1] = "required into module"
|
||||
return result
|
||||
@@ -1 +0,0 @@
|
||||
return {"result from dependency"}
|
||||
@@ -1 +0,0 @@
|
||||
return {"result from init.lua"}
|
||||
@@ -1 +0,0 @@
|
||||
return {"result from lua_dependency"}
|
||||
@@ -1 +0,0 @@
|
||||
return {"result from init.luau"}
|
||||
@@ -1,3 +0,0 @@
|
||||
local result = require("./dependency")
|
||||
result[#result+1] = "required into module"
|
||||
return result
|
||||
@@ -1,2 +0,0 @@
|
||||
local result = require("@self/submodule")
|
||||
return result
|
||||
@@ -1 +0,0 @@
|
||||
return {"result from submodule"}
|
||||
@@ -1,3 +0,0 @@
|
||||
local result = require("./nested")
|
||||
result[#result+1] = "required into module"
|
||||
return result
|
||||
@@ -1,4 +0,0 @@
|
||||
local result1 = require("./dependency")
|
||||
local result2 = require("./dependency")
|
||||
assert(result1 == result2, "expect the same result when requiring the same module twice")
|
||||
return {}
|
||||
@@ -18,6 +18,7 @@ lua53 = ["mlua/lua53"]
|
||||
lua52 = ["mlua/lua52"]
|
||||
lua51 = ["mlua/lua51"]
|
||||
luajit = ["mlua/luajit"]
|
||||
luau = ["mlua/luau"]
|
||||
|
||||
[dependencies]
|
||||
mlua = { path = "../..", features = ["module"] }
|
||||
|
||||
@@ -10,6 +10,7 @@ lua53 = ["mlua/lua53"]
|
||||
lua52 = ["mlua/lua52"]
|
||||
lua51 = ["mlua/lua51"]
|
||||
luajit = ["mlua/luajit"]
|
||||
luau = ["mlua/luau"]
|
||||
vendored = ["mlua/vendored"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
+30
-116
@@ -3,12 +3,13 @@ use std::collections::HashMap;
|
||||
use std::iter::FromIterator;
|
||||
use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||
use std::string::String as StdString;
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::{error, f32, f64, fmt};
|
||||
|
||||
use mlua::{
|
||||
ffi, ChunkMode, Error, ExternalError, Function, Lua, LuaOptions, Nil, Result, StdLib, String, Table,
|
||||
UserData, Value, Variadic,
|
||||
ChunkMode, Error, ExternalError, Function, Lua, LuaOptions, Nil, Result, StdLib, String, Table, UserData,
|
||||
Value, Variadic,
|
||||
};
|
||||
|
||||
#[test]
|
||||
@@ -500,29 +501,6 @@ fn test_panic() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
#[test]
|
||||
fn test_safe_integers() -> Result<()> {
|
||||
const MAX_SAFE_INTEGER: i64 = 2i64.pow(53) - 1;
|
||||
const MIN_SAFE_INTEGER: i64 = -2i64.pow(53) + 1;
|
||||
|
||||
let lua = Lua::new();
|
||||
let f = lua.load("return ...").into_function()?;
|
||||
|
||||
assert_eq!(f.call::<i64>(MAX_SAFE_INTEGER)?, MAX_SAFE_INTEGER);
|
||||
assert_eq!(f.call::<i64>(MIN_SAFE_INTEGER)?, MIN_SAFE_INTEGER);
|
||||
|
||||
// For Lua versions that does not support 64-bit integers, the values will be converted to f64
|
||||
#[cfg(any(feature = "luau", feature = "lua51", feature = "luajit"))]
|
||||
{
|
||||
assert_ne!(f.call::<i64>(MAX_SAFE_INTEGER + 2)?, MAX_SAFE_INTEGER + 2);
|
||||
assert_ne!(f.call::<i64>(MIN_SAFE_INTEGER - 2)?, MIN_SAFE_INTEGER - 2);
|
||||
assert_eq!(f.call::<f64>(i64::MAX)?, i64::MAX as f64);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_num_conversion() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
@@ -944,11 +922,9 @@ fn test_rust_function() -> Result<()> {
|
||||
fn test_c_function() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
extern "C-unwind" fn c_function(state: *mut mlua::lua_State) -> std::os::raw::c_int {
|
||||
unsafe {
|
||||
ffi::lua_pushboolean(state, 1);
|
||||
ffi::lua_setglobal(state, b"c_function\0" as *const _ as *const _);
|
||||
}
|
||||
unsafe extern "C-unwind" fn c_function(state: *mut mlua::lua_State) -> std::os::raw::c_int {
|
||||
ffi::lua_pushboolean(state, 1);
|
||||
ffi::lua_setglobal(state, b"c_function\0" as *const _ as *const _);
|
||||
0
|
||||
}
|
||||
|
||||
@@ -1169,79 +1145,36 @@ fn test_jit_version() -> Result<()> {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_register_module() -> Result<()> {
|
||||
fn test_load_from_function() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let t = lua.create_table()?;
|
||||
t.set("name", "my_module")?;
|
||||
lua.register_module("@my_module", &t)?;
|
||||
|
||||
lua.load(
|
||||
r#"
|
||||
local my_module = require("@my_module")
|
||||
assert(my_module.name == "my_module")
|
||||
"#,
|
||||
)
|
||||
.exec()?;
|
||||
|
||||
lua.unload_module("@my_module")?;
|
||||
lua.load(
|
||||
r#"
|
||||
local ok, err = pcall(function() return require("@my_module") end)
|
||||
assert(not ok)
|
||||
"#,
|
||||
)
|
||||
.exec()?;
|
||||
|
||||
#[cfg(feature = "luau")]
|
||||
{
|
||||
// Luau registered modules must have '@' prefix
|
||||
let res = lua.register_module("my_module", 123);
|
||||
assert!(res.is_err());
|
||||
assert_eq!(
|
||||
res.unwrap_err().to_string(),
|
||||
"runtime error: module name must begin with '@'"
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(feature = "luau"))]
|
||||
fn test_preload_module() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let loader = lua.create_function(move |lua, modname: String| {
|
||||
let i = Arc::new(AtomicU32::new(0));
|
||||
let i2 = i.clone();
|
||||
let func = lua.create_function(move |lua, modname: String| {
|
||||
i2.fetch_add(1, Ordering::Relaxed);
|
||||
let t = lua.create_table()?;
|
||||
t.set("name", modname)?;
|
||||
t.set("__name", modname)?;
|
||||
Ok(t)
|
||||
})?;
|
||||
|
||||
lua.preload_module("@my_module", loader.clone())?;
|
||||
lua.load(
|
||||
r#"
|
||||
-- `my_module` is global for purposes of next test
|
||||
my_module = require("@my_module")
|
||||
assert(my_module.name == "@my_module")
|
||||
local my_module2 = require("@my_module")
|
||||
assert(my_module == my_module2)
|
||||
"#,
|
||||
)
|
||||
.exec()
|
||||
.unwrap();
|
||||
let t: Table = lua.load_from_function("my_module", func.clone())?;
|
||||
assert_eq!(t.get::<String>("__name")?, "my_module");
|
||||
assert_eq!(i.load(Ordering::Relaxed), 1);
|
||||
|
||||
let _: Value = lua.load_from_function("my_module", func.clone())?;
|
||||
assert_eq!(i.load(Ordering::Relaxed), 1);
|
||||
|
||||
let func_nil = lua.create_function(move |_, _: String| Ok(Value::Nil))?;
|
||||
let v: Value = lua.load_from_function("my_module2", func_nil)?;
|
||||
assert_eq!(v, Value::Boolean(true));
|
||||
|
||||
// Test unloading and loading again
|
||||
lua.unload_module("@my_module")?;
|
||||
lua.load(
|
||||
r#"
|
||||
local my_module3 = require("@my_module")
|
||||
-- `my_module` is not equal to `my_module3` because it was reloaded
|
||||
assert(my_module ~= my_module3)
|
||||
"#,
|
||||
)
|
||||
.exec()
|
||||
.unwrap();
|
||||
lua.unload("my_module")?;
|
||||
let _: Value = lua.load_from_function("my_module", func)?;
|
||||
assert_eq!(i.load(Ordering::Relaxed), 2);
|
||||
|
||||
// Unloading nonexistent module must not fail
|
||||
lua.unload("my_module2")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1370,7 +1303,8 @@ fn test_warnings() -> Result<()> {
|
||||
lua.set_warning_function(|_, _, _| Err(Error::runtime("warning error")));
|
||||
assert!(matches!(
|
||||
lua.load(r#"warn("test")"#).exec(),
|
||||
Err(Error::RuntimeError(ref err)) if err == "warning error"
|
||||
Err(Error::CallbackError { cause, .. })
|
||||
if matches!(*cause, Error::RuntimeError(ref err) if err == "warning error")
|
||||
));
|
||||
|
||||
// Recursive warning
|
||||
@@ -1486,23 +1420,3 @@ fn test_gc_drop_ref_thread() -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
#[test]
|
||||
fn test_get_or_init_from_ptr() -> Result<()> {
|
||||
// This would not work with Luau, the state must be init by mlua internally
|
||||
let state = unsafe { ffi::luaL_newstate() };
|
||||
|
||||
let mut lua = unsafe { Lua::get_or_init_from_ptr(state) };
|
||||
lua.globals().set("hello", "world678")?;
|
||||
|
||||
// The same Lua instance must be returned
|
||||
lua = unsafe { Lua::get_or_init_from_ptr(state) };
|
||||
assert_eq!(lua.globals().get::<String>("hello")?, "world678");
|
||||
|
||||
unsafe { ffi::lua_close(state) };
|
||||
|
||||
// Lua must not be accessed after closing
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+1
-26
@@ -164,7 +164,7 @@ fn test_thread_reset() -> Result<()> {
|
||||
let result = thread.resume::<()>(());
|
||||
assert!(
|
||||
matches!(result, Err(Error::CallbackError{ ref cause, ..})
|
||||
if matches!(cause.as_ref(), Error::RuntimeError(err)
|
||||
if matches!(cause.as_ref(), Error::RuntimeError(ref err)
|
||||
if err == "cannot reset a running thread")
|
||||
),
|
||||
"unexpected result: {result:?}",
|
||||
@@ -227,28 +227,3 @@ fn test_thread_pointer() -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "luau")]
|
||||
fn test_thread_resume_error() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let thread = lua
|
||||
.load(
|
||||
r#"
|
||||
coroutine.create(function()
|
||||
local ok, err = pcall(coroutine.yield, 123)
|
||||
assert(not ok, "yield should fail")
|
||||
assert(err == "myerror", "unexpected error: " .. tostring(err))
|
||||
return "success"
|
||||
end)
|
||||
"#,
|
||||
)
|
||||
.eval::<Thread>()?;
|
||||
|
||||
assert_eq!(thread.resume::<i64>(())?, 123);
|
||||
let status = thread.resume_error::<String>("myerror").unwrap();
|
||||
assert_eq!(status, "success");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
[default]
|
||||
extend-ignore-identifiers-re = ["catched", "2nd", "ser"]
|
||||
|
||||
[default.extend-words]
|
||||
thr = "thr"
|
||||
aas = "aas"
|
||||
Reference in New Issue
Block a user