mirror of
https://github.com/mlua-rs/mlua
synced 2026-06-08 16:05:43 +00:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 15e353a7f8 | |||
| 765117c2bb | |||
| 573d71345f | |||
| 72de17bf47 | |||
| 5a96e80266 | |||
| bfdb4087b8 | |||
| eb84284824 | |||
| 34679e105d | |||
| bc194981fc | |||
| c9715aa5d9 | |||
| c108dc8213 | |||
| e86ef9d755 |
@@ -14,7 +14,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Generate coverage report
|
- name: Generate coverage report
|
||||||
run: |
|
run: |
|
||||||
cargo tarpaulin --verbose --features lua54,vendored,async,send,serialize,macros --out xml --exclude-files benches --exclude-files build --exclude-files mlua_derive --exclude-files src/ffi --exclude-files tests
|
cargo tarpaulin --out xml --tests --exclude-files benches/* --exclude-files src/ffi/*/*
|
||||||
|
|
||||||
- name: Upload report to codecov.io
|
- name: Upload report to codecov.io
|
||||||
uses: codecov/codecov-action@v3
|
uses: codecov/codecov-action@v3
|
||||||
|
|||||||
@@ -1,3 +1,21 @@
|
|||||||
|
## v0.8.9
|
||||||
|
|
||||||
|
- Update minimal (vendored) Lua 5.4 to 5.4.6
|
||||||
|
- Use `lua_closethread` instead of `lua_resetthread` in vendored mode (Lua 5.4.6)
|
||||||
|
- Allow deserializing Lua null into unit (`()`) or unit struct.
|
||||||
|
|
||||||
|
## v0.8.8
|
||||||
|
|
||||||
|
- Fix potential deadlock when trying to reuse dropped registry keys.
|
||||||
|
- Optimize userdata methods call when __index and fields_getters are nil
|
||||||
|
|
||||||
|
## v0.8.7
|
||||||
|
|
||||||
|
- Minimum Luau updated to 0.555 (`LUAI_MAXCSTACK` limit increased to 100000)
|
||||||
|
- `_VERSION` in Luau now includes version number
|
||||||
|
- Fixed lifetime of `DebugNames` in `Debug::names()` and `DebugSource` in `Debug::source()`
|
||||||
|
- Fixed subtraction overflow when calculating index for `MultiValue::get()`
|
||||||
|
|
||||||
## v0.8.6
|
## v0.8.6
|
||||||
|
|
||||||
- Fixed bug when recycled Registry slot can be set to Nil
|
- Fixed bug when recycled Registry slot can be set to Nil
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mlua"
|
name = "mlua"
|
||||||
version = "0.8.6" # remember to update html_root_url and mlua_derive
|
version = "0.8.9" # remember to update mlua_derive
|
||||||
authors = ["Aleksandr Orlenko <zxteam@pm.me>", "kyren <catherine@chucklefish.org>"]
|
authors = ["Aleksandr Orlenko <zxteam@pm.me>", "kyren <catherine@chucklefish.org>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
repository = "https://github.com/khvzak/mlua"
|
repository = "https://github.com/khvzak/mlua"
|
||||||
@@ -56,7 +56,7 @@ parking_lot = { version = "0.12", optional = true }
|
|||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cc = { version = "1.0" }
|
cc = { version = "1.0" }
|
||||||
pkg-config = { version = "0.3.17" }
|
pkg-config = { version = "0.3.17" }
|
||||||
lua-src = { version = ">= 544.0.0, < 550.0.0", optional = true }
|
lua-src = { version = ">= 546.0.0, < 550.0.0", optional = true }
|
||||||
luajit-src = { version = ">= 210.4.0, < 220.0.0", optional = true }
|
luajit-src = { version = ">= 210.4.0, < 220.0.0", optional = true }
|
||||||
luau0-src = { version = "0.5.0", optional = true }
|
luau0-src = { version = "0.5.0", optional = true }
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
[crates.io]: https://crates.io/crates/mlua
|
[crates.io]: https://crates.io/crates/mlua
|
||||||
[API Documentation]: https://docs.rs/mlua/badge.svg
|
[API Documentation]: https://docs.rs/mlua/badge.svg
|
||||||
[docs.rs]: https://docs.rs/mlua
|
[docs.rs]: https://docs.rs/mlua
|
||||||
[Coverage Status]: https://codecov.io/gh/khvzak/mlua/branch/master/graph/badge.svg?token=99339FS1CG
|
[Coverage Status]: https://codecov.io/gh/khvzak/mlua/branch/v0.8/graph/badge.svg?token=99339FS1CG
|
||||||
[codecov.io]: https://codecov.io/gh/khvzak/mlua
|
[codecov.io]: https://codecov.io/gh/khvzak/mlua
|
||||||
[MSRV]: https://img.shields.io/badge/rust-1.56+-brightgreen.svg?&logo=rust
|
[MSRV]: https://img.shields.io/badge/rust-1.56+-brightgreen.svg?&logo=rust
|
||||||
|
|
||||||
|
|||||||
@@ -112,7 +112,10 @@ extern "C" {
|
|||||||
pub fn lua_newstate(f: lua_Alloc, ud: *mut c_void) -> *mut lua_State;
|
pub fn lua_newstate(f: lua_Alloc, ud: *mut c_void) -> *mut lua_State;
|
||||||
pub fn lua_close(L: *mut lua_State);
|
pub fn lua_close(L: *mut lua_State);
|
||||||
pub fn lua_newthread(L: *mut lua_State) -> *mut lua_State;
|
pub fn lua_newthread(L: *mut lua_State) -> *mut lua_State;
|
||||||
|
// Deprecated in Lua 5.4.6
|
||||||
pub fn lua_resetthread(L: *mut lua_State) -> c_int;
|
pub fn lua_resetthread(L: *mut lua_State) -> c_int;
|
||||||
|
#[cfg(feature = "vendored")]
|
||||||
|
pub fn lua_closethread(L: *mut lua_State, from: *mut lua_State) -> c_int;
|
||||||
|
|
||||||
pub fn lua_atpanic(L: *mut lua_State, panicf: lua_CFunction) -> lua_CFunction;
|
pub fn lua_atpanic(L: *mut lua_State, panicf: lua_CFunction) -> lua_CFunction;
|
||||||
|
|
||||||
|
|||||||
@@ -71,8 +71,6 @@
|
|||||||
//! [`serde::Serialize`]: https://docs.serde.rs/serde/ser/trait.Serialize.html
|
//! [`serde::Serialize`]: https://docs.serde.rs/serde/ser/trait.Serialize.html
|
||||||
//! [`serde::Deserialize`]: https://docs.serde.rs/serde/de/trait.Deserialize.html
|
//! [`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.8.6")]
|
|
||||||
// Deny warnings inside doc tests / examples. When this isn't present, rustdoc doesn't show *any*
|
// Deny warnings inside doc tests / examples. When this isn't present, rustdoc doesn't show *any*
|
||||||
// warnings at all.
|
// warnings at all.
|
||||||
#![doc(test(attr(deny(warnings))))]
|
#![doc(test(attr(deny(warnings))))]
|
||||||
|
|||||||
+14
-7
@@ -1738,8 +1738,10 @@ impl Lua {
|
|||||||
let extra = &mut *self.extra.get();
|
let extra = &mut *self.extra.get();
|
||||||
if extra.recycled_thread_cache.len() < extra.recycled_thread_cache.capacity() {
|
if extra.recycled_thread_cache.len() < extra.recycled_thread_cache.capacity() {
|
||||||
let thread_state = ffi::lua_tothread(extra.ref_thread, thread.0.index);
|
let thread_state = ffi::lua_tothread(extra.ref_thread, thread.0.index);
|
||||||
#[cfg(feature = "lua54")]
|
#[cfg(all(feature = "lua54", not(feature = "vendored")))]
|
||||||
let status = ffi::lua_resetthread(thread_state);
|
let status = ffi::lua_resetthread(thread_state);
|
||||||
|
#[cfg(all(feature = "lua54", feature = "vendored"))]
|
||||||
|
let status = ffi::lua_closethread(thread_state, self.state);
|
||||||
#[cfg(feature = "lua54")]
|
#[cfg(feature = "lua54")]
|
||||||
if status != ffi::LUA_OK {
|
if status != ffi::LUA_OK {
|
||||||
// Error object is on top, drop it
|
// Error object is on top, drop it
|
||||||
@@ -2072,22 +2074,27 @@ impl Lua {
|
|||||||
let _sg = StackGuard::new(self.state);
|
let _sg = StackGuard::new(self.state);
|
||||||
check_stack(self.state, 4)?;
|
check_stack(self.state, 4)?;
|
||||||
|
|
||||||
let unref_list = (*self.extra.get()).registry_unref_list.clone();
|
|
||||||
self.push_value(t)?;
|
self.push_value(t)?;
|
||||||
|
|
||||||
// Try to reuse previously allocated slot
|
// Try to reuse previously allocated slot
|
||||||
let unref_list2 = unref_list.clone();
|
let unref_list = (*self.extra.get()).registry_unref_list.clone();
|
||||||
let mut unref_list2 = mlua_expect!(unref_list2.lock(), "unref list poisoned");
|
let free_registry_id = mlua_expect!(unref_list.lock(), "unref list poisoned")
|
||||||
if let Some(registry_id) = unref_list2.as_mut().and_then(|x| x.pop()) {
|
.as_mut()
|
||||||
|
.and_then(|x| x.pop());
|
||||||
|
if let Some(registry_id) = free_registry_id {
|
||||||
// It must be safe to replace the value without triggering memory error
|
// It must be safe to replace the value without triggering memory error
|
||||||
ffi::lua_rawseti(self.state, ffi::LUA_REGISTRYINDEX, registry_id as Integer);
|
ffi::lua_rawseti(self.state, ffi::LUA_REGISTRYINDEX, registry_id as Integer);
|
||||||
return Ok(RegistryKey::new(registry_id, unref_list));
|
return Ok(RegistryKey::new(registry_id, unref_list));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate a new RegistryKey
|
// Allocate a new RegistryKey
|
||||||
let registry_id = protect_lua!(self.state, 1, 0, |state| {
|
let registry_id = if self.unlikely_memory_error() {
|
||||||
|
ffi::luaL_ref(self.state, ffi::LUA_REGISTRYINDEX)
|
||||||
|
} else {
|
||||||
|
protect_lua!(self.state, 1, 0, |state| {
|
||||||
ffi::luaL_ref(state, ffi::LUA_REGISTRYINDEX)
|
ffi::luaL_ref(state, ffi::LUA_REGISTRYINDEX)
|
||||||
})?;
|
})?
|
||||||
|
};
|
||||||
Ok(RegistryKey::new(registry_id, unref_list))
|
Ok(RegistryKey::new(registry_id, unref_list))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-1
@@ -327,9 +327,31 @@ impl<'lua, 'de> serde::Deserializer<'de> for Deserializer<'lua> {
|
|||||||
visitor.visit_newtype_struct(self)
|
visitor.visit_newtype_struct(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
|
||||||
|
where
|
||||||
|
V: de::Visitor<'de>,
|
||||||
|
{
|
||||||
|
match self.value {
|
||||||
|
Value::LightUserData(ud) if ud.0.is_null() => visitor.visit_unit(),
|
||||||
|
_ => self.deserialize_any(visitor),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn deserialize_unit_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>
|
||||||
|
where
|
||||||
|
V: de::Visitor<'de>,
|
||||||
|
{
|
||||||
|
match self.value {
|
||||||
|
Value::LightUserData(ud) if ud.0.is_null() => visitor.visit_unit(),
|
||||||
|
_ => self.deserialize_any(visitor),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
serde::forward_to_deserialize_any! {
|
serde::forward_to_deserialize_any! {
|
||||||
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes
|
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes
|
||||||
byte_buf unit unit_struct identifier ignored_any
|
byte_buf identifier ignored_any
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -201,8 +201,10 @@ impl<'lua> Thread<'lua> {
|
|||||||
lua.push_ref(&self.0);
|
lua.push_ref(&self.0);
|
||||||
let thread_state = ffi::lua_tothread(lua.state, -1);
|
let thread_state = ffi::lua_tothread(lua.state, -1);
|
||||||
|
|
||||||
#[cfg(feature = "lua54")]
|
#[cfg(all(feature = "lua54", not(feature = "vendored")))]
|
||||||
let status = ffi::lua_resetthread(thread_state);
|
let status = ffi::lua_resetthread(thread_state);
|
||||||
|
#[cfg(all(feature = "lua54", feature = "vendored"))]
|
||||||
|
let status = ffi::lua_closethread(thread_state, lua.state);
|
||||||
#[cfg(feature = "lua54")]
|
#[cfg(feature = "lua54")]
|
||||||
if status != ffi::LUA_OK {
|
if status != ffi::LUA_OK {
|
||||||
return Err(pop_error(thread_state, status));
|
return Err(pop_error(thread_state, status));
|
||||||
|
|||||||
+10
-3
@@ -245,7 +245,8 @@ pub unsafe fn pop_error(state: *mut ffi::lua_State, err_code: c_int) -> Error {
|
|||||||
// Uses 3 (or 1 if unprotected) stack spaces, does not call checkstack.
|
// Uses 3 (or 1 if unprotected) stack spaces, does not call checkstack.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn push_string(state: *mut ffi::lua_State, s: &[u8], protect: bool) -> Result<()> {
|
pub unsafe fn push_string(state: *mut ffi::lua_State, s: &[u8], protect: bool) -> Result<()> {
|
||||||
if protect {
|
// Always use protected mode if the string is too long
|
||||||
|
if protect || s.len() > (1 << 30) {
|
||||||
protect_lua!(state, 0, 1, |state| {
|
protect_lua!(state, 0, 1, |state| {
|
||||||
ffi::lua_pushlstring(state, s.as_ptr() as *const c_char, s.len());
|
ffi::lua_pushlstring(state, s.as_ptr() as *const c_char, s.len());
|
||||||
})
|
})
|
||||||
@@ -427,11 +428,17 @@ unsafe fn init_userdata_metatable_index(state: *mut ffi::lua_State) -> Result<()
|
|||||||
}
|
}
|
||||||
ffi::lua_pop(state, 1);
|
ffi::lua_pop(state, 1);
|
||||||
|
|
||||||
// Create and cache `__index` helper
|
// Create and cache `__index` generator
|
||||||
let code = cstr!(
|
let code = cstr!(
|
||||||
r#"
|
r#"
|
||||||
local error, isfunction = ...
|
local error, isfunction = ...
|
||||||
return function (__index, field_getters, methods)
|
return function (__index, field_getters, methods)
|
||||||
|
-- Fastpath to return methods table for index access
|
||||||
|
if __index == nil and field_getters == nil then
|
||||||
|
return methods
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Alternatively return a function for index access
|
||||||
return function (self, key)
|
return function (self, key)
|
||||||
if field_getters ~= nil then
|
if field_getters ~= nil then
|
||||||
local field_getter = field_getters[key]
|
local field_getter = field_getters[key]
|
||||||
@@ -481,7 +488,7 @@ pub unsafe fn init_userdata_metatable_newindex(state: *mut ffi::lua_State) -> Re
|
|||||||
}
|
}
|
||||||
ffi::lua_pop(state, 1);
|
ffi::lua_pop(state, 1);
|
||||||
|
|
||||||
// Create and cache `__newindex` helper
|
// Create and cache `__newindex` generator
|
||||||
let code = cstr!(
|
let code = cstr!(
|
||||||
r#"
|
r#"
|
||||||
local error, isfunction = ...
|
local error, isfunction = ...
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
[lua54_coverage]
|
||||||
|
features = "lua54,vendored,async,serialize,macros"
|
||||||
|
|
||||||
|
[lua51_coverage]
|
||||||
|
features = "lua51,vendored,async,serialize,macros"
|
||||||
|
|
||||||
|
[luau_coverage]
|
||||||
|
features = "luau,async,serialize,macros"
|
||||||
+18
-5
@@ -391,31 +391,44 @@ fn test_from_value_newtype_struct() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_from_value_enum() -> Result<(), Box<dyn std::error::Error>> {
|
fn test_from_value_enum() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let lua = Lua::new();
|
let lua = Lua::new();
|
||||||
|
lua.globals().set("null", lua.null())?;
|
||||||
|
|
||||||
#[derive(Deserialize, PartialEq, Debug)]
|
#[derive(Deserialize, PartialEq, Debug)]
|
||||||
enum E {
|
struct UnitStruct;
|
||||||
|
|
||||||
|
#[derive(Deserialize, PartialEq, Debug)]
|
||||||
|
enum E<T = ()> {
|
||||||
Unit,
|
Unit,
|
||||||
Integer(u32),
|
Integer(u32),
|
||||||
Tuple(u32, u32),
|
Tuple(u32, u32),
|
||||||
Struct { a: u32 },
|
Struct { a: u32 },
|
||||||
|
Wrap(T),
|
||||||
}
|
}
|
||||||
|
|
||||||
let value = lua.load(r#""Unit""#).eval()?;
|
let value = lua.load(r#""Unit""#).eval()?;
|
||||||
let got = lua.from_value(value)?;
|
let got: E = lua.from_value(value)?;
|
||||||
assert_eq!(E::Unit, got);
|
assert_eq!(E::Unit, got);
|
||||||
|
|
||||||
let value = lua.load(r#"{Integer = 1}"#).eval()?;
|
let value = lua.load(r#"{Integer = 1}"#).eval()?;
|
||||||
let got = lua.from_value(value)?;
|
let got: E = lua.from_value(value)?;
|
||||||
assert_eq!(E::Integer(1), got);
|
assert_eq!(E::Integer(1), got);
|
||||||
|
|
||||||
let value = lua.load(r#"{Tuple = {1, 2}}"#).eval()?;
|
let value = lua.load(r#"{Tuple = {1, 2}}"#).eval()?;
|
||||||
let got = lua.from_value(value)?;
|
let got: E = lua.from_value(value)?;
|
||||||
assert_eq!(E::Tuple(1, 2), got);
|
assert_eq!(E::Tuple(1, 2), got);
|
||||||
|
|
||||||
let value = lua.load(r#"{Struct = {a = 3}}"#).eval()?;
|
let value = lua.load(r#"{Struct = {a = 3}}"#).eval()?;
|
||||||
let got = lua.from_value(value)?;
|
let got: E = lua.from_value(value)?;
|
||||||
assert_eq!(E::Struct { a: 3 }, got);
|
assert_eq!(E::Struct { a: 3 }, got);
|
||||||
|
|
||||||
|
let value = lua.load(r#"{Wrap = null}"#).eval()?;
|
||||||
|
let got = lua.from_value(value)?;
|
||||||
|
assert_eq!(E::Wrap(UnitStruct), got);
|
||||||
|
|
||||||
|
let value = lua.load(r#"{Wrap = null}"#).eval()?;
|
||||||
|
let got = lua.from_value(value)?;
|
||||||
|
assert_eq!(E::Wrap(()), got);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -991,7 +991,7 @@ fn test_ref_stack_exhaustion() {
|
|||||||
match catch_unwind(AssertUnwindSafe(|| -> Result<()> {
|
match catch_unwind(AssertUnwindSafe(|| -> Result<()> {
|
||||||
let lua = Lua::new();
|
let lua = Lua::new();
|
||||||
let mut vals = Vec::new();
|
let mut vals = Vec::new();
|
||||||
for _ in 0..1000000 {
|
for _ in 0..10000000 {
|
||||||
vals.push(lua.create_table()?);
|
vals.push(lua.create_table()?);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
Reference in New Issue
Block a user