mirror of
https://github.com/mlua-rs/mlua
synced 2026-06-08 16:05:43 +00:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 58953e5635 | |||
| 6406de405d | |||
| 727096dd3b | |||
| 2445230759 | |||
| 1cd2bdc808 | |||
| f8ed33a2aa | |||
| 25955893e0 | |||
| 3f0c69b70b | |||
| 9da98d42c7 | |||
| f539f60987 | |||
| aa187e6663 | |||
| ec10bf2a39 | |||
| 3ea80b763d | |||
| 2e0e86dab2 | |||
| 0ac7aebb27 | |||
| 634e5d4550 | |||
| 05d6c20520 | |||
| 63e7cfd31b |
@@ -1,3 +1,10 @@
|
||||
## v0.11.0-beta.3 (Jun 23, 2025)
|
||||
|
||||
- Luau in sandboxed mode has reduced options in `collectgarbage` function (to follow the official doc)
|
||||
- `Function::deep_clone` now returns `Result<Function>` as this operation can trigger memory errors
|
||||
- Luau "Require" resolves included Lua files relative to the current directory (#605)
|
||||
- Fixed bug when finalizing `AsyncThread` on drop (`call_async` methods family)
|
||||
|
||||
## v0.11.0-beta.2 (Jun 12, 2025)
|
||||
|
||||
- Lua 5.4 updated to 5.4.8
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mlua"
|
||||
version = "0.11.0-beta.2" # remember to update mlua_derive
|
||||
version = "0.11.0-beta.3" # remember to update mlua_derive
|
||||
authors = ["Aleksandr Orlenko <zxteam@pm.me>", "kyren <catherine@kyju.org>"]
|
||||
rust-version = "1.79.0"
|
||||
edition = "2021"
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mlua-sys"
|
||||
version = "0.8.0"
|
||||
version = "0.8.1"
|
||||
authors = ["Aleksandr Orlenko <zxteam@pm.me>"]
|
||||
rust-version = "1.71"
|
||||
edition = "2021"
|
||||
|
||||
@@ -388,7 +388,7 @@ pub unsafe fn luaL_loadbufferenv(
|
||||
}
|
||||
}
|
||||
|
||||
if chunk_is_text {
|
||||
let status = if chunk_is_text {
|
||||
if env < 0 {
|
||||
env -= 1;
|
||||
}
|
||||
@@ -397,14 +397,21 @@ pub unsafe fn luaL_loadbufferenv(
|
||||
ptr::write(data_ud, data);
|
||||
// By deferring the `free(data)` to the userdata destructor, we ensure that
|
||||
// even if `luau_load` throws an error, the `data` is still released.
|
||||
let ok = luau_load(L, name, data, size, env) == 0;
|
||||
let status = luau_load(L, name, data, size, env);
|
||||
lua_replace(L, -2); // replace data with the result
|
||||
if !ok {
|
||||
return LUA_ERRSYNTAX;
|
||||
status
|
||||
} else {
|
||||
luau_load(L, name, data, size, env)
|
||||
};
|
||||
|
||||
if status != 0 {
|
||||
if lua_isstring(L, -1) != 0 && CStr::from_ptr(lua_tostring(L, -1)) == c"not enough memory" {
|
||||
// A case for Luau >= 0.679
|
||||
return LUA_ERRMEM;
|
||||
}
|
||||
} else if luau_load(L, name, data, size, env) != 0 {
|
||||
return LUA_ERRSYNTAX;
|
||||
}
|
||||
|
||||
LUA_OK
|
||||
}
|
||||
|
||||
|
||||
+14
-6
@@ -492,16 +492,24 @@ impl Function {
|
||||
/// This function returns shallow clone (same handle) for Rust/C functions.
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
pub fn deep_clone(&self) -> Self {
|
||||
pub fn deep_clone(&self) -> Result<Self> {
|
||||
let lua = self.0.lua.lock();
|
||||
let ref_thread = lua.ref_thread();
|
||||
let state = lua.state();
|
||||
unsafe {
|
||||
if ffi::lua_iscfunction(ref_thread, self.0.index) != 0 {
|
||||
return self.clone();
|
||||
let _sg = StackGuard::new(state);
|
||||
check_stack(state, 2)?;
|
||||
|
||||
lua.push_ref(&self.0);
|
||||
if ffi::lua_iscfunction(state, -1) != 0 {
|
||||
return Ok(self.clone());
|
||||
}
|
||||
|
||||
ffi::lua_clonefunction(ref_thread, self.0.index);
|
||||
Function(lua.pop_ref_thread())
|
||||
if lua.unlikely_memory_error() {
|
||||
ffi::lua_clonefunction(state, -1);
|
||||
} else {
|
||||
protect_lua!(state, 1, 1, fn(state) ffi::lua_clonefunction(state, -1))?;
|
||||
}
|
||||
Ok(Function(lua.pop_ref()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -86,7 +86,7 @@ impl<'a> Debug<'a> {
|
||||
}
|
||||
|
||||
/// Corresponds to the `n` what mask.
|
||||
pub fn names(&self) -> DebugNames {
|
||||
pub fn names(&self) -> DebugNames<'_> {
|
||||
unsafe {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
mlua_assert!(
|
||||
@@ -113,7 +113,7 @@ impl<'a> Debug<'a> {
|
||||
}
|
||||
|
||||
/// Corresponds to the `S` what mask.
|
||||
pub fn source(&self) -> DebugSource {
|
||||
pub fn source(&self) -> DebugSource<'_> {
|
||||
unsafe {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
mlua_assert!(
|
||||
|
||||
+7
-6
@@ -5,7 +5,7 @@ use std::ptr;
|
||||
use crate::chunk::ChunkMode;
|
||||
use crate::error::Result;
|
||||
use crate::function::Function;
|
||||
use crate::state::{callback_error_ext, Lua};
|
||||
use crate::state::{callback_error_ext, ExtraData, Lua};
|
||||
use crate::traits::{FromLuaMulti, IntoLua};
|
||||
|
||||
pub use require::{NavigateError, Require, TextRequirer};
|
||||
@@ -45,16 +45,17 @@ unsafe extern "C-unwind" fn lua_collectgarbage(state: *mut ffi::lua_State) -> c_
|
||||
let option = ffi::luaL_optstring(state, 1, cstr!("collect"));
|
||||
let option = CStr::from_ptr(option);
|
||||
let arg = ffi::luaL_optinteger(state, 2, 0);
|
||||
let is_sandboxed = (*ExtraData::get(state)).sandboxed;
|
||||
match option.to_str() {
|
||||
Ok("collect") => {
|
||||
Ok("collect") if !is_sandboxed => {
|
||||
ffi::lua_gc(state, ffi::LUA_GCCOLLECT, 0);
|
||||
0
|
||||
}
|
||||
Ok("stop") => {
|
||||
Ok("stop") if !is_sandboxed => {
|
||||
ffi::lua_gc(state, ffi::LUA_GCSTOP, 0);
|
||||
0
|
||||
}
|
||||
Ok("restart") => {
|
||||
Ok("restart") if !is_sandboxed => {
|
||||
ffi::lua_gc(state, ffi::LUA_GCRESTART, 0);
|
||||
0
|
||||
}
|
||||
@@ -64,12 +65,12 @@ unsafe extern "C-unwind" fn lua_collectgarbage(state: *mut ffi::lua_State) -> c_
|
||||
ffi::lua_pushnumber(state, kbytes + kbytes_rem / 1024.0);
|
||||
1
|
||||
}
|
||||
Ok("step") => {
|
||||
Ok("step") if !is_sandboxed => {
|
||||
let res = ffi::lua_gc(state, ffi::LUA_GCSTEP, arg as _);
|
||||
ffi::lua_pushboolean(state, res);
|
||||
1
|
||||
}
|
||||
Ok("isrunning") => {
|
||||
Ok("isrunning") if !is_sandboxed => {
|
||||
let res = ffi::lua_gc(state, ffi::LUA_GCISRUNNING, 0);
|
||||
ffi::lua_pushboolean(state, res);
|
||||
1
|
||||
|
||||
+4
-2
@@ -200,9 +200,11 @@ impl Require for TextRequirer {
|
||||
let chunk_path = Self::normalize_path(chunk_name.as_ref());
|
||||
|
||||
if chunk_path.extension() == Some("rs".as_ref()) {
|
||||
// Special case for Rust source files, reset to the current directory
|
||||
let chunk_filename = chunk_path.file_name().unwrap();
|
||||
let cwd = env::current_dir().map_err(|_| NavigateError::NotFound)?;
|
||||
self.abs_path = Self::normalize_path(&cwd.join(&chunk_path));
|
||||
self.rel_path = chunk_path;
|
||||
self.abs_path = Self::normalize_path(&cwd.join(chunk_filename));
|
||||
self.rel_path = ([Component::CurDir, Component::Normal(chunk_filename)].into_iter()).collect();
|
||||
self.module_path = PathBuf::new();
|
||||
|
||||
return Ok(());
|
||||
|
||||
+7
-6
@@ -486,6 +486,7 @@ impl Lua {
|
||||
/// - Set globals to read-only (and activates safeenv)
|
||||
/// - Setup local environment table that performs writes locally and proxies reads to the global
|
||||
/// environment.
|
||||
/// - Allow only `count` mode in `collectgarbage` function.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -876,7 +877,7 @@ impl Lua {
|
||||
/// not count in the stack).
|
||||
///
|
||||
/// [`Debug`]: crate::hook::Debug
|
||||
pub fn inspect_stack(&self, level: usize) -> Option<Debug> {
|
||||
pub fn inspect_stack(&self, level: usize) -> Option<Debug<'_>> {
|
||||
let lua = self.lock();
|
||||
unsafe {
|
||||
let mut ar: ffi::lua_Debug = mem::zeroed();
|
||||
@@ -1955,7 +1956,7 @@ impl Lua {
|
||||
/// Panics if the data object of type `T` is currently mutably borrowed. Multiple immutable
|
||||
/// reads can be taken out at the same time.
|
||||
#[track_caller]
|
||||
pub fn app_data_ref<T: 'static>(&self) -> Option<AppDataRef<T>> {
|
||||
pub fn app_data_ref<T: 'static>(&self) -> Option<AppDataRef<'_, T>> {
|
||||
let guard = self.lock_arc();
|
||||
let extra = unsafe { &*guard.extra.get() };
|
||||
extra.app_data.borrow(Some(guard))
|
||||
@@ -1963,7 +1964,7 @@ impl Lua {
|
||||
|
||||
/// Tries to get a reference to an application data object stored by [`Lua::set_app_data`] of
|
||||
/// type `T`.
|
||||
pub fn try_app_data_ref<T: 'static>(&self) -> StdResult<Option<AppDataRef<T>>, BorrowError> {
|
||||
pub fn try_app_data_ref<T: 'static>(&self) -> StdResult<Option<AppDataRef<'_, T>>, BorrowError> {
|
||||
let guard = self.lock_arc();
|
||||
let extra = unsafe { &*guard.extra.get() };
|
||||
extra.app_data.try_borrow(Some(guard))
|
||||
@@ -1976,7 +1977,7 @@ impl Lua {
|
||||
///
|
||||
/// Panics if the data object of type `T` is currently borrowed.
|
||||
#[track_caller]
|
||||
pub fn app_data_mut<T: 'static>(&self) -> Option<AppDataRefMut<T>> {
|
||||
pub fn app_data_mut<T: 'static>(&self) -> Option<AppDataRefMut<'_, T>> {
|
||||
let guard = self.lock_arc();
|
||||
let extra = unsafe { &*guard.extra.get() };
|
||||
extra.app_data.borrow_mut(Some(guard))
|
||||
@@ -1984,7 +1985,7 @@ impl Lua {
|
||||
|
||||
/// Tries to get a mutable reference to an application data object stored by
|
||||
/// [`Lua::set_app_data`] of type `T`.
|
||||
pub fn try_app_data_mut<T: 'static>(&self) -> StdResult<Option<AppDataRefMut<T>>, BorrowMutError> {
|
||||
pub fn try_app_data_mut<T: 'static>(&self) -> StdResult<Option<AppDataRefMut<'_, T>>, BorrowMutError> {
|
||||
let guard = self.lock_arc();
|
||||
let extra = unsafe { &*guard.extra.get() };
|
||||
extra.app_data.try_borrow_mut(Some(guard))
|
||||
@@ -2058,7 +2059,7 @@ impl Lua {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn lock(&self) -> ReentrantMutexGuard<RawLua> {
|
||||
pub(crate) fn lock(&self) -> ReentrantMutexGuard<'_, RawLua> {
|
||||
let rawlua = self.raw.lock();
|
||||
#[cfg(feature = "luau")]
|
||||
if unsafe { (*rawlua.extra.get()).running_gc } {
|
||||
|
||||
+31
-3
@@ -28,7 +28,7 @@ use super::{Lua, WeakLua};
|
||||
static EXTRA_REGISTRY_KEY: u8 = 0;
|
||||
|
||||
const WRAPPED_FAILURE_POOL_DEFAULT_CAPACITY: usize = 64;
|
||||
const REF_STACK_RESERVE: c_int = 2;
|
||||
const REF_STACK_RESERVE: c_int = 3;
|
||||
|
||||
/// Data associated with the Lua state.
|
||||
pub(crate) struct ExtraData {
|
||||
@@ -89,7 +89,7 @@ pub(crate) struct ExtraData {
|
||||
#[cfg(feature = "luau")]
|
||||
pub(crate) running_gc: bool,
|
||||
#[cfg(feature = "luau")]
|
||||
pub(super) sandboxed: bool,
|
||||
pub(crate) sandboxed: bool,
|
||||
#[cfg(feature = "luau")]
|
||||
pub(super) compiler: Option<Compiler>,
|
||||
#[cfg(feature = "luau-jit")]
|
||||
@@ -212,7 +212,7 @@ impl ExtraData {
|
||||
self.weak.write(WeakLua(XRc::downgrade(raw)));
|
||||
}
|
||||
|
||||
pub(super) unsafe fn get(state: *mut ffi::lua_State) -> *mut Self {
|
||||
pub(crate) unsafe fn get(state: *mut ffi::lua_State) -> *mut Self {
|
||||
#[cfg(feature = "luau")]
|
||||
if cfg!(not(feature = "module")) {
|
||||
// In the main app we can use `lua_callbacks` to access ExtraData
|
||||
@@ -259,4 +259,32 @@ impl ExtraData {
|
||||
pub(super) unsafe fn weak(&self) -> &WeakLua {
|
||||
self.weak.assume_init_ref()
|
||||
}
|
||||
|
||||
/// Pops a reference from top of the auxiliary stack and move it to a first free slot.
|
||||
pub(super) unsafe fn ref_stack_pop(&mut self) -> c_int {
|
||||
if let Some(free) = self.ref_free.pop() {
|
||||
ffi::lua_replace(self.ref_thread, free);
|
||||
return free;
|
||||
}
|
||||
|
||||
// Try to grow max stack size
|
||||
if self.ref_stack_top >= self.ref_stack_size {
|
||||
let mut inc = self.ref_stack_size; // Try to double stack size
|
||||
while inc > 0 && ffi::lua_checkstack(self.ref_thread, inc) == 0 {
|
||||
inc /= 2;
|
||||
}
|
||||
if inc == 0 {
|
||||
// Pop item on top of the stack to avoid stack leaking and successfully run destructors
|
||||
// during unwinding.
|
||||
ffi::lua_pop(self.ref_thread, 1);
|
||||
let top = self.ref_stack_top;
|
||||
// It is a user error to create too many references to exhaust the Lua max stack size
|
||||
// for the ref thread.
|
||||
panic!("cannot create a Lua reference, out of auxiliary stack space (used {top} slots)");
|
||||
}
|
||||
self.ref_stack_size += inc;
|
||||
}
|
||||
self.ref_stack_top += 1;
|
||||
self.ref_stack_top
|
||||
}
|
||||
}
|
||||
|
||||
+13
-9
@@ -11,7 +11,7 @@ use crate::chunk::ChunkMode;
|
||||
use crate::error::{Error, Result};
|
||||
use crate::function::Function;
|
||||
use crate::memory::{MemoryState, ALLOCATOR};
|
||||
use crate::state::util::{callback_error_ext, ref_stack_pop};
|
||||
use crate::state::util::callback_error_ext;
|
||||
use crate::stdlib::StdLib;
|
||||
use crate::string::String;
|
||||
use crate::table::Table;
|
||||
@@ -316,7 +316,7 @@ impl RawLua {
|
||||
/// Private version of [`Lua::app_data_ref`]
|
||||
#[track_caller]
|
||||
#[inline]
|
||||
pub(crate) fn priv_app_data_ref<T: 'static>(&self) -> Option<AppDataRef<T>> {
|
||||
pub(crate) fn priv_app_data_ref<T: 'static>(&self) -> Option<AppDataRef<'_, T>> {
|
||||
let extra = unsafe { &*self.extra.get() };
|
||||
extra.app_data_priv.borrow(None)
|
||||
}
|
||||
@@ -324,7 +324,7 @@ impl RawLua {
|
||||
/// Private version of [`Lua::app_data_mut`]
|
||||
#[track_caller]
|
||||
#[inline]
|
||||
pub(crate) fn priv_app_data_mut<T: 'static>(&self) -> Option<AppDataRefMut<T>> {
|
||||
pub(crate) fn priv_app_data_mut<T: 'static>(&self) -> Option<AppDataRefMut<'_, T>> {
|
||||
let extra = unsafe { &*self.extra.get() };
|
||||
extra.app_data_priv.borrow_mut(None)
|
||||
}
|
||||
@@ -694,7 +694,7 @@ impl RawLua {
|
||||
|
||||
/// Pops a value from the Lua stack.
|
||||
///
|
||||
/// Uses 2 stack spaces, does not call `checkstack`.
|
||||
/// Uses up to 1 stack spaces, does not call `checkstack`.
|
||||
pub(crate) unsafe fn pop_value(&self) -> Value {
|
||||
let value = self.stack_value(-1, None);
|
||||
ffi::lua_pop(self.state(), 1);
|
||||
@@ -703,7 +703,7 @@ impl RawLua {
|
||||
|
||||
/// Returns value at given stack index without popping it.
|
||||
///
|
||||
/// Uses 2 stack spaces, does not call checkstack.
|
||||
/// Uses up to 1 stack spaces, does not call `checkstack`.
|
||||
pub(crate) unsafe fn stack_value(&self, idx: c_int, type_hint: Option<c_int>) -> Value {
|
||||
let state = self.state();
|
||||
match type_hint.unwrap_or_else(|| ffi::lua_type(state, idx)) {
|
||||
@@ -816,21 +816,21 @@ impl RawLua {
|
||||
#[inline]
|
||||
pub(crate) unsafe fn pop_ref(&self) -> ValueRef {
|
||||
ffi::lua_xmove(self.state(), self.ref_thread(), 1);
|
||||
let index = ref_stack_pop(self.extra.get());
|
||||
let index = (*self.extra.get()).ref_stack_pop();
|
||||
ValueRef::new(self, index)
|
||||
}
|
||||
|
||||
// Same as `pop_ref` but assumes the value is already on the reference thread
|
||||
#[inline]
|
||||
pub(crate) unsafe fn pop_ref_thread(&self) -> ValueRef {
|
||||
let index = ref_stack_pop(self.extra.get());
|
||||
let index = (*self.extra.get()).ref_stack_pop();
|
||||
ValueRef::new(self, index)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) unsafe fn clone_ref(&self, vref: &ValueRef) -> ValueRef {
|
||||
ffi::lua_pushvalue(self.ref_thread(), vref.index);
|
||||
let index = ref_stack_pop(self.extra.get());
|
||||
let index = (*self.extra.get()).ref_stack_pop();
|
||||
ValueRef::new(self, index)
|
||||
}
|
||||
|
||||
@@ -1262,7 +1262,7 @@ impl RawLua {
|
||||
if nargs == 1 && ffi::lua_tolightuserdata(state, -1) == Lua::poll_terminate().0 {
|
||||
// Destroy the future and terminate the Lua thread
|
||||
(*upvalue).data.take();
|
||||
ffi::lua_pushinteger(state, 0);
|
||||
ffi::lua_pushinteger(state, -1);
|
||||
return Ok(1);
|
||||
}
|
||||
|
||||
@@ -1347,6 +1347,10 @@ impl RawLua {
|
||||
return res
|
||||
elseif nres == 2 then
|
||||
return res, res2
|
||||
elseif nres < 0 then
|
||||
-- Negative `nres` means that the future is terminated
|
||||
-- It must stay yielded and never be resumed again
|
||||
yield()
|
||||
else
|
||||
return unpack(res, nres)
|
||||
end
|
||||
|
||||
+1
-29
@@ -89,7 +89,7 @@ where
|
||||
PreallocatedFailure::New(_) => {
|
||||
ffi::lua_rotate(state, 1, -1);
|
||||
ffi::lua_xmove(state, ref_thread, 1);
|
||||
let index = ref_stack_pop(extra);
|
||||
let index = (*extra).ref_stack_pop();
|
||||
(*extra).wrapped_failure_pool.push(index);
|
||||
(*extra).wrapped_failure_top += 1;
|
||||
}
|
||||
@@ -150,31 +150,3 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) unsafe fn ref_stack_pop(extra: *mut ExtraData) -> c_int {
|
||||
let extra = &mut *extra;
|
||||
if let Some(free) = extra.ref_free.pop() {
|
||||
ffi::lua_replace(extra.ref_thread, free);
|
||||
return free;
|
||||
}
|
||||
|
||||
// Try to grow max stack size
|
||||
if extra.ref_stack_top >= extra.ref_stack_size {
|
||||
let mut inc = extra.ref_stack_size; // Try to double stack size
|
||||
while inc > 0 && ffi::lua_checkstack(extra.ref_thread, inc) == 0 {
|
||||
inc /= 2;
|
||||
}
|
||||
if inc == 0 {
|
||||
// Pop item on top of the stack to avoid stack leaking and successfully run destructors
|
||||
// during unwinding.
|
||||
ffi::lua_pop(extra.ref_thread, 1);
|
||||
let top = extra.ref_stack_top;
|
||||
// It is a user error to create enough references to exhaust the Lua max stack size for
|
||||
// the ref thread.
|
||||
panic!("cannot create a Lua reference, out of auxiliary stack space (used {top} slots)");
|
||||
}
|
||||
extra.ref_stack_size += inc;
|
||||
}
|
||||
extra.ref_stack_top += 1;
|
||||
extra.ref_stack_top
|
||||
}
|
||||
|
||||
+3
-3
@@ -43,7 +43,7 @@ impl String {
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn to_str(&self) -> Result<BorrowedStr> {
|
||||
pub fn to_str(&self) -> Result<BorrowedStr<'_>> {
|
||||
BorrowedStr::try_from(self)
|
||||
}
|
||||
|
||||
@@ -102,12 +102,12 @@ impl String {
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_bytes(&self) -> BorrowedBytes {
|
||||
pub fn as_bytes(&self) -> BorrowedBytes<'_> {
|
||||
BorrowedBytes::from(self)
|
||||
}
|
||||
|
||||
/// Get the bytes that make up this string, including the trailing nul byte.
|
||||
pub fn as_bytes_with_nul(&self) -> BorrowedBytes {
|
||||
pub fn as_bytes_with_nul(&self) -> BorrowedBytes<'_> {
|
||||
let BorrowedBytes { buf, borrow, _lua } = BorrowedBytes::from(self);
|
||||
// Include the trailing nul byte (it's always present but excluded by default)
|
||||
let buf = unsafe { slice::from_raw_parts((*buf).as_ptr(), (*buf).len() + 1) };
|
||||
|
||||
+2
-2
@@ -613,7 +613,7 @@ impl Table {
|
||||
/// ```
|
||||
///
|
||||
/// [Lua manual]: http://www.lua.org/manual/5.4/manual.html#pdf-next
|
||||
pub fn pairs<K: FromLua, V: FromLua>(&self) -> TablePairs<K, V> {
|
||||
pub fn pairs<K: FromLua, V: FromLua>(&self) -> TablePairs<'_, K, V> {
|
||||
TablePairs {
|
||||
guard: self.0.lua.lock(),
|
||||
table: self,
|
||||
@@ -678,7 +678,7 @@ impl Table {
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn sequence_values<V: FromLua>(&self) -> TableSequence<V> {
|
||||
pub fn sequence_values<V: FromLua>(&self) -> TableSequence<'_, V> {
|
||||
TableSequence {
|
||||
guard: self.0.lua.lock(),
|
||||
table: self,
|
||||
|
||||
@@ -529,6 +529,7 @@ impl<R> Drop for AsyncThread<R> {
|
||||
// The thread is dropped while yielded, resume it with the "terminate" signal
|
||||
ffi::lua_pushlightuserdata(self.thread.1, crate::Lua::poll_terminate().0);
|
||||
if let Ok((new_status, _)) = self.thread.resume_inner(&lua, 1) {
|
||||
// `new_status` should always be `ThreadStatusInner::Yielded(0)`
|
||||
status = new_status;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ impl AppData {
|
||||
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub(crate) fn borrow<T: 'static>(&self, guard: Option<LuaGuard>) -> Option<AppDataRef<T>> {
|
||||
pub(crate) fn borrow<T: 'static>(&self, guard: Option<LuaGuard>) -> Option<AppDataRef<'_, T>> {
|
||||
match self.try_borrow(guard) {
|
||||
Ok(data) => data,
|
||||
Err(err) => panic!("already mutably borrowed: {err:?}"),
|
||||
@@ -53,7 +53,7 @@ impl AppData {
|
||||
pub(crate) fn try_borrow<T: 'static>(
|
||||
&self,
|
||||
guard: Option<LuaGuard>,
|
||||
) -> Result<Option<AppDataRef<T>>, BorrowError> {
|
||||
) -> Result<Option<AppDataRef<'_, T>>, BorrowError> {
|
||||
let data = unsafe { &*self.container.get() }
|
||||
.get(&TypeId::of::<T>())
|
||||
.map(|c| c.try_borrow())
|
||||
@@ -74,7 +74,7 @@ impl AppData {
|
||||
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub(crate) fn borrow_mut<T: 'static>(&self, guard: Option<LuaGuard>) -> Option<AppDataRefMut<T>> {
|
||||
pub(crate) fn borrow_mut<T: 'static>(&self, guard: Option<LuaGuard>) -> Option<AppDataRefMut<'_, T>> {
|
||||
match self.try_borrow_mut(guard) {
|
||||
Ok(data) => data,
|
||||
Err(err) => panic!("already borrowed: {err:?}"),
|
||||
@@ -84,7 +84,7 @@ impl AppData {
|
||||
pub(crate) fn try_borrow_mut<T: 'static>(
|
||||
&self,
|
||||
guard: Option<LuaGuard>,
|
||||
) -> Result<Option<AppDataRefMut<T>>, BorrowMutError> {
|
||||
) -> Result<Option<AppDataRefMut<'_, T>>, BorrowMutError> {
|
||||
let data = unsafe { &*self.container.get() }
|
||||
.get(&TypeId::of::<T>())
|
||||
.map(|c| c.try_borrow_mut())
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ mod inner {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn lock(&self) -> ReentrantMutexGuard<T> {
|
||||
pub(crate) fn lock(&self) -> ReentrantMutexGuard<'_, T> {
|
||||
ReentrantMutexGuard(&self.0)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1008,7 +1008,7 @@ impl UserDataMetatable {
|
||||
/// The pairs are wrapped in a [`Result`], since they are lazily converted to `V` type.
|
||||
///
|
||||
/// [`Result`]: crate::Result
|
||||
pub fn pairs<V: FromLua>(&self) -> UserDataMetatablePairs<V> {
|
||||
pub fn pairs<V: FromLua>(&self) -> UserDataMetatablePairs<'_, V> {
|
||||
UserDataMetatablePairs(self.0.pairs())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ pub(crate) unsafe fn init_internal_metatable<T: TypeKey>(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Uses 2 stack spaces, does not call checkstack
|
||||
// Uses up to 1 stack space, does not call `checkstack`
|
||||
pub(crate) unsafe fn get_internal_userdata<T: TypeKey>(
|
||||
state: *mut ffi::lua_State,
|
||||
index: c_int,
|
||||
|
||||
+2
-2
@@ -357,7 +357,7 @@ impl Value {
|
||||
/// If the value is a Lua [`String`], try to convert it to [`BorrowedStr`] or return `None`
|
||||
/// otherwise.
|
||||
#[inline]
|
||||
pub fn as_str(&self) -> Option<BorrowedStr> {
|
||||
pub fn as_str(&self) -> Option<BorrowedStr<'_>> {
|
||||
self.as_string().and_then(|s| s.to_str().ok())
|
||||
}
|
||||
|
||||
@@ -484,7 +484,7 @@ impl Value {
|
||||
#[cfg(feature = "serde")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
|
||||
#[doc(hidden)]
|
||||
pub fn to_serializable(&self) -> SerializableValue {
|
||||
pub fn to_serializable(&self) -> SerializableValue<'_> {
|
||||
SerializableValue::new(self, Default::default(), None)
|
||||
}
|
||||
|
||||
|
||||
@@ -610,6 +610,36 @@ async fn test_async_task() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_async_task_abort() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let sleep = lua.create_async_function(move |_lua, n: u64| async move {
|
||||
sleep_ms(n).await;
|
||||
Ok(())
|
||||
})?;
|
||||
lua.globals().set("sleep", sleep)?;
|
||||
|
||||
let local = tokio::task::LocalSet::new();
|
||||
local
|
||||
.run_until(async {
|
||||
let lua2 = lua.clone();
|
||||
let jh = tokio::task::spawn_local(async move {
|
||||
lua2.load("sleep(200) result = 'done'")
|
||||
.exec_async()
|
||||
.await
|
||||
.unwrap();
|
||||
});
|
||||
sleep_ms(100).await; // Wait for the task to start
|
||||
jh.abort();
|
||||
})
|
||||
.await;
|
||||
local.await;
|
||||
assert_eq!(lua.globals().get::<Value>("result")?, Value::Nil);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[cfg(not(feature = "luau"))]
|
||||
async fn test_async_hook() -> Result<()> {
|
||||
|
||||
+2
-2
@@ -306,7 +306,7 @@ fn test_function_deep_clone() -> Result<()> {
|
||||
|
||||
lua.globals().set("a", 1)?;
|
||||
let func1 = lua.load("a += 1; return a").into_function()?;
|
||||
let func2 = func1.deep_clone();
|
||||
let func2 = func1.deep_clone()?;
|
||||
|
||||
assert_ne!(func1.to_pointer(), func2.to_pointer());
|
||||
assert_eq!(func1.call::<i32>(())?, 2);
|
||||
@@ -314,7 +314,7 @@ fn test_function_deep_clone() -> Result<()> {
|
||||
|
||||
// Check that for Rust functions deep_clone is just a clone
|
||||
let rust_func = lua.create_function(|_, ()| Ok(42))?;
|
||||
let rust_func2 = rust_func.deep_clone();
|
||||
let rust_func2 = rust_func.deep_clone()?;
|
||||
assert_eq!(rust_func.to_pointer(), rust_func2.to_pointer());
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -196,6 +196,14 @@ fn test_sandbox() -> Result<()> {
|
||||
co.sandbox()?;
|
||||
assert_eq!(co.resume::<Option<i32>>(())?, Some(123));
|
||||
|
||||
// collectgarbage should be restricted in sandboxed mode
|
||||
let collectgarbage = lua.globals().get::<Function>("collectgarbage")?;
|
||||
for arg in ["collect", "stop", "restart", "step", "isrunning"] {
|
||||
let err = collectgarbage.call::<()>(arg).err().unwrap().to_string();
|
||||
assert!(err.contains("collectgarbage called with invalid option"));
|
||||
}
|
||||
assert!(collectgarbage.call::<u64>("count").unwrap() > 0);
|
||||
|
||||
lua.sandbox(false)?;
|
||||
|
||||
// Previously set variable `global` should be cleared now
|
||||
@@ -205,6 +213,11 @@ fn test_sandbox() -> Result<()> {
|
||||
let table = lua.globals().get::<Table>("table")?;
|
||||
table.set("test", "test")?;
|
||||
|
||||
// collectgarbage should work now
|
||||
for arg in ["collect", "stop", "restart", "count", "step", "isrunning"] {
|
||||
collectgarbage.call::<()>(arg).unwrap();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
+34
-19
@@ -105,63 +105,69 @@ fn test_require_without_config() {
|
||||
let lua = Lua::new();
|
||||
|
||||
// RequireSimpleRelativePath
|
||||
let res = run_require(&lua, "./require/without_config/dependency").unwrap();
|
||||
let res = run_require(&lua, "./tests/luau/require/without_config/dependency").unwrap();
|
||||
assert_eq!("result from dependency", get_str(&res, 1));
|
||||
|
||||
// RequireSimpleRelativePathWithinPcall
|
||||
let res = run_require_pcall(&lua, "./require/without_config/dependency").unwrap();
|
||||
let res = run_require_pcall(&lua, "./tests/luau/require/without_config/dependency").unwrap();
|
||||
assert!(res[0].as_boolean().unwrap());
|
||||
assert_eq!("result from dependency", get_str(&res[1], 1));
|
||||
|
||||
// RequireRelativeToRequiringFile
|
||||
let res = run_require(&lua, "./require/without_config/module").unwrap();
|
||||
let res = run_require(&lua, "./tests/luau/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();
|
||||
let res = run_require(&lua, "./tests/luau/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();
|
||||
let res = run_require(&lua, "./tests/luau/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();
|
||||
let res = run_require(&lua, "./tests/luau/require/without_config/lua").unwrap();
|
||||
assert_eq!("result from init.lua", get_str(&res, 1));
|
||||
|
||||
// RequireSubmoduleUsingSelfIndirectly
|
||||
let res = run_require(&lua, "./require/without_config/nested_module_requirer").unwrap();
|
||||
let res = run_require(&lua, "./tests/luau/require/without_config/nested_module_requirer").unwrap();
|
||||
assert_eq!("result from submodule", get_str(&res, 1));
|
||||
|
||||
// RequireSubmoduleUsingSelfDirectly
|
||||
let res = run_require(&lua, "./require/without_config/nested").unwrap();
|
||||
let res = run_require(&lua, "./tests/luau/require/without_config/nested").unwrap();
|
||||
assert_eq!("result from submodule", get_str(&res, 1));
|
||||
|
||||
// CannotRequireInitLuauDirectly
|
||||
let res = run_require(&lua, "./require/without_config/nested/init");
|
||||
let res = run_require(&lua, "./tests/luau/require/without_config/nested/init");
|
||||
assert!(res.is_err());
|
||||
assert!((res.unwrap_err().to_string()).contains("could not resolve child component \"init\""));
|
||||
|
||||
// RequireNestedInits
|
||||
let res = run_require(&lua, "./require/without_config/nested_inits_requirer").unwrap();
|
||||
let res = run_require(&lua, "./tests/luau/require/without_config/nested_inits_requirer").unwrap();
|
||||
assert_eq!("result from nested_inits/init", get_str(&res, 1));
|
||||
assert_eq!("required into module", get_str(&res, 2));
|
||||
|
||||
// RequireWithFileAmbiguity
|
||||
let res = run_require(&lua, "./require/without_config/ambiguous_file_requirer");
|
||||
let res = run_require(
|
||||
&lua,
|
||||
"./tests/luau/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");
|
||||
let res = run_require(
|
||||
&lua,
|
||||
"./tests/luau/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();
|
||||
let res = run_require(&lua, "./tests/luau/require/without_config/validate_cache").unwrap();
|
||||
assert!(res.is_table());
|
||||
}
|
||||
|
||||
@@ -170,15 +176,19 @@ fn test_require_with_config() {
|
||||
let lua = Lua::new();
|
||||
|
||||
// RequirePathWithAlias
|
||||
let res = run_require(&lua, "./require/with_config/src/alias_requirer").unwrap();
|
||||
let res = run_require(&lua, "./tests/luau/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();
|
||||
let res = run_require(&lua, "./tests/luau/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();
|
||||
let res = run_require(
|
||||
&lua,
|
||||
"./tests/luau/require/with_config/src/directory_alias_requirer",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!("result from subdirectory_dependency", get_str(&res, 1));
|
||||
|
||||
// RequireAliasThatDoesNotExist
|
||||
@@ -192,7 +202,7 @@ fn test_require_with_config() {
|
||||
assert!((res.unwrap_err().to_string()).contains("@ is not a valid alias"));
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[cfg(all(feature = "async", not(windows)))]
|
||||
#[tokio::test]
|
||||
async fn test_async_require() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
@@ -215,14 +225,19 @@ async fn test_async_require() -> Result<()> {
|
||||
Ok(())
|
||||
})?,
|
||||
)?;
|
||||
lua.globals().set("tmp_dir", temp_dir.path().to_str().unwrap())?;
|
||||
lua.globals().set(
|
||||
"curr_dir_components",
|
||||
std::env::current_dir().unwrap().components().count(),
|
||||
)?;
|
||||
|
||||
lua.load(
|
||||
r#"
|
||||
local result = require("./async_chunk")
|
||||
local path_to_root = string.rep("/..", curr_dir_components - 1)
|
||||
local result = require(`.{path_to_root}{tmp_dir}/async_chunk`)
|
||||
assert(result == "result_after_async_sleep")
|
||||
"#,
|
||||
)
|
||||
.set_name(format!("@{}", temp_dir.path().join("require.rs").display()))
|
||||
.exec_async()
|
||||
.await
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user