mirror of
https://github.com/mlua-rs/mlua
synced 2026-06-08 16:05:43 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c85616137a | |||
| f52d106a82 | |||
| 10826a7e67 | |||
| 18c3255c90 | |||
| 6190427f37 | |||
| 9a5a341e44 | |||
| dd91ebfbe5 | |||
| f9fe869b76 | |||
| 6e4033abba |
@@ -1,3 +1,10 @@
|
||||
## v0.7.4
|
||||
|
||||
- Improved `Lua::create_registry_value` to reuse previously expired registry keys.
|
||||
No need to call `Lua::expire_registry_values` when creating/dropping registry values.
|
||||
- Added `Lua::replace_registry_value` to change value of an existing Registry Key
|
||||
- Async calls optimization
|
||||
|
||||
## v0.7.3
|
||||
|
||||
- Fixed cross-compilation issue (introduced in 84a174c)
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mlua"
|
||||
version = "0.7.3" # remember to update html_root_url and mlua_derive
|
||||
version = "0.7.4" # remember to update html_root_url and mlua_derive
|
||||
authors = ["Aleksandr Orlenko <zxteam@pm.me>", "kyren <catherine@chucklefish.org>"]
|
||||
edition = "2018"
|
||||
repository = "https://github.com/khvzak/mlua"
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub fn probe_lua() -> PathBuf {
|
||||
pub fn probe_lua() -> Option<PathBuf> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
@@ -101,6 +101,10 @@ pub const LUA_TFUNCTION: c_int = 6;
|
||||
pub const LUA_TUSERDATA: c_int = 7;
|
||||
pub const LUA_TTHREAD: c_int = 8;
|
||||
|
||||
// Type produced by LuaJIT FFI module
|
||||
#[cfg(feature = "luajit")]
|
||||
pub const LUA_TCDATA: c_int = 10;
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
pub const LUA_NUMTYPES: c_int = 9;
|
||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
||||
|
||||
@@ -236,6 +236,9 @@ pub use self::lua::LUA_ERRGCMM;
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
pub use self::lua::{LUA_ENVIRONINDEX, LUA_GLOBALSINDEX};
|
||||
|
||||
#[cfg(feature = "luajit")]
|
||||
pub use self::lua::LUA_TCDATA;
|
||||
|
||||
// constants from lauxlib.h
|
||||
pub use self::lauxlib::{LUA_ERRFILE, LUA_NOREF, LUA_REFNIL};
|
||||
|
||||
|
||||
+1
-1
@@ -72,7 +72,7 @@
|
||||
//! [`serde::Deserialize`]: https://docs.serde.rs/serde/de/trait.Deserialize.html
|
||||
|
||||
// mlua types in rustdoc of other crates get linked to here.
|
||||
#![doc(html_root_url = "https://docs.rs/mlua/0.7.3")]
|
||||
#![doc(html_root_url = "https://docs.rs/mlua/0.7.4")]
|
||||
// Deny warnings inside doc tests / examples. When this isn't present, rustdoc doesn't show *any*
|
||||
// warnings at all.
|
||||
#![doc(test(attr(deny(warnings))))]
|
||||
|
||||
+68
-10
@@ -1708,11 +1708,12 @@ impl Lua {
|
||||
|
||||
/// Place a value in the Lua registry with an auto-generated key.
|
||||
///
|
||||
/// This value will be available to rust from all `Lua` instances which share the same main
|
||||
/// This value will be available to Rust from all `Lua` instances which share the same main
|
||||
/// state.
|
||||
///
|
||||
/// Be warned, garbage collection of values held inside the registry is not automatic, see
|
||||
/// [`RegistryKey`] for more details.
|
||||
/// However, dropped [`RegistryKey`]s automatically reused to store new values.
|
||||
///
|
||||
/// [`RegistryKey`]: crate::RegistryKey
|
||||
pub fn create_registry_value<'lua, T: ToLua<'lua>>(&'lua self, t: T) -> Result<RegistryKey> {
|
||||
@@ -1721,14 +1722,29 @@ impl Lua {
|
||||
let _sg = StackGuard::new(self.state);
|
||||
check_stack(self.state, 4)?;
|
||||
|
||||
let unref_list = (*self.extra.get()).registry_unref_list.clone();
|
||||
self.push_value(t)?;
|
||||
|
||||
// Try to reuse previously allocated RegistryKey
|
||||
let unref_list2 = unref_list.clone();
|
||||
let mut unref_list2 = mlua_expect!(unref_list2.lock(), "unref list poisoned");
|
||||
if let Some(registry_id) = unref_list2.as_mut().and_then(|x| x.pop()) {
|
||||
// It must be safe to replace the value without triggering memory error
|
||||
ffi::lua_rawseti(self.state, ffi::LUA_REGISTRYINDEX, registry_id as Integer);
|
||||
return Ok(RegistryKey {
|
||||
registry_id,
|
||||
unref_list,
|
||||
});
|
||||
}
|
||||
|
||||
// Allocate a new RegistryKey
|
||||
let registry_id = protect_lua!(self.state, 1, 0, |state| {
|
||||
ffi::luaL_ref(state, ffi::LUA_REGISTRYINDEX)
|
||||
})?;
|
||||
|
||||
Ok(RegistryKey {
|
||||
registry_id,
|
||||
unref_list: (*self.extra.get()).registry_unref_list.clone(),
|
||||
unref_list,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1777,6 +1793,37 @@ impl Lua {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Replaces a value in the Lua registry by its `RegistryKey`.
|
||||
///
|
||||
/// See [`create_registry_value`] for more details.
|
||||
///
|
||||
/// [`create_registry_value`]: #method.create_registry_value
|
||||
pub fn replace_registry_value<'lua, T: ToLua<'lua>>(
|
||||
&'lua self,
|
||||
key: &RegistryKey,
|
||||
t: T,
|
||||
) -> Result<()> {
|
||||
if !self.owns_registry_value(key) {
|
||||
return Err(Error::MismatchedRegistryKey);
|
||||
}
|
||||
|
||||
let t = t.to_lua(self)?;
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(self.state);
|
||||
check_stack(self.state, 2)?;
|
||||
|
||||
self.push_value(t)?;
|
||||
// It must be safe to replace the value without triggering memory error
|
||||
ffi::lua_rawseti(
|
||||
self.state,
|
||||
ffi::LUA_REGISTRYINDEX,
|
||||
key.registry_id as Integer,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the given `RegistryKey` was created by a `Lua` which shares the underlying
|
||||
/// main state with this `Lua` instance.
|
||||
///
|
||||
@@ -1988,6 +2035,13 @@ impl Lua {
|
||||
|
||||
ffi::LUA_TTHREAD => Value::Thread(Thread(self.pop_ref())),
|
||||
|
||||
#[cfg(feature = "luajit")]
|
||||
ffi::LUA_TCDATA => {
|
||||
ffi::lua_pop(state, 1);
|
||||
// TODO: Fix this in a next major release
|
||||
panic!("cdata objects cannot be handled by mlua yet");
|
||||
}
|
||||
|
||||
_ => mlua_panic!("LUA_TNONE in pop_value"),
|
||||
}
|
||||
}
|
||||
@@ -2400,19 +2454,23 @@ impl Lua {
|
||||
Function(self.pop_ref())
|
||||
};
|
||||
|
||||
unsafe extern "C" fn unpack(state: *mut ffi::lua_State) -> c_int {
|
||||
let len = ffi::lua_tointeger(state, 2);
|
||||
ffi::luaL_checkstack(state, len as c_int, ptr::null());
|
||||
for i in 1..=len {
|
||||
ffi::lua_rawgeti(state, 1, i);
|
||||
}
|
||||
len as c_int
|
||||
}
|
||||
|
||||
let coroutine = self.globals().get::<_, Table>("coroutine")?;
|
||||
|
||||
let env = self.create_table_with_capacity(0, 4)?;
|
||||
env.set("get_poll", get_poll)?;
|
||||
env.set("yield", coroutine.get::<_, Function>("yield")?)?;
|
||||
env.set(
|
||||
"unpack",
|
||||
self.create_function(|lua, (tbl, len): (Table, Integer)| {
|
||||
let mut values = MultiValue::new_or_cached(lua);
|
||||
values.refill(tbl.raw_sequence_values_by_len(Some(len)))?;
|
||||
Ok(values)
|
||||
})?,
|
||||
)?;
|
||||
unsafe {
|
||||
env.set("unpack", self.create_c_function(unpack)?)?;
|
||||
}
|
||||
env.set("pending", {
|
||||
LightUserData(&ASYNC_POLL_PENDING as *const u8 as *mut c_void)
|
||||
})?;
|
||||
|
||||
+1
-1
@@ -455,7 +455,7 @@ impl<'lua> Table<'lua> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "async", feature = "serialize"))]
|
||||
#[cfg(any(feature = "serialize"))]
|
||||
pub(crate) fn raw_sequence_values_by_len<V: FromLua<'lua>>(
|
||||
self,
|
||||
len: Option<Integer>,
|
||||
|
||||
@@ -800,6 +800,17 @@ fn test_drop_registry_value() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_replace_registry_value() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let key = lua.create_registry_value::<i32>(42)?;
|
||||
lua.replace_registry_value(&key, "new value")?;
|
||||
assert_eq!(lua.registry_value::<String>(&key)?, "new value");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lua_registry_hash() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
@@ -1256,3 +1267,24 @@ fn test_warnings() -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "luajit")]
|
||||
#[should_panic]
|
||||
fn test_luajit_cdata() {
|
||||
let lua = unsafe { Lua::unsafe_new() };
|
||||
let _v: Result<Value> = lua
|
||||
.load(
|
||||
r#"
|
||||
local ffi = require("ffi")
|
||||
ffi.cdef[[
|
||||
void *malloc(size_t size);
|
||||
void free(void *ptr);
|
||||
]]
|
||||
local ptr = ffi.C.malloc(1)
|
||||
ffi.C.free(ptr)
|
||||
return ptr
|
||||
"#,
|
||||
)
|
||||
.eval();
|
||||
}
|
||||
|
||||
+9
-1
@@ -130,7 +130,15 @@ fn test_thread_reset() -> Result<()> {
|
||||
assert_eq!(thread.status(), ThreadStatus::Error);
|
||||
assert_eq!(Arc::strong_count(&arc), 2);
|
||||
assert!(thread.reset(func.clone()).is_err());
|
||||
assert_eq!(thread.status(), ThreadStatus::Error);
|
||||
// Reset behavior has changed in Lua v5.4.4
|
||||
// It's became possible to force reset thread by popping error object
|
||||
assert!(matches!(
|
||||
thread.status(),
|
||||
ThreadStatus::Unresumable | ThreadStatus::Error
|
||||
));
|
||||
// Would pass in 5.4.4
|
||||
// assert!(thread.reset(func.clone()).is_ok());
|
||||
// assert_eq!(thread.status(), ThreadStatus::Resumable);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user