Compare commits

...

28 Commits

Author SHA1 Message Date
Alex Orlenko 270b98a429 v0.9.6 2024-02-29 15:39:14 +00:00
Alex Orlenko 0ee3324462 Add LUA_TCDATA to util::to_string() helper 2024-02-29 12:57:04 +00:00
Alex Orlenko 8a9c4f0b15 Optimize table array traversal during serialization 2024-02-11 23:02:36 +00:00
Alex Orlenko 34db5f985e Refactor benchmarks 2024-02-11 17:48:25 +00:00
Alex Orlenko 020e8a78a8 Impl FromLua for RegistryKey 2024-02-10 15:41:48 +00:00
Alex Orlenko 3ca7b4942e Implement IntoLua for &Value 2024-02-07 00:10:49 +00:00
Alex Orlenko 1754226c74 Impl IntoLua::push_into_stack for integers 2024-02-03 21:32:49 +00:00
Alex Orlenko 3014c4d7a1 Add REF_STACK_RESERVE constant 2024-02-02 23:26:33 +00:00
Alex Orlenko 908f37656a Add to_pointer function to Function/Table/Thread 2024-02-02 09:23:16 +00:00
Alex Orlenko f4d783cb41 Impl push_into_stack for StdResult 2024-02-01 23:42:44 +00:00
Alex Orlenko f5982bc204 Add inline to FromLua<bool>::from_stack 2024-01-27 14:40:32 +00:00
Alex Orlenko e30b425224 Fix crash when initializing Luau sandbox without stdlibs (#361) 2024-01-27 11:51:59 +00:00
Alex Orlenko 512921404c Add fastpath push_into_stack/from_stack methods for bool type 2024-01-26 14:07:56 +00:00
Alex Orlenko dfd82edc42 Add Lua::push() helper 2024-01-26 13:52:19 +00:00
Alex Orlenko 75a15ceabf v0.9.5 2024-01-25 22:24:58 +00:00
Alex Orlenko 60730fd068 Update compile tests messages 2024-01-25 18:19:16 +00:00
Alex Orlenko df778b7b33 Impl Into/FromLua for OwnedString 2024-01-25 18:04:55 +00:00
Alex Orlenko 45299c0ef1 Update authors 2024-01-25 12:56:57 +00:00
Alex Orlenko 38eec1236c Update itertools dependency 2024-01-25 10:49:39 +00:00
Alex Orlenko 145c5b316b Fix FromLua derive proc macro to cover more cases 2024-01-25 10:26:43 +00:00
Alex Orlenko e97e69a309 Update Luau to 0.609 (luau-src v0.8.0) 2024-01-25 09:38:46 +00:00
Alex Orlenko 2ac7b23596 Impl Into/FromLua for OwnedThread 2024-01-25 09:34:37 +00:00
Alex Orlenko 8200bee467 Implement IntoLua for ref to String/Table/Function/AnyUserData
This would prevent cloning plus has better performance when pushing values to Lua stack (`IntoLua::push_into_stack` method)
2024-01-23 22:14:50 +00:00
Alex Orlenko fe6ab250bf Update codecov links after moving repo 2024-01-23 21:56:00 +00:00
Alex Orlenko 804972b099 Fix typos in examples/guided_tour 2024-01-23 20:50:57 +00:00
Alex Orlenko 727f99ee4d Implement IntoLua for &RegistryKey
This would allow just passing registry keys to arguments with fasttrack to push directly into stack.
2024-01-20 22:04:28 +00:00
Alex Orlenko 3c801e7b17 Expose internal POLL_PENDING constant (hidden) 2024-01-20 15:52:00 +00:00
Alex Orlenko a38e484fe9 Increase luau max stack size to 1M from 100k 2024-01-18 23:05:23 +00:00
43 changed files with 1250 additions and 427 deletions
+16
View File
@@ -1,3 +1,19 @@
## v0.9.6
- Added `to_pointer` function to `Function`/`Table`/`Thread`
- Implemented `IntoLua` for `&Value`
- Implemented `FromLua` for `RegistryKey`
- Faster (~5%) table array traversal during serialization
- Some performance improvements for bool/int types
## v0.9.5
- Minimal Luau updated to 0.609
- Luau max stack size increased to 1M (from 100K)
- Implemented `IntoLua` for refs to `String`/`Table`/`Function`/`AnyUserData`/`Thread` + `RegistryKey`
- Implemented `IntoLua` and `FromLua` for `OwnedThread`/`OwnedString`
- Fixed `FromLua` derive proc macro to cover more cases
## v0.9.4
- Fixed loading all-in-one modules under mixed states (eg. main state and coroutines)
+4 -4
View File
@@ -1,7 +1,7 @@
[package]
name = "mlua"
version = "0.9.4" # remember to update mlua_derive
authors = ["Aleksandr Orlenko <zxteam@pm.me>", "kyren <catherine@chucklefish.org>"]
version = "0.9.6" # remember to update mlua_derive
authors = ["Aleksandr Orlenko <zxteam@pm.me>", "kyren <catherine@kyju.org>"]
rust-version = "1.71"
edition = "2021"
repository = "https://github.com/khvzak/mlua"
@@ -44,7 +44,7 @@ macros = ["mlua_derive/macros"]
unstable = []
[dependencies]
mlua_derive = { version = "=0.9.1", optional = true, path = "mlua_derive" }
mlua_derive = { version = "=0.9.2", optional = true, path = "mlua_derive" }
bstr = { version = "1.0", features = ["std"], default_features = false }
once_cell = { version = "1.0" }
num-traits = { version = "0.2.14" }
@@ -55,7 +55,7 @@ erased-serde = { version = "0.4", optional = true }
serde-value = { version = "0.7", optional = true }
parking_lot = { version = "0.12", optional = true }
ffi = { package = "mlua-sys", version = "0.5.0", path = "mlua-sys" }
ffi = { package = "mlua-sys", version = "0.5.1", path = "mlua-sys" }
[target.'cfg(unix)'.dependencies]
libloading = { version = "0.8", optional = true }
+2 -2
View File
@@ -7,8 +7,8 @@
[crates.io]: https://crates.io/crates/mlua
[API Documentation]: https://docs.rs/mlua/badge.svg
[docs.rs]: https://docs.rs/mlua
[Coverage Status]: https://codecov.io/gh/khvzak/mlua/branch/master/graph/badge.svg?token=99339FS1CG
[codecov.io]: https://codecov.io/gh/khvzak/mlua
[Coverage Status]: https://codecov.io/gh/mlua-rs/mlua/branch/master/graph/badge.svg?token=99339FS1CG
[codecov.io]: https://codecov.io/gh/mlua-rs/mlua
[MSRV]: https://img.shields.io/badge/rust-1.71+-brightgreen.svg?&logo=rust
[Guided Tour] | [Benchmarks] | [FAQ]
+187 -166
View File
@@ -1,5 +1,7 @@
use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Duration;
use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
use tokio::runtime::Runtime;
use tokio::task;
@@ -10,10 +12,10 @@ fn collect_gc_twice(lua: &Lua) {
lua.gc_collect().unwrap();
}
fn create_table(c: &mut Criterion) {
fn table_create_empty(c: &mut Criterion) {
let lua = Lua::new();
c.bench_function("create [table empty]", |b| {
c.bench_function("table [create empty]", |b| {
b.iter_batched(
|| collect_gc_twice(&lua),
|_| {
@@ -24,35 +26,33 @@ fn create_table(c: &mut Criterion) {
});
}
fn create_array(c: &mut Criterion) {
fn table_create_array(c: &mut Criterion) {
let lua = Lua::new();
c.bench_function("create [array] 10", |b| {
c.bench_function("table [create array]", |b| {
b.iter_batched(
|| collect_gc_twice(&lua),
|_| {
let table = lua.create_table().unwrap();
for i in 1..=10 {
table.set(i, i).unwrap();
}
lua.create_sequence_from(1..=10).unwrap();
},
BatchSize::SmallInput,
);
});
}
fn create_string_table(c: &mut Criterion) {
fn table_create_hash(c: &mut Criterion) {
let lua = Lua::new();
c.bench_function("create [table string] 10", |b| {
c.bench_function("table [create hash]", |b| {
b.iter_batched(
|| collect_gc_twice(&lua),
|_| {
let table = lua.create_table().unwrap();
for &s in &["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"] {
let s = lua.create_string(s).unwrap();
table.set(s.clone(), s).unwrap();
}
lua.create_table_from(
["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]
.into_iter()
.map(|s| (s, s)),
)
.unwrap();
},
BatchSize::SmallInput,
);
@@ -62,17 +62,15 @@ fn create_string_table(c: &mut Criterion) {
fn table_get_set(c: &mut Criterion) {
let lua = Lua::new();
let table = lua.create_table().unwrap();
c.bench_function("table raw_get and raw_set [10]", |b| {
c.bench_function("table [get and set]", |b| {
b.iter_batched(
|| {
collect_gc_twice(&lua);
table.clear().unwrap();
lua.create_table().unwrap()
},
|_| {
for (i, &s) in ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]
.iter()
|table| {
for (i, s) in ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]
.into_iter()
.enumerate()
{
table.raw_set(s, i).unwrap();
@@ -87,7 +85,7 @@ fn table_get_set(c: &mut Criterion) {
fn table_traversal_pairs(c: &mut Criterion) {
let lua = Lua::new();
c.bench_function("table traversal [pairs]", |b| {
c.bench_function("table [traversal pairs]", |b| {
b.iter_batched(
|| lua.globals(),
|globals| {
@@ -103,7 +101,7 @@ fn table_traversal_pairs(c: &mut Criterion) {
fn table_traversal_for_each(c: &mut Criterion) {
let lua = Lua::new();
c.bench_function("table traversal [for_each]", |b| {
c.bench_function("table [traversal for_each]", |b| {
b.iter_batched(
|| lua.globals(),
|globals| globals.for_each::<String, LuaValue>(|_k, _v| Ok(())),
@@ -117,7 +115,7 @@ fn table_traversal_sequence(c: &mut Criterion) {
let table = lua.create_sequence_from(1..1000).unwrap();
c.bench_function("table traversal [sequence]", |b| {
c.bench_function("table [traversal sequence]", |b| {
b.iter_batched(
|| table.clone(),
|table| {
@@ -130,236 +128,255 @@ fn table_traversal_sequence(c: &mut Criterion) {
});
}
fn create_function(c: &mut Criterion) {
fn function_create(c: &mut Criterion) {
let lua = Lua::new();
c.bench_function("create [function] 10", |b| {
c.bench_function("function [create Rust]", |b| {
b.iter_batched(
|| collect_gc_twice(&lua),
|_| {
for i in 0..10 {
lua.create_function(move |_, ()| Ok(i)).unwrap();
}
lua.create_function(|_, ()| Ok(123)).unwrap();
},
BatchSize::SmallInput,
);
});
}
fn call_lua_function(c: &mut Criterion) {
fn function_call_sum(c: &mut Criterion) {
let lua = Lua::new();
c.bench_function("call Lua function [sum] 3 10", |b| {
b.iter_batched_ref(
|| {
collect_gc_twice(&lua);
lua.load("function(a, b, c) return a + b + c end")
.eval::<LuaFunction>()
.unwrap()
},
|function| {
for i in 0..10 {
let _result: i64 = function.call((i, i + 1, i + 2)).unwrap();
}
},
BatchSize::SmallInput,
);
});
}
fn call_sum_callback(c: &mut Criterion) {
let lua = Lua::new();
let callback = lua
.create_function(|_, (a, b, c): (i64, i64, i64)| Ok(a + b + c))
let sum = lua
.create_function(|_, (a, b, c): (i64, i64, i64)| Ok(a + b - c))
.unwrap();
lua.globals().set("callback", callback).unwrap();
c.bench_function("call Rust callback [sum] 3 10", |b| {
b.iter_batched_ref(
|| {
collect_gc_twice(&lua);
lua.load("function() for i = 1,10 do callback(i, i+1, i+2) end end")
.eval::<LuaFunction>()
.unwrap()
},
|function| {
function.call::<_, ()>(()).unwrap();
c.bench_function("function [call Rust sum]", |b| {
b.iter_batched(
|| collect_gc_twice(&lua),
|_| {
assert_eq!(sum.call::<_, i64>((10, 20, 30)).unwrap(), 0);
},
BatchSize::SmallInput,
);
});
}
fn call_async_sum_callback(c: &mut Criterion) {
let options = LuaOptions::new().thread_pool_size(1024);
let lua = Lua::new_with(LuaStdLib::ALL_SAFE, options).unwrap();
let callback = lua
.create_async_function(|_, (a, b, c): (i64, i64, i64)| async move {
task::yield_now().await;
Ok(a + b + c)
})
.unwrap();
lua.globals().set("callback", callback).unwrap();
c.bench_function("call async Rust callback [sum] 3 10", |b| {
let rt = Runtime::new().unwrap();
b.to_async(rt).iter_batched(
|| {
collect_gc_twice(&lua);
lua.load("function() for i = 1,10 do callback(i, i+1, i+2) end end")
.eval::<LuaFunction>()
.unwrap()
},
|function| async move {
function.call_async::<_, ()>(()).await.unwrap();
},
BatchSize::SmallInput,
);
});
}
fn call_concat_callback(c: &mut Criterion) {
fn function_call_lua_sum(c: &mut Criterion) {
let lua = Lua::new();
let callback = lua
let sum = lua
.load("function(a, b, c) return a + b - c end")
.eval::<LuaFunction>()
.unwrap();
c.bench_function("function [call Lua sum]", |b| {
b.iter_batched(
|| collect_gc_twice(&lua),
|_| {
assert_eq!(sum.call::<_, i64>((10, 20, 30)).unwrap(), 0);
},
BatchSize::SmallInput,
);
});
}
fn function_call_concat(c: &mut Criterion) {
let lua = Lua::new();
let concat = lua
.create_function(|_, (a, b): (LuaString, LuaString)| {
Ok(format!("{}{}", a.to_str()?, b.to_str()?))
})
.unwrap();
lua.globals().set("callback", callback).unwrap();
let i = AtomicUsize::new(0);
c.bench_function("call Rust callback [concat string] 10", |b| {
b.iter_batched_ref(
c.bench_function("function [call Rust concat string]", |b| {
b.iter_batched(
|| {
collect_gc_twice(&lua);
lua.load("function() for i = 1,10 do callback('a', tostring(i)) end end")
.eval::<LuaFunction>()
.unwrap()
i.fetch_add(1, Ordering::Relaxed)
},
|function| {
function.call::<_, ()>(()).unwrap();
|i| {
assert_eq!(
concat.call::<_, LuaString>(("num:", i)).unwrap(),
format!("num:{i}")
);
},
BatchSize::SmallInput,
);
});
}
fn create_registry_values(c: &mut Criterion) {
fn function_call_lua_concat(c: &mut Criterion) {
let lua = Lua::new();
c.bench_function("create [registry value] 10", |b| {
let concat = lua
.load("function(a, b) return a..b end")
.eval::<LuaFunction>()
.unwrap();
let i = AtomicUsize::new(0);
c.bench_function("function [call Lua concat string]", |b| {
b.iter_batched(
|| collect_gc_twice(&lua),
|_| {
for _ in 0..10 {
lua.create_registry_value(lua.pack(true).unwrap()).unwrap();
}
lua.expire_registry_values();
|| {
collect_gc_twice(&lua);
i.fetch_add(1, Ordering::Relaxed)
},
|i| {
assert_eq!(
concat.call::<_, LuaString>(("num:", i)).unwrap(),
format!("num:{i}")
);
},
BatchSize::SmallInput,
);
});
}
fn create_userdata(c: &mut Criterion) {
fn function_async_call_sum(c: &mut Criterion) {
let options = LuaOptions::new().thread_pool_size(1024);
let lua = Lua::new_with(LuaStdLib::ALL_SAFE, options).unwrap();
let sum = lua
.create_async_function(|_, (a, b, c): (i64, i64, i64)| async move {
task::yield_now().await;
Ok(a + b - c)
})
.unwrap();
c.bench_function("function [async call Rust sum]", |b| {
let rt = Runtime::new().unwrap();
b.to_async(rt).iter_batched(
|| collect_gc_twice(&lua),
|_| async {
assert_eq!(sum.call_async::<_, i64>((10, 20, 30)).await.unwrap(), 0);
},
BatchSize::SmallInput,
);
});
}
fn registry_value_create(c: &mut Criterion) {
let lua = Lua::new();
lua.gc_stop();
c.bench_function("registry value [create]", |b| {
b.iter_batched(
|| collect_gc_twice(&lua),
|_| lua.create_registry_value("hello").unwrap(),
BatchSize::SmallInput,
);
});
}
fn userdata_create(c: &mut Criterion) {
struct UserData(i64);
impl LuaUserData for UserData {}
let lua = Lua::new();
c.bench_function("create [table userdata] 10", |b| {
c.bench_function("userdata [create]", |b| {
b.iter_batched(
|| collect_gc_twice(&lua),
|_| {
let table: LuaTable = lua.create_table().unwrap();
for i in 1..11 {
table.set(i, UserData(i)).unwrap();
}
lua.create_userdata(UserData(123)).unwrap();
},
BatchSize::SmallInput,
);
});
}
fn call_userdata_index(c: &mut Criterion) {
fn userdata_call_index(c: &mut Criterion) {
struct UserData(i64);
impl LuaUserData for UserData {
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_meta_method(LuaMetaMethod::Index, move |_, _, index: String| Ok(index));
methods.add_meta_method(LuaMetaMethod::Index, move |_, _, key: LuaString| Ok(key));
}
}
let lua = Lua::new();
lua.globals().set("userdata", UserData(10)).unwrap();
let ud = lua.create_userdata(UserData(123)).unwrap();
let index = lua
.load("function(ud) return ud.test end")
.eval::<LuaFunction>()
.unwrap();
c.bench_function("call [userdata index] 10", |b| {
b.iter_batched_ref(
|| {
collect_gc_twice(&lua);
lua.load("function() for i = 1,10 do local v = userdata.test end end")
.eval::<LuaFunction>()
.unwrap()
},
|function| {
function.call::<_, ()>(()).unwrap();
c.bench_function("userdata [call index]", |b| {
b.iter_batched(
|| collect_gc_twice(&lua),
|_| {
assert_eq!(index.call::<_, LuaString>(&ud).unwrap(), "test");
},
BatchSize::SmallInput,
);
});
}
fn call_userdata_method(c: &mut Criterion) {
fn userdata_call_method(c: &mut Criterion) {
struct UserData(i64);
impl LuaUserData for UserData {
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_method("method", |_, this, ()| Ok(this.0));
methods.add_method("add", |_, this, i: i64| Ok(this.0 + i));
}
}
let lua = Lua::new();
lua.globals().set("userdata", UserData(10)).unwrap();
let ud = lua.create_userdata(UserData(123)).unwrap();
let method = lua
.load("function(ud, i) return ud:add(i) end")
.eval::<LuaFunction>()
.unwrap();
let i = AtomicUsize::new(0);
c.bench_function("call [userdata method] 10", |b| {
b.iter_batched_ref(
c.bench_function("userdata [call method]", |b| {
b.iter_batched(
|| {
collect_gc_twice(&lua);
lua.load("function() for i = 1,10 do userdata:method() end end")
.eval::<LuaFunction>()
.unwrap()
i.fetch_add(1, Ordering::Relaxed)
},
|function| {
function.call::<_, ()>(()).unwrap();
|i| {
assert_eq!(method.call::<_, usize>((&ud, i)).unwrap(), 123 + i);
},
BatchSize::SmallInput,
);
});
}
fn call_async_userdata_method(c: &mut Criterion) {
struct UserData(String);
fn userdata_async_call_method(c: &mut Criterion) {
struct UserData(i64);
impl LuaUserData for UserData {
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_async_method("method", |_, this, ()| async move { Ok(this.0.clone()) });
methods.add_async_method("add", |_, this, i: i64| async move {
task::yield_now().await;
Ok(this.0 + i)
});
}
}
let options = LuaOptions::new().thread_pool_size(1024);
let lua = Lua::new_with(LuaStdLib::ALL_SAFE, options).unwrap();
lua.globals()
.set("userdata", UserData("hello".to_string()))
let ud = lua.create_userdata(UserData(123)).unwrap();
let method = lua
.load("function(ud, i) return ud:add(i) end")
.eval::<LuaFunction>()
.unwrap();
let i = AtomicUsize::new(0);
c.bench_function("call async [userdata method] 10", |b| {
c.bench_function("userdata [async call method] 10", |b| {
let rt = Runtime::new().unwrap();
b.to_async(rt).iter_batched(
|| {
collect_gc_twice(&lua);
lua.load("function() for i = 1,10 do userdata:method() end end")
.eval::<LuaFunction>()
.unwrap()
(
method.clone(),
ud.clone(),
i.fetch_add(1, Ordering::Relaxed),
)
},
|function| async move {
function.call_async::<_, ()>(()).await.unwrap();
|(method, ud, i)| async move {
assert_eq!(
method.call_async::<_, usize>((ud, i)).await.unwrap(),
123 + i
);
},
BatchSize::SmallInput,
);
@@ -369,27 +386,31 @@ fn call_async_userdata_method(c: &mut Criterion) {
criterion_group! {
name = benches;
config = Criterion::default()
.sample_size(300)
.sample_size(500)
.measurement_time(Duration::from_secs(10))
.noise_threshold(0.02);
targets =
create_table,
create_array,
create_string_table,
table_create_empty,
table_create_array,
table_create_hash,
table_get_set,
table_traversal_pairs,
table_traversal_for_each,
table_traversal_sequence,
create_function,
call_lua_function,
call_sum_callback,
call_async_sum_callback,
call_concat_callback,
create_registry_values,
create_userdata,
call_userdata_index,
call_userdata_method,
call_async_userdata_method,
function_create,
function_call_sum,
function_call_lua_sum,
function_call_concat,
function_call_lua_concat,
function_async_call_sum,
registry_value_create,
userdata_create,
userdata_call_index,
userdata_call_method,
userdata_async_call_method,
}
criterion_main!(benches);
+25 -33
View File
@@ -8,43 +8,35 @@ fn collect_gc_twice(lua: &Lua) {
lua.gc_collect().unwrap();
}
fn serialize_json(c: &mut Criterion) {
fn encode_json(c: &mut Criterion) {
let lua = Lua::new();
lua.globals()
.set(
"encode",
LuaFunction::wrap(|_, t: LuaValue| Ok(serde_json::to_string(&t).unwrap())),
let encode = lua
.create_function(|_, t: LuaValue| Ok(serde_json::to_string(&t).unwrap()))
.unwrap();
let table = lua
.load(
r#"{
name = "Clark Kent",
address = {
city = "Smallville",
state = "Kansas",
country = "USA",
},
age = 22,
parents = {"Jonathan Kent", "Martha Kent"},
superman = true,
interests = {"flying", "saving the world", "kryptonite"},
}"#,
)
.eval::<LuaTable>()
.unwrap();
c.bench_function("serialize table to json [10]", |b| {
c.bench_function("serialize json", |b| {
b.iter_batched(
|| {
collect_gc_twice(&lua);
lua.load(
r#"
local encode = encode
return function()
for i = 1, 10 do
encode({
name = "Clark Kent",
nickname = "Superman",
address = {
city = "Metropolis",
},
age = 32,
superman = true,
})
end
end
"#,
)
.eval::<LuaFunction>()
.unwrap()
},
|func| {
func.call::<_, ()>(()).unwrap();
|| collect_gc_twice(&lua),
|_| {
encode.call::<_, LuaString>(&table).unwrap();
},
BatchSize::SmallInput,
);
@@ -54,11 +46,11 @@ fn serialize_json(c: &mut Criterion) {
criterion_group! {
name = benches;
config = Criterion::default()
.sample_size(300)
.sample_size(500)
.measurement_time(Duration::from_secs(10))
.noise_threshold(0.02);
targets =
serialize_json,
encode_json,
}
criterion_main!(benches);
+3 -3
View File
@@ -24,7 +24,7 @@ fn main() -> Result<()> {
// You can load and evaluate Lua code. The returned type of `Lua::load` is a builder
// that allows you to change settings before running Lua code. Here, we are using it to set
// the name of the laoded chunk to "example code", which will be used when Lua error
// the name of the loaded chunk to "example code", which will be used when Lua error
// messages are printed.
lua.load(
@@ -89,7 +89,7 @@ fn main() -> Result<()> {
let print: Function = globals.get("print")?;
print.call::<_, ()>("hello from rust")?;
// This API generally handles variadics using tuples. This is one way to call a function with
// This API generally handles variadic using tuples. This is one way to call a function with
// multiple parameters:
print.call::<_, ()>(("hello", "again", "from", "rust"))?;
@@ -100,7 +100,7 @@ fn main() -> Result<()> {
["hello", "yet", "again", "from", "rust"].iter().cloned(),
))?;
// You can bind rust functions to Lua as well. Callbacks receive the Lua state inself as their
// You can bind rust functions to Lua as well. Callbacks receive the Lua state itself as their
// first parameter, and the arguments given to the function as the second parameter. The type
// of the arguments can be anything that is convertible from the parameters given by Lua, in
// this case, the function expects two string sequences.
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "mlua-sys"
version = "0.5.0"
version = "0.5.1"
authors = ["Aleksandr Orlenko <zxteam@pm.me>"]
rust-version = "1.71"
edition = "2021"
@@ -40,4 +40,4 @@ cfg-if = "1.0"
pkg-config = "0.3.17"
lua-src = { version = ">= 546.0.2, < 546.1.0", optional = true }
luajit-src = { version = ">= 210.5.0, < 210.6.0", optional = true }
luau0-src = { version = "0.7.11", optional = true }
luau0-src = { version = "0.8.0", optional = true }
+1
View File
@@ -21,6 +21,7 @@ pub fn probe_lua() {
#[cfg(feature = "luau")]
let artifacts = luau0_src::Build::new()
.enable_codegen(cfg!(feature = "luau-codegen"))
.set_max_cstack_size(1000000)
.set_vector_size(if cfg!(feature = "luau-vector4") { 4 } else { 3 })
.build();
+8
View File
@@ -328,6 +328,14 @@ pub unsafe fn lua_getglobal_(L: *mut lua_State, var: *const c_char) {
lua_getfield_(L, LUA_GLOBALSINDEX, var)
}
#[inline(always)]
pub unsafe fn lua_tolightuserdata(L: *mut lua_State, idx: c_int) -> *mut c_void {
if lua_islightuserdata(L, idx) != 0 {
return lua_touserdata(L, idx);
}
ptr::null_mut()
}
#[inline(always)]
pub unsafe fn lua_tostring(L: *mut lua_State, i: c_int) -> *const c_char {
lua_tolstring(L, i, ptr::null_mut())
+8
View File
@@ -417,6 +417,14 @@ pub unsafe fn lua_pushglobaltable(L: *mut lua_State) {
lua_rawgeti_(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS as _)
}
#[inline(always)]
pub unsafe fn lua_tolightuserdata(L: *mut lua_State, idx: c_int) -> *mut c_void {
if lua_islightuserdata(L, idx) != 0 {
return lua_touserdata(L, idx);
}
ptr::null_mut()
}
#[inline(always)]
pub unsafe fn lua_tostring(L: *mut lua_State, i: c_int) -> *const c_char {
lua_tolstring(L, i, ptr::null_mut())
+8
View File
@@ -424,6 +424,14 @@ pub unsafe fn lua_pushglobaltable(L: *mut lua_State) -> c_int {
lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS)
}
#[inline(always)]
pub unsafe fn lua_tolightuserdata(L: *mut lua_State, idx: c_int) -> *mut c_void {
if lua_islightuserdata(L, idx) != 0 {
return lua_touserdata(L, idx);
}
ptr::null_mut()
}
#[inline(always)]
pub unsafe fn lua_tostring(L: *mut lua_State, i: c_int) -> *const c_char {
lua_tolstring(L, i, ptr::null_mut())
+8
View File
@@ -457,6 +457,14 @@ pub unsafe fn lua_pushglobaltable(L: *mut lua_State) -> c_int {
lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS)
}
#[inline(always)]
pub unsafe fn lua_tolightuserdata(L: *mut lua_State, idx: c_int) -> *mut c_void {
if lua_islightuserdata(L, idx) != 0 {
return lua_touserdata(L, idx);
}
ptr::null_mut()
}
#[inline(always)]
pub unsafe fn lua_tostring(L: *mut lua_State, i: c_int) -> *const c_char {
lua_tolstring(L, i, ptr::null_mut())
+6 -3
View File
@@ -144,9 +144,12 @@ pub unsafe fn luaL_sandbox(L: *mut lua_State, enabled: c_int) {
// set all builtin metatables to read-only
lua_pushliteral(L, "");
lua_getmetatable(L, -1);
lua_setreadonly(L, -1, enabled);
lua_pop(L, 2);
if lua_getmetatable(L, -1) != 0 {
lua_setreadonly(L, -1, enabled);
lua_pop(L, 2);
} else {
lua_pop(L, 1);
}
// set globals to readonly and activate safeenv since the env is immutable
lua_setreadonly(L, LUA_GLOBALSINDEX, enabled);
+21 -2
View File
@@ -8,7 +8,13 @@ use std::{mem, ptr};
pub const LUA_MULTRET: c_int = -1;
// Max number of Lua stack slots
const LUAI_MAXCSTACK: c_int = 100000;
const LUAI_MAXCSTACK: c_int = 1000000;
// Number of valid Lua userdata tags
const LUA_UTAG_LIMIT: c_int = 128;
// Number of valid Lua lightuserdata tags
const LUA_LUTAG_LIMIT: c_int = 128;
//
// Pseudo-indices
@@ -144,9 +150,11 @@ extern "C-unwind" {
pub fn lua_objlen(L: *mut lua_State, idx: c_int) -> usize;
pub fn lua_tocfunction(L: *mut lua_State, idx: c_int) -> Option<lua_CFunction>;
pub fn lua_tolightuserdata(L: *mut lua_State, idx: c_int) -> *mut c_void;
pub fn lua_tolightuserdatatagged(L: *mut lua_State, idx: c_int, tag: c_int) -> *mut c_void;
pub fn lua_touserdata(L: *mut lua_State, idx: c_int) -> *mut c_void;
pub fn lua_touserdatatagged(L: *mut lua_State, idx: c_int, tag: c_int) -> *mut c_void;
pub fn lua_userdatatag(L: *mut lua_State, idx: c_int) -> c_int;
pub fn lua_lightuserdatatag(L: *mut lua_State, idx: c_int) -> c_int;
pub fn lua_tothread(L: *mut lua_State, idx: c_int) -> *mut lua_State;
pub fn lua_tobuffer(L: *mut lua_State, idx: c_int, len: *mut usize) -> *mut c_void;
pub fn lua_topointer(L: *mut lua_State, idx: c_int) -> *const c_void;
@@ -179,7 +187,7 @@ extern "C-unwind" {
pub fn lua_pushboolean(L: *mut lua_State, b: c_int);
pub fn lua_pushthread(L: *mut lua_State) -> c_int;
pub fn lua_pushlightuserdata(L: *mut lua_State, p: *mut c_void);
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_newuserdatadtor(L: *mut lua_State, sz: usize, dtor: lua_Udestructor) -> *mut c_void;
@@ -280,6 +288,8 @@ 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_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;
pub fn lua_clonefunction(L: *mut lua_State, idx: c_int);
pub fn lua_cleartable(L: *mut lua_State, idx: c_int);
pub fn lua_getallocf(L: *mut lua_State, ud: *mut *mut c_void) -> lua_Alloc;
@@ -398,18 +408,22 @@ pub unsafe fn lua_pushliteral(L: *mut lua_State, s: &'static str) {
lua_pushlstring_(L, c_str.as_ptr(), c_str.as_bytes().len())
}
#[inline(always)]
pub unsafe fn lua_pushcfunction(L: *mut lua_State, f: lua_CFunction) {
lua_pushcclosurek(L, f, ptr::null(), 0, None)
}
#[inline(always)]
pub unsafe fn lua_pushcfunctiond(L: *mut lua_State, f: lua_CFunction, debugname: *const c_char) {
lua_pushcclosurek(L, f, debugname, 0, None)
}
#[inline(always)]
pub unsafe fn lua_pushcclosure(L: *mut lua_State, f: lua_CFunction, nup: c_int) {
lua_pushcclosurek(L, f, ptr::null(), nup, None)
}
#[inline(always)]
pub unsafe fn lua_pushcclosured(
L: *mut lua_State,
f: lua_CFunction,
@@ -419,6 +433,11 @@ pub unsafe fn lua_pushcclosured(
lua_pushcclosurek(L, f, debugname, nup, None)
}
#[inline(always)]
pub unsafe fn lua_pushlightuserdata(L: *mut lua_State, p: *mut c_void) {
lua_pushlightuserdatatagged(L, p, 0)
}
#[inline(always)]
pub unsafe fn lua_setglobal(L: *mut lua_State, var: *const c_char) {
lua_setfield(L, LUA_GLOBALSINDEX, var)
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "mlua_derive"
version = "0.9.1"
version = "0.9.2"
authors = ["Aleksandr Orlenko <zxteam@pm.me>"]
edition = "2021"
description = "Procedural macros for the mlua crate."
@@ -19,6 +19,6 @@ quote = "1.0"
proc-macro2 = { version = "1.0", features = ["span-locations"] }
proc-macro-error = { version = "1.0", optional = true }
syn = { version = "2.0", features = ["full"] }
itertools = { version = "0.11", optional = true }
itertools = { version = "0.12", optional = true }
regex = { version = "1.4", optional = true }
once_cell = { version = "1.0", optional = true }
+4 -3
View File
@@ -7,16 +7,17 @@ pub fn from_lua(input: TokenStream) -> TokenStream {
ident, generics, ..
} = parse_macro_input!(input as DeriveInput);
let ident_str = ident.to_string();
let (impl_generics, ty_generics, _) = generics.split_for_impl();
let where_clause = match &generics.where_clause {
Some(where_clause) => quote! { #where_clause, Self: 'static + Clone },
None => quote! { where Self: 'static + Clone },
};
let ident_str = ident.to_string();
quote! {
impl #generics ::mlua::FromLua<'_> for #ident #generics #where_clause {
impl #impl_generics ::mlua::FromLua<'_> for #ident #ty_generics #where_clause {
#[inline]
fn from_lua(value: ::mlua::Value<'_>, lua: &'_ ::mlua::Lua) -> ::mlua::Result<Self> {
fn from_lua(value: ::mlua::Value<'_>, _: &'_ ::mlua::Lua) -> ::mlua::Result<Self> {
match value {
::mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()),
_ => Err(::mlua::Error::FromLuaConversionError {
+230 -2
View File
@@ -16,12 +16,15 @@ use crate::lua::Lua;
use crate::string::String;
use crate::table::Table;
use crate::thread::Thread;
use crate::types::{LightUserData, MaybeSend};
use crate::types::{LightUserData, MaybeSend, RegistryKey};
use crate::userdata::{AnyUserData, UserData, UserDataRef, UserDataRefMut};
use crate::value::{FromLua, IntoLua, Nil, Value};
#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
use crate::{function::OwnedFunction, table::OwnedTable, userdata::OwnedAnyUserData};
use crate::{
function::OwnedFunction, string::OwnedString, table::OwnedTable, thread::OwnedThread,
userdata::OwnedAnyUserData,
};
impl<'lua> IntoLua<'lua> for Value<'lua> {
#[inline]
@@ -30,6 +33,18 @@ impl<'lua> IntoLua<'lua> for Value<'lua> {
}
}
impl<'lua> IntoLua<'lua> for &Value<'lua> {
#[inline]
fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
Ok(self.clone())
}
#[inline]
unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
lua.push_value_ref(self)
}
}
impl<'lua> FromLua<'lua> for Value<'lua> {
#[inline]
fn from_lua(lua_value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
@@ -44,6 +59,18 @@ impl<'lua> IntoLua<'lua> for String<'lua> {
}
}
impl<'lua> IntoLua<'lua> for &String<'lua> {
#[inline]
fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
Ok(Value::String(self.clone()))
}
#[inline]
unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
Ok(lua.push_ref(&self.0))
}
}
impl<'lua> FromLua<'lua> for String<'lua> {
#[inline]
fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<String<'lua>> {
@@ -57,6 +84,38 @@ impl<'lua> FromLua<'lua> for String<'lua> {
}
}
#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
impl<'lua> IntoLua<'lua> for OwnedString {
#[inline]
fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
Ok(Value::String(String(lua.adopt_owned_ref(self.0))))
}
}
#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
impl<'lua> IntoLua<'lua> for &OwnedString {
#[inline]
fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
OwnedString::into_lua(self.clone(), lua)
}
#[inline]
unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
Ok(lua.push_owned_ref(&self.0))
}
}
#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
impl<'lua> FromLua<'lua> for OwnedString {
#[inline]
fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<OwnedString> {
String::from_lua(value, lua).map(|s| s.into_owned())
}
}
impl<'lua> IntoLua<'lua> for Table<'lua> {
#[inline]
fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
@@ -64,6 +123,18 @@ impl<'lua> IntoLua<'lua> for Table<'lua> {
}
}
impl<'lua> IntoLua<'lua> for &Table<'lua> {
#[inline]
fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
Ok(Value::Table(self.clone()))
}
#[inline]
unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
Ok(lua.push_ref(&self.0))
}
}
impl<'lua> FromLua<'lua> for Table<'lua> {
#[inline]
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Table<'lua>> {
@@ -87,6 +158,20 @@ impl<'lua> IntoLua<'lua> for OwnedTable {
}
}
#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
impl<'lua> IntoLua<'lua> for &OwnedTable {
#[inline]
fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
OwnedTable::into_lua(self.clone(), lua)
}
#[inline]
unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
Ok(lua.push_owned_ref(&self.0))
}
}
#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
impl<'lua> FromLua<'lua> for OwnedTable {
@@ -103,6 +188,18 @@ impl<'lua> IntoLua<'lua> for Function<'lua> {
}
}
impl<'lua> IntoLua<'lua> for &Function<'lua> {
#[inline]
fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
Ok(Value::Function(self.clone()))
}
#[inline]
unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
Ok(lua.push_ref(&self.0))
}
}
impl<'lua> FromLua<'lua> for Function<'lua> {
#[inline]
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Function<'lua>> {
@@ -126,6 +223,20 @@ impl<'lua> IntoLua<'lua> for OwnedFunction {
}
}
#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
impl<'lua> IntoLua<'lua> for &OwnedFunction {
#[inline]
fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
OwnedFunction::into_lua(self.clone(), lua)
}
#[inline]
unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
Ok(lua.push_owned_ref(&self.0))
}
}
#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
impl<'lua> FromLua<'lua> for OwnedFunction {
@@ -142,6 +253,18 @@ impl<'lua> IntoLua<'lua> for Thread<'lua> {
}
}
impl<'lua> IntoLua<'lua> for &Thread<'lua> {
#[inline]
fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
Ok(Value::Thread(self.clone()))
}
#[inline]
unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
Ok(lua.push_ref(&self.0))
}
}
impl<'lua> FromLua<'lua> for Thread<'lua> {
#[inline]
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Thread<'lua>> {
@@ -156,6 +279,38 @@ impl<'lua> FromLua<'lua> for Thread<'lua> {
}
}
#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
impl<'lua> IntoLua<'lua> for OwnedThread {
#[inline]
fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
Ok(Value::Thread(Thread(lua.adopt_owned_ref(self.0), self.1)))
}
}
#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
impl<'lua> IntoLua<'lua> for &OwnedThread {
#[inline]
fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
OwnedThread::into_lua(self.clone(), lua)
}
#[inline]
unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
Ok(lua.push_owned_ref(&self.0))
}
}
#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
impl<'lua> FromLua<'lua> for OwnedThread {
#[inline]
fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<OwnedThread> {
Thread::from_lua(value, lua).map(|s| s.into_owned())
}
}
impl<'lua> IntoLua<'lua> for AnyUserData<'lua> {
#[inline]
fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
@@ -163,6 +318,18 @@ impl<'lua> IntoLua<'lua> for AnyUserData<'lua> {
}
}
impl<'lua> IntoLua<'lua> for &AnyUserData<'lua> {
#[inline]
fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
Ok(Value::UserData(self.clone()))
}
#[inline]
unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
Ok(lua.push_ref(&self.0))
}
}
impl<'lua> FromLua<'lua> for AnyUserData<'lua> {
#[inline]
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<AnyUserData<'lua>> {
@@ -189,6 +356,20 @@ impl<'lua> IntoLua<'lua> for OwnedAnyUserData {
}
}
#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
impl<'lua> IntoLua<'lua> for &OwnedAnyUserData {
#[inline]
fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
OwnedAnyUserData::into_lua(self.clone(), lua)
}
#[inline]
unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
Ok(lua.push_owned_ref(&self.0))
}
}
#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
impl<'lua> FromLua<'lua> for OwnedAnyUserData {
@@ -240,11 +421,44 @@ impl<'lua> FromLua<'lua> for Error {
}
}
impl<'lua> IntoLua<'lua> for &RegistryKey {
#[inline]
fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
lua.registry_value(self)
}
unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
if !lua.owns_registry_value(self) {
return Err(Error::MismatchedRegistryKey);
}
if self.is_nil() {
ffi::lua_pushnil(lua.state());
} else {
ffi::lua_rawgeti(lua.state(), ffi::LUA_REGISTRYINDEX, self.registry_id as _);
}
Ok(())
}
}
impl<'lua> FromLua<'lua> for RegistryKey {
#[inline]
fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<RegistryKey> {
lua.create_registry_value(value)
}
}
impl<'lua> IntoLua<'lua> for bool {
#[inline]
fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
Ok(Value::Boolean(self))
}
#[inline]
unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
ffi::lua_pushboolean(lua.state(), self as c_int);
Ok(())
}
}
impl<'lua> FromLua<'lua> for bool {
@@ -256,6 +470,11 @@ impl<'lua> FromLua<'lua> for bool {
_ => Ok(true),
}
}
#[inline]
unsafe fn from_stack(idx: c_int, lua: &'lua Lua) -> Result<Self> {
Ok(ffi::lua_toboolean(lua.state(), idx) != 0)
}
}
impl<'lua> IntoLua<'lua> for LightUserData {
@@ -497,6 +716,15 @@ macro_rules! lua_convert_int {
message: Some("out of range".to_owned()),
})
}
#[inline]
unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
match cast(self) {
Some(i) => ffi::lua_pushinteger(lua.state(), i),
None => ffi::lua_pushnumber(lua.state(), self as ffi::lua_Number),
}
Ok(())
}
}
impl<'lua> FromLua<'lua> for $x {
+10
View File
@@ -494,6 +494,16 @@ impl<'lua> Function<'lua> {
}
}
/// Converts this function to a generic C pointer.
///
/// There is no way to convert the pointer back to its original value.
///
/// Typically this function is used only for hashing and debug information.
#[inline]
pub fn to_pointer(&self) -> *const c_void {
self.0.to_pointer()
}
/// Convert this handle to owned version.
#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
+64 -60
View File
@@ -226,6 +226,7 @@ pub(crate) static EXTRA_REGISTRY_KEY: u8 = 0;
const WRAPPED_FAILURE_POOL_SIZE: usize = 64;
const MULTIVALUE_POOL_SIZE: usize = 64;
const REF_STACK_RESERVE: c_int = 1;
/// Requires `feature = "send"`
#[cfg(feature = "send")]
@@ -519,8 +520,8 @@ impl Lua {
#[cfg(feature = "module")]
skip_memory_check: false,
ref_thread,
// We need 1 extra stack space to move values in and out of the ref stack.
ref_stack_size: ffi::LUA_MINSTACK - 1,
// We need some reserved stack space to move values in and out of the ref stack.
ref_stack_size: ffi::LUA_MINSTACK - REF_STACK_RESERVE,
ref_stack_top: ffi::lua_gettop(ref_thread),
ref_free: Vec::new(),
wrapped_failure_pool: Vec::with_capacity(WRAPPED_FAILURE_POOL_SIZE),
@@ -1413,8 +1414,8 @@ impl Lua {
let protect = !self.unlikely_memory_error();
push_table(state, 0, lower_bound, protect)?;
for (k, v) in iter {
self.push_value(k.into_lua(self)?)?;
self.push_value(v.into_lua(self)?)?;
self.push(k)?;
self.push(v)?;
if protect {
protect_lua!(state, 3, 1, fn(state) ffi::lua_rawset(state, -3))?;
} else {
@@ -1442,7 +1443,7 @@ impl Lua {
let protect = !self.unlikely_memory_error();
push_table(state, lower_bound, 0, protect)?;
for (i, v) in iter.enumerate() {
self.push_value(v.into_lua(self)?)?;
self.push(v)?;
if protect {
protect_lua!(state, 2, 1, |state| {
ffi::lua_rawseti(state, -2, (i + 1) as Integer);
@@ -1977,12 +1978,11 @@ impl Lua {
T: IntoLua<'lua>,
{
let state = self.state();
let t = t.into_lua(self)?;
unsafe {
let _sg = StackGuard::new(state);
check_stack(state, 5)?;
self.push_value(t)?;
self.push(t)?;
rawset_field(state, ffi::LUA_REGISTRYINDEX, name)
}
}
@@ -2269,33 +2269,38 @@ impl Lua {
extra.app_data.remove()
}
/// Pushes a value onto the Lua stack.
/// Pushes a value that implements `IntoLua` onto the Lua stack.
///
/// Uses 2 stack spaces, does not call checkstack.
#[doc(hidden)]
#[inline(always)]
pub unsafe fn push<'lua>(&'lua self, value: impl IntoLua<'lua>) -> Result<()> {
value.push_into_stack(self)
}
/// Pushes a `Value` onto the Lua stack.
///
/// Uses 2 stack spaces, does not call checkstack.
#[doc(hidden)]
pub unsafe fn push_value(&self, value: Value) -> Result<()> {
if let Value::Error(err) = value {
let protect = !self.unlikely_memory_error();
return push_gc_userdata(self.state(), WrappedFailure::Error(err), protect);
}
self.push_value_ref(&value)
}
/// Pushes a `&Value` (by reference) onto the Lua stack.
///
/// Similar to [`Lua::push_value`], uses 2 stack spaces, does not call checkstack.
pub(crate) unsafe fn push_value_ref(&self, value: &Value) -> Result<()> {
let state = self.state();
match value {
Value::Nil => {
ffi::lua_pushnil(state);
}
Value::Boolean(b) => {
ffi::lua_pushboolean(state, b as c_int);
}
Value::LightUserData(ud) => {
ffi::lua_pushlightuserdata(state, ud.0);
}
Value::Integer(i) => {
ffi::lua_pushinteger(state, i);
}
Value::Number(n) => {
ffi::lua_pushnumber(state, n);
}
Value::Nil => ffi::lua_pushnil(state),
Value::Boolean(b) => ffi::lua_pushboolean(state, *b as c_int),
Value::LightUserData(ud) => ffi::lua_pushlightuserdata(state, ud.0),
Value::Integer(i) => ffi::lua_pushinteger(state, *i),
Value::Number(n) => ffi::lua_pushnumber(state, *n),
#[cfg(feature = "luau")]
Value::Vector(v) => {
#[cfg(not(feature = "luau-vector4"))]
@@ -2303,33 +2308,16 @@ impl Lua {
#[cfg(feature = "luau-vector4")]
ffi::lua_pushvector(state, v.x(), v.y(), v.z(), v.w());
}
Value::String(s) => {
self.push_ref(&s.0);
}
Value::Table(t) => {
self.push_ref(&t.0);
}
Value::Function(f) => {
self.push_ref(&f.0);
}
Value::Thread(t) => {
self.push_ref(&t.0);
}
Value::UserData(ud) => {
self.push_ref(&ud.0);
}
Value::String(s) => self.push_ref(&s.0),
Value::Table(t) => self.push_ref(&t.0),
Value::Function(f) => self.push_ref(&f.0),
Value::Thread(t) => self.push_ref(&t.0),
Value::UserData(ud) => self.push_ref(&ud.0),
Value::Error(err) => {
let protect = !self.unlikely_memory_error();
push_gc_userdata(state, WrappedFailure::Error(err), protect)?;
push_gc_userdata(state, WrappedFailure::Error(err.clone()), protect)?;
}
}
Ok(())
}
@@ -2558,6 +2546,15 @@ impl Lua {
ffi::lua_xpush(self.ref_thread(), self.state(), lref.index);
}
#[cfg(all(feature = "unstable", not(feature = "send")))]
pub(crate) unsafe fn push_owned_ref(&self, loref: &crate::types::LuaOwnedRef) {
assert!(
Arc::ptr_eq(&loref.inner, &self.0),
"Lua instance passed Value created from a different main Lua state"
);
ffi::lua_xpush(self.ref_thread(), self.state(), loref.index);
}
// Pops the topmost element of the stack and stores a reference to it. This pins the object,
// preventing garbage collection until the returned `LuaRef` is dropped.
//
@@ -2634,12 +2631,12 @@ impl Lua {
let metatable_nrec = metatable_nrec + registry.async_meta_methods.len();
push_table(state, 0, metatable_nrec, true)?;
for (k, m) in registry.meta_methods {
self.push_value(Value::Function(self.create_callback(m)?))?;
self.push(self.create_callback(m)?)?;
rawset_field(state, -2, MetaMethod::validate(&k)?)?;
}
#[cfg(feature = "async")]
for (k, m) in registry.async_meta_methods {
self.push_value(Value::Function(self.create_async_callback(m)?))?;
self.push(self.create_async_callback(m)?)?;
rawset_field(state, -2, MetaMethod::validate(&k)?)?;
}
let mut has_name = false;
@@ -2690,7 +2687,7 @@ impl Lua {
if field_getters_nrec > 0 {
push_table(state, 0, field_getters_nrec, true)?;
for (k, m) in registry.field_getters {
self.push_value(Value::Function(self.create_callback(m)?))?;
self.push(self.create_callback(m)?)?;
rawset_field(state, -2, &k)?;
}
field_getters_index = Some(ffi::lua_absindex(state, -1));
@@ -2702,7 +2699,7 @@ impl Lua {
if field_setters_nrec > 0 {
push_table(state, 0, field_setters_nrec, true)?;
for (k, m) in registry.field_setters {
self.push_value(Value::Function(self.create_callback(m)?))?;
self.push(self.create_callback(m)?)?;
rawset_field(state, -2, &k)?;
}
field_setters_index = Some(ffi::lua_absindex(state, -1));
@@ -2725,12 +2722,12 @@ impl Lua {
}
}
for (k, m) in registry.methods {
self.push_value(Value::Function(self.create_callback(m)?))?;
self.push(self.create_callback(m)?)?;
rawset_field(state, -2, &k)?;
}
#[cfg(feature = "async")]
for (k, m) in registry.async_methods {
self.push_value(Value::Function(self.create_async_callback(m)?))?;
self.push(self.create_async_callback(m)?)?;
rawset_field(state, -2, &k)?;
}
match index_type {
@@ -2965,8 +2962,7 @@ impl Lua {
match fut.as_mut().poll(&mut ctx) {
Poll::Pending => {
ffi::lua_pushnil(state);
let pending = &ASYNC_POLL_PENDING as *const u8 as *mut c_void;
ffi::lua_pushlightuserdata(state, pending);
ffi::lua_pushlightuserdata(state, Lua::poll_pending().0);
Ok(2)
}
Poll::Ready(nresults) => {
@@ -2982,7 +2978,7 @@ impl Lua {
nresults => {
let results = MultiValue::from_stack_multi(nresults, lua)?;
ffi::lua_pushinteger(state, nresults as _);
lua.push_value(Value::Table(lua.create_sequence_from(results)?))?;
lua.push(lua.create_sequence_from(results)?)?;
Ok(2)
}
}
@@ -3069,6 +3065,14 @@ impl Lua {
mem::replace(&mut (*self.extra.get()).waker, waker)
}
/// Returns internal `Poll::Pending` constant used for executing async callbacks.
#[cfg(feature = "async")]
#[doc(hidden)]
#[inline]
pub fn poll_pending() -> LightUserData {
LightUserData(&ASYNC_POLL_PENDING as *const u8 as *mut c_void)
}
pub(crate) unsafe fn make_userdata<T>(&self, data: UserDataCell<T>) -> Result<AnyUserData>
where
T: UserData + 'static,
+28
View File
@@ -23,6 +23,20 @@ impl<'lua, T: IntoLua<'lua>, E: IntoLua<'lua>> IntoLuaMulti<'lua> for StdResult<
}
Ok(result)
}
#[inline]
unsafe fn push_into_stack_multi(self, lua: &'lua Lua) -> Result<c_int> {
match self {
Ok(v) => v.push_into_stack(lua).map(|_| 1),
Err(e) => {
let state = lua.state();
check_stack(state, 3)?;
ffi::lua_pushnil(state);
e.push_into_stack(lua)?;
Ok(2)
}
}
}
}
impl<'lua, E: IntoLua<'lua>> IntoLuaMulti<'lua> for StdResult<(), E> {
@@ -38,6 +52,20 @@ impl<'lua, E: IntoLua<'lua>> IntoLuaMulti<'lua> for StdResult<(), E> {
}
}
}
#[inline]
unsafe fn push_into_stack_multi(self, lua: &'lua Lua) -> Result<c_int> {
match self {
Ok(_) => Ok(0),
Err(e) => {
let state = lua.state();
check_stack(state, 3)?;
ffi::lua_pushnil(state);
e.push_into_stack(lua)?;
Ok(2)
}
}
}
}
impl<'lua, T: IntoLua<'lua>> IntoLuaMulti<'lua> for T {
+5 -5
View File
@@ -19,7 +19,7 @@ use crate::util::{
self, assert_stack, check_stack, init_userdata_metatable, push_string, push_table,
rawset_field, short_type_name, take_userdata, StackGuard,
};
use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, Value};
use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti};
#[cfg(feature = "lua54")]
use crate::userdata::USER_VALUE_MAXSLOT;
@@ -405,7 +405,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
let meta_methods_nrec = registry.meta_methods.len() + registry.meta_fields.len() + 1;
push_table(state, 0, meta_methods_nrec, true)?;
for (k, m) in registry.meta_methods {
lua.push_value(Value::Function(wrap_method(self, ud_ptr, &k, m)?))?;
lua.push(wrap_method(self, ud_ptr, &k, m)?)?;
rawset_field(state, -2, MetaMethod::validate(&k)?)?;
}
let mut has_name = false;
@@ -455,7 +455,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
if field_getters_nrec > 0 {
push_table(state, 0, field_getters_nrec, true)?;
for (k, m) in registry.field_getters {
lua.push_value(Value::Function(wrap_method(self, ud_ptr, &k, m)?))?;
lua.push(wrap_method(self, ud_ptr, &k, m)?)?;
rawset_field(state, -2, &k)?;
}
field_getters_index = Some(ffi::lua_absindex(state, -1));
@@ -466,7 +466,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
if field_setters_nrec > 0 {
push_table(state, 0, field_setters_nrec, true)?;
for (k, m) in registry.field_setters {
lua.push_value(Value::Function(wrap_method(self, ud_ptr, &k, m)?))?;
lua.push(wrap_method(self, ud_ptr, &k, m)?)?;
rawset_field(state, -2, &k)?;
}
field_setters_index = Some(ffi::lua_absindex(state, -1));
@@ -478,7 +478,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
// Create table used for methods lookup
push_table(state, 0, methods_nrec, true)?;
for (k, m) in registry.methods {
lua.push_value(Value::Function(wrap_method(self, ud_ptr, &k, m)?))?;
lua.push(wrap_method(self, ud_ptr, &k, m)?)?;
rawset_field(state, -2, &k)?;
}
methods_index = Some(ffi::lua_absindex(state, -1));
+1 -1
View File
@@ -132,7 +132,7 @@ impl<'lua> String<'lua> {
}
}
/// Converts the string to a generic C pointer.
/// Converts this string to a generic C pointer.
///
/// There is no way to convert the pointer back to its original value.
///
+42 -33
View File
@@ -591,7 +591,7 @@ impl<'lua> Table<'lua> {
unsafe { ffi::lua_getreadonly(ref_thread, self.0.index) != 0 }
}
/// Converts the table to a generic C pointer.
/// Converts this table to a generic C pointer.
///
/// Different tables will give different pointers.
/// There is no way to convert the pointer back to its original value.
@@ -721,7 +721,6 @@ impl<'lua> Table<'lua> {
TableSequence {
table: self.0,
index: 1,
len: None,
_phantom: PhantomData,
}
}
@@ -733,17 +732,25 @@ impl<'lua> Table<'lua> {
}
#[cfg(feature = "serialize")]
pub(crate) fn sequence_values_by_len<V: FromLua<'lua>>(
self,
len: Option<usize>,
) -> TableSequence<'lua, V> {
let len = len.unwrap_or_else(|| self.raw_len()) as Integer;
TableSequence {
table: self.0,
index: 1,
len: Some(len),
_phantom: PhantomData,
pub(crate) fn for_each_value<V>(&self, mut f: impl FnMut(V) -> Result<()>) -> Result<()>
where
V: FromLua<'lua>,
{
let lua = self.0.lua;
let state = lua.state();
unsafe {
let _sg = StackGuard::new(state);
check_stack(state, 4)?;
lua.push_ref(&self.0);
let len = ffi::lua_rawlen(state, -1);
for i in 1..=len {
ffi::lua_rawgeti(state, -1, i as _);
f(V::from_stack(-1, lua)?)?;
ffi::lua_pop(state, 1);
}
}
Ok(())
}
/// Sets element value at position `idx` without invoking metamethods.
@@ -1085,6 +1092,13 @@ impl<'a, 'lua> Serialize for SerializableTable<'a, 'lua> {
use crate::serde::de::{check_value_for_skip, MapPairs};
use crate::value::SerializableValue;
let convert_result = |res: Result<()>, serialize_err: Option<S::Error>| match res {
Ok(v) => Ok(v),
Err(Error::SerializeError(_)) if serialize_err.is_some() => Err(serialize_err.unwrap()),
Err(Error::SerializeError(msg)) => Err(serde::ser::Error::custom(msg)),
Err(err) => Err(serde::ser::Error::custom(err.to_string())),
};
let options = self.options;
let visited = &self.visited;
visited.borrow_mut().insert(self.table.to_pointer());
@@ -1093,15 +1107,21 @@ impl<'a, 'lua> Serialize for SerializableTable<'a, 'lua> {
let len = self.table.raw_len();
if len > 0 || self.table.is_array() {
let mut seq = serializer.serialize_seq(Some(len))?;
for value in self.table.clone().sequence_values_by_len::<Value>(None) {
let value = &value.map_err(serde::ser::Error::custom)?;
let skip = check_value_for_skip(value, self.options, &self.visited)
.map_err(serde::ser::Error::custom)?;
let mut serialize_err = None;
let res = self.table.for_each_value::<Value>(|value| {
let skip = check_value_for_skip(&value, self.options, &self.visited)
.map_err(|err| Error::SerializeError(err.to_string()))?;
if skip {
continue;
// continue iteration
return Ok(());
}
seq.serialize_element(&SerializableValue::new(value, options, Some(visited)))?;
}
seq.serialize_element(&SerializableValue::new(&value, options, Some(visited)))
.map_err(|err| {
serialize_err = Some(err);
Error::SerializeError(String::new())
})
});
convert_result(res, serialize_err)?;
return seq.end();
}
@@ -1138,18 +1158,7 @@ impl<'a, 'lua> Serialize for SerializableTable<'a, 'lua> {
process_pair(key, value)
})
};
match res {
Ok(_) => {}
Err(Error::SerializeError(_)) if serialize_err.is_some() => {
return Err(serialize_err.unwrap());
}
Err(Error::SerializeError(msg)) => {
return Err(serde::ser::Error::custom(msg));
}
Err(err) => {
return Err(serde::ser::Error::custom(err.to_string()));
}
}
convert_result(res, serialize_err)?;
map.end()
}
}
@@ -1219,9 +1228,9 @@ where
///
/// [`Table::sequence_values`]: crate::Table::sequence_values
pub struct TableSequence<'lua, V> {
// TODO: Use `&Table`
table: LuaRef<'lua>,
index: Integer,
len: Option<Integer>,
_phantom: PhantomData<V>,
}
@@ -1242,7 +1251,7 @@ where
lua.push_ref(&self.table);
match ffi::lua_rawgeti(state, -1, self.index) {
ffi::LUA_TNIL if self.index > self.len.unwrap_or(0) => None,
ffi::LUA_TNIL => None,
_ => {
self.index += 1;
Some(V::from_stack(-1, lua))
+13 -8
View File
@@ -1,4 +1,4 @@
use std::os::raw::c_int;
use std::os::raw::{c_int, c_void};
use crate::error::{Error, Result};
#[allow(unused)]
@@ -15,7 +15,7 @@ use crate::{
#[cfg(feature = "async")]
use {
crate::{lua::ASYNC_POLL_PENDING, value::MultiValue},
crate::value::MultiValue,
futures_util::stream::Stream,
std::{
future::Future,
@@ -375,6 +375,16 @@ impl<'lua> Thread<'lua> {
}
}
/// Converts this thread to a generic C pointer.
///
/// There is no way to convert the pointer back to its original value.
///
/// Typically this function is used only for hashing and debug information.
#[inline]
pub fn to_pointer(&self) -> *const c_void {
self.0.to_pointer()
}
/// Convert this handle to owned version.
#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
@@ -530,12 +540,7 @@ where
#[cfg(feature = "async")]
#[inline(always)]
unsafe fn is_poll_pending(state: *mut ffi::lua_State) -> bool {
if ffi::lua_islightuserdata(state, -1) != 0 {
let stack_ptr = ffi::lua_touserdata(state, -1) as *const u8;
let pending_ptr = &ASYNC_POLL_PENDING as *const u8;
return std::ptr::eq(stack_ptr, pending_ptr);
}
false
ffi::lua_tolightuserdata(state, -1) == Lua::poll_pending().0
}
#[cfg(feature = "async")]
+13 -3
View File
@@ -5,7 +5,7 @@ use std::fmt;
use std::hash::Hash;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::os::raw::{c_char, c_int};
use std::os::raw::{c_char, c_int, c_void};
use std::string::String as StdString;
#[cfg(feature = "async")]
@@ -919,7 +919,7 @@ impl<'lua> AnyUserData<'lua> {
check_stack(state, 5)?;
lua.push_userdata_ref(&self.0)?;
lua.push_value(v.into_lua(lua)?)?;
lua.push(v)?;
#[cfg(feature = "lua54")]
if n < USER_VALUE_MAXSLOT {
@@ -1014,7 +1014,7 @@ impl<'lua> AnyUserData<'lua> {
check_stack(state, 5)?;
lua.push_userdata_ref(&self.0)?;
lua.push_value(v.into_lua(lua)?)?;
lua.push(v)?;
// Multiple (extra) user values are emulated by storing them in a table
protect_lua!(state, 2, 0, |state| {
@@ -1096,6 +1096,16 @@ impl<'lua> AnyUserData<'lua> {
}
}
/// Converts this userdata to a generic C pointer.
///
/// There is no way to convert the pointer back to its original value.
///
/// Typically this function is used only for hashing and debug information.
#[inline]
pub fn to_pointer(&self) -> *const c_void {
self.0.to_pointer()
}
/// Convert this handle to owned version.
#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
+2
View File
@@ -1045,6 +1045,8 @@ pub(crate) unsafe fn to_string(state: *mut ffi::lua_State, index: c_int) -> Stri
ffi::LUA_TTHREAD => format!("<thread {:?}>", ffi::lua_topointer(state, index)),
#[cfg(feature = "luau")]
ffi::LUA_TBUFFER => format!("<buffer {:?}>", ffi::lua_topointer(state, index)),
#[cfg(feature = "luajit")]
ffi::LUA_TCDATA => format!("<cdata {:?}>", ffi::lua_topointer(state, index)),
_ => "<unknown>".to_string(),
}
}
+1 -1
View File
@@ -443,7 +443,7 @@ async fn test_async_userdata() -> Result<()> {
let globals = lua.globals();
let userdata = lua.create_userdata(MyUserData(11))?;
globals.set("userdata", userdata.clone())?;
globals.set("userdata", &userdata)?;
lua.load(
r#"
@@ -4,7 +4,7 @@ error: lifetime may not live long enough
9 | reg.add_async_method("t", |_, this: &String, ()| async {
| ___________________________________----------------------_^
| | | |
| | | return type of closure `[async block@$DIR/tests/compile/async_any_userdata_method.rs:9:58: 12:10]` contains a lifetime `'2`
| | | return type of closure `{async block@$DIR/tests/compile/async_any_userdata_method.rs:9:58: 12:10}` contains a lifetime `'2`
| | lifetime `'1` represents this closure's body
10 | | s = this;
11 | | Ok(())
@@ -27,6 +27,8 @@ error[E0596]: cannot borrow `s` as mutable, as it is a captured variable in a `F
error[E0597]: `s` does not live long enough
--> tests/compile/async_any_userdata_method.rs:8:21
|
7 | let s = String::new();
| - binding `s` declared here
8 | let mut s = &s;
| ^^ borrowed value does not live long enough
9 | / reg.add_async_method("t", |_, this: &String, ()| async {
+40 -8
View File
@@ -7,14 +7,46 @@ error[E0277]: the type `UnsafeCell<mlua::lua::ExtraData>` may contain interior m
| required by a bound introduced by this call
|
= help: within `Lua`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<mlua::lua::ExtraData>`
= note: required because it appears within the type `ArcInner<UnsafeCell<ExtraData>>`
= note: required because it appears within the type `PhantomData<ArcInner<UnsafeCell<ExtraData>>>`
= note: required because it appears within the type `Arc<UnsafeCell<ExtraData>>`
= note: required because it appears within the type `LuaInner`
= note: required because it appears within the type `ArcInner<LuaInner>`
= note: required because it appears within the type `PhantomData<ArcInner<LuaInner>>`
= note: required because it appears within the type `Arc<LuaInner>`
= note: required because it appears within the type `Lua`
note: required because it appears within the type `ArcInner<UnsafeCell<ExtraData>>`
--> $RUST/alloc/src/sync.rs
|
| struct ArcInner<T: ?Sized> {
| ^^^^^^^^
note: required because it appears within the type `PhantomData<ArcInner<UnsafeCell<ExtraData>>>`
--> $RUST/core/src/marker.rs
|
| pub struct PhantomData<T: ?Sized>;
| ^^^^^^^^^^^
note: required because it appears within the type `Arc<UnsafeCell<ExtraData>>`
--> $RUST/alloc/src/sync.rs
|
| pub struct Arc<
| ^^^
note: required because it appears within the type `LuaInner`
--> src/lua.rs
|
| pub struct LuaInner {
| ^^^^^^^^
note: required because it appears within the type `ArcInner<LuaInner>`
--> $RUST/alloc/src/sync.rs
|
| struct ArcInner<T: ?Sized> {
| ^^^^^^^^
note: required because it appears within the type `PhantomData<ArcInner<LuaInner>>`
--> $RUST/core/src/marker.rs
|
| pub struct PhantomData<T: ?Sized>;
| ^^^^^^^^^^^
note: required because it appears within the type `Arc<LuaInner>`
--> $RUST/alloc/src/sync.rs
|
| pub struct Arc<
| ^^^
note: required because it appears within the type `Lua`
--> src/lua.rs
|
| pub struct Lua(Arc<LuaInner>);
| ^^^
= note: required for `&Lua` to implement `UnwindSafe`
note: required because it's used within this closure
--> tests/compile/lua_norefunwindsafe.rs:7:18
+6 -3
View File
@@ -4,22 +4,25 @@ error[E0277]: `Rc<Cell<i32>>` cannot be sent between threads safely
11 | lua.create_function(move |_, ()| {
| --------------- ^-----------
| | |
| _________|_______________within this `[closure@$DIR/tests/compile/non_send.rs:11:25: 11:37]`
| _________|_______________within this `{closure@$DIR/tests/compile/non_send.rs:11:25: 11:37}`
| | |
| | required by a bound introduced by this call
12 | | Ok(data.get())
13 | | })?
| |_____^ `Rc<Cell<i32>>` cannot be sent between threads safely
|
= help: within `[closure@$DIR/tests/compile/non_send.rs:11:25: 11:37]`, the trait `Send` is not implemented for `Rc<Cell<i32>>`
= 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
|
11 | lua.create_function(move |_, ()| {
| ^^^^^^^^^^^^
= note: required for `[closure@$DIR/tests/compile/non_send.rs:11:25: 11:37]` to implement `mlua::types::MaybeSend`
= note: required for `{closure@$DIR/tests/compile/non_send.rs:11:25: 11:37}` to implement `mlua::types::MaybeSend`
note: required by a bound in `Lua::create_function`
--> src/lua.rs
|
| pub fn create_function<'lua, A, R, F>(&'lua self, func: F) -> Result<Function<'lua>>
| --------------- required by a bound in this associated function
...
| F: Fn(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
| ^^^^^^^^^ required by this bound in `Lua::create_function`
+50 -10
View File
@@ -7,17 +7,57 @@ error[E0277]: the type `UnsafeCell<mlua::lua::ExtraData>` may contain interior m
| required by a bound introduced by this call
|
= help: within `Lua`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<mlua::lua::ExtraData>`
= note: required because it appears within the type `ArcInner<UnsafeCell<ExtraData>>`
= note: required because it appears within the type `PhantomData<ArcInner<UnsafeCell<ExtraData>>>`
= note: required because it appears within the type `Arc<UnsafeCell<ExtraData>>`
= note: required because it appears within the type `LuaInner`
= note: required because it appears within the type `ArcInner<LuaInner>`
= note: required because it appears within the type `PhantomData<ArcInner<LuaInner>>`
= note: required because it appears within the type `Arc<LuaInner>`
= note: required because it appears within the type `Lua`
note: required because it appears within the type `ArcInner<UnsafeCell<ExtraData>>`
--> $RUST/alloc/src/sync.rs
|
| struct ArcInner<T: ?Sized> {
| ^^^^^^^^
note: required because it appears within the type `PhantomData<ArcInner<UnsafeCell<ExtraData>>>`
--> $RUST/core/src/marker.rs
|
| pub struct PhantomData<T: ?Sized>;
| ^^^^^^^^^^^
note: required because it appears within the type `Arc<UnsafeCell<ExtraData>>`
--> $RUST/alloc/src/sync.rs
|
| pub struct Arc<
| ^^^
note: required because it appears within the type `LuaInner`
--> src/lua.rs
|
| pub struct LuaInner {
| ^^^^^^^^
note: required because it appears within the type `ArcInner<LuaInner>`
--> $RUST/alloc/src/sync.rs
|
| struct ArcInner<T: ?Sized> {
| ^^^^^^^^
note: required because it appears within the type `PhantomData<ArcInner<LuaInner>>`
--> $RUST/core/src/marker.rs
|
| pub struct PhantomData<T: ?Sized>;
| ^^^^^^^^^^^
note: required because it appears within the type `Arc<LuaInner>`
--> $RUST/alloc/src/sync.rs
|
| pub struct Arc<
| ^^^
note: required because it appears within the type `Lua`
--> src/lua.rs
|
| pub struct Lua(Arc<LuaInner>);
| ^^^
= note: required for `&Lua` to implement `UnwindSafe`
= note: required because it appears within the type `LuaRef<'_>`
= note: required because it appears within the type `Table<'_>`
note: required because it appears within the type `LuaRef<'_>`
--> src/types.rs
|
| pub(crate) struct LuaRef<'lua> {
| ^^^^^^
note: required because it appears within the type `Table<'_>`
--> src/table.rs
|
| pub struct Table<'lua>(pub(crate) LuaRef<'lua>);
| ^^^^^
note: required because it's used within this closure
--> tests/compile/ref_nounwindsafe.rs:8:18
|
@@ -4,6 +4,8 @@ error[E0597]: `ibad` does not live long enough
11 | lua.scope(|scope| {
| ----- has type `&mlua::Scope<'_, '1>`
...
14 | let ibad = 42;
| ---- binding `ibad` declared here
15 | scope.create_nonstatic_userdata(MyUserData(&ibad)).unwrap();
| -------------------------------------------^^^^^--
| | |
+20 -24
View File
@@ -1,35 +1,31 @@
error[E0597]: `lua` does not live long enough
--> tests/compile/static_callback_args.rs:12:5
|
10 | let lua = Lua::new();
| --- binding `lua` declared here
10 | let lua = Lua::new();
| --- binding `lua` declared here
11 |
12 | / lua.create_function(|_, table: Table| {
13 | |/ BAD_TIME.with(|bt| {
14 | || *bt.borrow_mut() = Some(table);
15 | || });
| ||__________- argument requires that `lua` is borrowed for `'static`
16 | | Ok(())
17 | | })?
| |_______^ borrowed value does not live long enough
12 | lua.create_function(|_, table: Table| {
| ^^^ borrowed value does not live long enough
13 | / BAD_TIME.with(|bt| {
14 | | *bt.borrow_mut() = Some(table);
15 | | });
| |__________- argument requires that `lua` is borrowed for `'static`
...
32 | }
| - `lua` dropped here while still borrowed
32 | }
| - `lua` dropped here while still borrowed
error[E0505]: cannot move out of `lua` because it is borrowed
--> tests/compile/static_callback_args.rs:22:10
|
10 | let lua = Lua::new();
| --- binding `lua` declared here
10 | let lua = Lua::new();
| --- binding `lua` declared here
11 |
12 | / lua.create_function(|_, table: Table| {
13 | |/ BAD_TIME.with(|bt| {
14 | || *bt.borrow_mut() = Some(table);
15 | || });
| ||__________- argument requires that `lua` is borrowed for `'static`
16 | | Ok(())
17 | | })?
| |_______- borrow of `lua` occurs here
12 | lua.create_function(|_, table: Table| {
| --- borrow of `lua` occurs here
13 | / BAD_TIME.with(|bt| {
14 | | *bt.borrow_mut() = Some(table);
15 | | });
| |__________- argument requires that `lua` is borrowed for `'static`
...
22 | drop(lua);
| ^^^ move out of `lua` occurs here
22 | drop(lua);
| ^^^ move out of `lua` occurs here
+264 -1
View File
@@ -3,7 +3,270 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::ffi::{CStr, CString};
use maplit::{btreemap, btreeset, hashmap, hashset};
use mlua::{Error, Lua, Result};
use mlua::{
AnyUserData, Error, Function, IntoLua, Lua, RegistryKey, Result, Table, Thread, UserDataRef,
Value,
};
#[test]
fn test_value_into_lua() -> Result<()> {
let lua = Lua::new();
// Direct conversion
let v = Value::Boolean(true);
let v2 = (&v).into_lua(&lua)?;
assert_eq!(v, v2);
// Push into stack
let table = lua.create_table()?;
table.set("v", &v)?;
assert_eq!(v, table.get::<_, Value>("v")?);
Ok(())
}
#[test]
fn test_string_into_lua() -> Result<()> {
let lua = Lua::new();
// Direct conversion
let s = lua.create_string("hello, world!")?;
let s2 = (&s).into_lua(&lua)?;
assert_eq!(s, s2.as_string().unwrap());
// Push into stack
let table = lua.create_table()?;
table.set("s", &s)?;
assert_eq!(s, table.get::<_, String>("s")?);
Ok(())
}
#[cfg(all(feature = "unstable", not(feature = "send")))]
#[test]
fn test_owned_string_into_lua() -> Result<()> {
let lua = Lua::new();
// Direct conversion
let s = lua.create_string("hello, world")?.into_owned();
let s2 = (&s).into_lua(&lua)?;
assert_eq!(s.to_ref(), *s2.as_string().unwrap());
// Push into stack
let table = lua.create_table()?;
table.set("s", &s)?;
assert_eq!(s.to_ref(), table.get::<_, String>("s")?);
Ok(())
}
#[cfg(all(feature = "unstable", not(feature = "send")))]
#[test]
fn test_owned_string_from_lua() -> Result<()> {
let lua = Lua::new();
let s = lua.unpack::<mlua::OwnedString>(lua.pack("hello, world")?)?;
assert_eq!(s.to_ref(), "hello, world");
Ok(())
}
#[test]
fn test_table_into_lua() -> Result<()> {
let lua = Lua::new();
// Direct conversion
let t = lua.create_table()?;
let t2 = (&t).into_lua(&lua)?;
assert_eq!(&t, t2.as_table().unwrap());
// Push into stack
let f = lua.create_function(|_, (t, s): (Table, String)| t.set("s", s))?;
f.call((&t, "hello"))?;
assert_eq!("hello", t.get::<_, String>("s")?);
Ok(())
}
#[cfg(all(feature = "unstable", not(feature = "send")))]
#[test]
fn test_owned_table_into_lua() -> Result<()> {
let lua = Lua::new();
// Direct conversion
let t = lua.create_table()?.into_owned();
let t2 = (&t).into_lua(&lua)?;
assert_eq!(t.to_ref(), *t2.as_table().unwrap());
// Push into stack
let f = lua.create_function(|_, (t, s): (Table, String)| t.set("s", s))?;
f.call((&t, "hello"))?;
assert_eq!("hello", t.to_ref().get::<_, String>("s")?);
Ok(())
}
#[test]
fn test_function_into_lua() -> Result<()> {
let lua = Lua::new();
// Direct conversion
let f = lua.create_function(|_, ()| Ok::<_, Error>(()))?;
let f2 = (&f).into_lua(&lua)?;
assert_eq!(&f, f2.as_function().unwrap());
// Push into stack
let table = lua.create_table()?;
table.set("f", &f)?;
assert_eq!(f, table.get::<_, Function>("f")?);
Ok(())
}
#[cfg(all(feature = "unstable", not(feature = "send")))]
#[test]
fn test_owned_function_into_lua() -> Result<()> {
let lua = Lua::new();
// Direct conversion
let f = lua
.create_function(|_, ()| Ok::<_, Error>(()))?
.into_owned();
let f2 = (&f).into_lua(&lua)?;
assert_eq!(f.to_ref(), *f2.as_function().unwrap());
// Push into stack
let table = lua.create_table()?;
table.set("f", &f)?;
assert_eq!(f.to_ref(), table.get::<_, Function>("f")?);
Ok(())
}
#[test]
fn test_thread_into_lua() -> Result<()> {
let lua = Lua::new();
// Direct conversion
let f = lua.create_function(|_, ()| Ok::<_, Error>(()))?;
let th = lua.create_thread(f)?;
let th2 = (&th).into_lua(&lua)?;
assert_eq!(&th, th2.as_thread().unwrap());
// Push into stack
let table = lua.create_table()?;
table.set("th", &th)?;
assert_eq!(th, table.get::<_, Thread>("th")?);
Ok(())
}
#[cfg(all(feature = "unstable", not(feature = "send")))]
#[test]
fn test_owned_thread_into_lua() -> Result<()> {
let lua = Lua::new();
// Direct conversion
let f = lua.create_function(|_, ()| Ok::<_, Error>(()))?;
let th = lua.create_thread(f)?.into_owned();
let th2 = (&th).into_lua(&lua)?;
assert_eq!(&th.to_ref(), th2.as_thread().unwrap());
// Push into stack
let table = lua.create_table()?;
table.set("th", &th)?;
assert_eq!(th.to_ref(), table.get::<_, Thread>("th")?);
Ok(())
}
#[cfg(all(feature = "unstable", not(feature = "send")))]
#[test]
fn test_owned_thread_from_lua() -> Result<()> {
let lua = Lua::new();
let th = lua.unpack::<mlua::OwnedThread>(Value::Thread(lua.current_thread()))?;
assert_eq!(th.to_ref(), lua.current_thread());
Ok(())
}
#[test]
fn test_anyuserdata_into_lua() -> Result<()> {
let lua = Lua::new();
// Direct conversion
let ud = lua.create_any_userdata(String::from("hello"))?;
let ud2 = (&ud).into_lua(&lua)?;
assert_eq!(&ud, ud2.as_userdata().unwrap());
// Push into stack
let table = lua.create_table()?;
table.set("ud", &ud)?;
assert_eq!(ud, table.get::<_, AnyUserData>("ud")?);
assert_eq!("hello", *table.get::<_, UserDataRef<String>>("ud")?);
Ok(())
}
#[cfg(all(feature = "unstable", not(feature = "send")))]
#[test]
fn test_owned_anyuserdata_into_lua() -> Result<()> {
let lua = Lua::new();
// Direct conversion
let ud = lua.create_any_userdata(String::from("hello"))?.into_owned();
let ud2 = (&ud).into_lua(&lua)?;
assert_eq!(ud.to_ref(), *ud2.as_userdata().unwrap());
// Push into stack
let table = lua.create_table()?;
table.set("ud", &ud)?;
assert_eq!(ud.to_ref(), table.get::<_, AnyUserData>("ud")?);
assert_eq!("hello", *table.get::<_, UserDataRef<String>>("ud")?);
Ok(())
}
#[test]
fn test_registry_value_into_lua() -> Result<()> {
let lua = Lua::new();
let t = lua.create_table()?;
let r = lua.create_registry_value(t)?;
let f = lua.create_function(|_, t: Table| t.raw_set("hello", "world"))?;
f.call(&r)?;
let v = r.into_lua(&lua)?;
let t = v.as_table().unwrap();
assert_eq!(t.get::<_, String>("hello")?, "world");
// Try to set nil registry key
let r_nil = lua.create_registry_value(Value::Nil)?;
t.set("hello", &r_nil)?;
assert_eq!(t.get::<_, Value>("hello")?, Value::Nil);
// Check non-owned registry key
let lua2 = Lua::new();
let r2 = lua2.create_registry_value("abc")?;
assert!(matches!(
f.call::<_, ()>(&r2),
Err(Error::MismatchedRegistryKey)
));
Ok(())
}
#[test]
fn test_registry_key_from_lua() -> Result<()> {
let lua = Lua::new();
let fkey = lua.load("function() return 1 end").eval::<RegistryKey>()?;
let f = lua.registry_value::<Function>(&fkey)?;
assert_eq!(f.call::<_, i32>(())?, 1);
Ok(())
}
#[test]
fn test_conv_vec() -> Result<()> {
+13
View File
@@ -231,6 +231,19 @@ fn test_function_info() -> Result<()> {
Ok(())
}
#[test]
fn test_function_pointer() -> Result<()> {
let lua = Lua::new();
let func1 = lua.load("return function() end").into_function()?;
let func2 = func1.call::<_, Function>(())?;
assert_eq!(func1.to_pointer(), func1.clone().to_pointer());
assert_ne!(func1.to_pointer(), func2.to_pointer());
Ok(())
}
#[test]
fn test_function_wrap() -> Result<()> {
use mlua::Error;
+16
View File
@@ -275,6 +275,22 @@ fn test_sandbox() -> Result<()> {
Ok(())
}
#[test]
fn test_sandbox_nolibs() -> Result<()> {
let lua = Lua::new_with(StdLib::NONE, LuaOptions::default()).unwrap();
lua.sandbox(true)?;
lua.load("global = 123").exec()?;
let n: i32 = lua.load("return global").eval()?;
assert_eq!(n, 123);
assert_eq!(lua.globals().get::<_, Option<i32>>("global")?, Some(123));
lua.sandbox(false)?;
assert_eq!(lua.globals().get::<_, Option<i32>>("global")?, None);
Ok(())
}
#[test]
fn test_sandbox_threads() -> Result<()> {
let lua = Lua::new();
+60
View File
@@ -0,0 +1,60 @@
use mlua::{Error, ExternalError, IntoLuaMulti, Lua, Result, String, Value};
#[test]
fn test_result_conversions() -> Result<()> {
let lua = Lua::new();
let globals = lua.globals();
let ok = lua.create_function(|_, ()| Ok(Ok::<(), Error>(())))?;
let err = lua.create_function(|_, ()| Ok(Err::<(), _>("failure1".into_lua_err())))?;
let ok2 = lua.create_function(|_, ()| Ok(Ok::<_, Error>("!".to_owned())))?;
let err2 = lua.create_function(|_, ()| Ok(Err::<String, _>("failure2".into_lua_err())))?;
globals.set("ok", ok)?;
globals.set("ok2", ok2)?;
globals.set("err", err)?;
globals.set("err2", err2)?;
lua.load(
r#"
local r, e = ok()
assert(r == nil and e == nil)
local r, e = err()
assert(r == nil)
assert(tostring(e):find("failure1") ~= nil)
local r, e = ok2()
assert(r == "!")
assert(e == nil)
local r, e = err2()
assert(r == nil)
assert(tostring(e):find("failure2") ~= nil)
"#,
)
.exec()?;
// Try to convert Result into MultiValue
let ok1 = Ok::<(), Error>(());
let multi_ok1 = ok1.into_lua_multi(&lua)?;
assert_eq!(multi_ok1.len(), 0);
let err1 = Err::<(), _>("failure1");
let multi_err1 = err1.into_lua_multi(&lua)?;
assert_eq!(multi_err1.len(), 2);
assert_eq!(multi_err1[0], Value::Nil);
assert_eq!(multi_err1[1].as_str().unwrap(), "failure1");
let ok2 = Ok::<_, Error>("!");
let multi_ok2 = ok2.into_lua_multi(&lua)?;
assert_eq!(multi_ok2.len(), 1);
assert_eq!(multi_ok2[0].as_str().unwrap(), "!");
let err2 = Err::<String, _>("failure2".into_lua_err());
let multi_err2 = err2.into_lua_multi(&lua)?;
assert_eq!(multi_err2.len(), 2);
assert_eq!(multi_err2[0], Value::Nil);
assert!(matches!(multi_err2[1], Value::Error(_)));
assert_eq!(multi_err2[1].to_string()?, "failure2");
Ok(())
}
+1 -1
View File
@@ -598,7 +598,7 @@ fn test_from_value_with_options() -> Result<(), Box<dyn StdError>> {
// Check recursion when using `Serialize` impl
let t = lua.create_table()?;
t.set("t", t.clone())?;
t.set("t", &t)?;
assert!(serde_json::to_string(&t).is_err());
// Serialize Lua globals table
+13
View File
@@ -99,6 +99,19 @@ fn test_string_debug() -> Result<()> {
Ok(())
}
#[test]
fn test_string_pointer() -> Result<()> {
let lua = Lua::new();
let str1 = lua.create_string("hello")?;
let str2 = lua.create_string("hello")?;
// Lua uses string interning, so these should be the same
assert_eq!(str1.to_pointer(), str2.to_pointer());
Ok(())
}
#[cfg(all(feature = "unstable", not(feature = "send")))]
#[test]
fn test_owned_string() -> Result<()> {
+13
View File
@@ -369,6 +369,19 @@ fn test_table_eq() -> Result<()> {
Ok(())
}
#[test]
fn test_table_pointer() -> Result<()> {
let lua = Lua::new();
let table1 = lua.create_table()?;
let table2 = lua.create_table()?;
assert_eq!(table1.to_pointer(), table1.clone().to_pointer());
assert_ne!(table1.to_pointer(), table2.to_pointer());
Ok(())
}
#[test]
fn test_table_error() -> Result<()> {
let lua = Lua::new();
+2 -40
View File
@@ -504,44 +504,6 @@ fn test_panic() -> Result<()> {
Ok(())
}
#[test]
fn test_result_conversions() -> Result<()> {
let lua = Lua::new();
let globals = lua.globals();
let ok = lua.create_function(|_, ()| Ok(Ok::<(), Error>(())))?;
let err = lua.create_function(|_, ()| Ok(Err::<(), _>("failure1".into_lua_err())))?;
let ok2 = lua.create_function(|_, ()| Ok(Ok::<_, Error>("!".to_owned())))?;
let err2 = lua.create_function(|_, ()| Ok(Err::<String, _>("failure2".into_lua_err())))?;
globals.set("ok", ok)?;
globals.set("ok2", ok2)?;
globals.set("err", err)?;
globals.set("err2", err2)?;
lua.load(
r#"
local r, e = ok()
assert(r == nil and e == nil)
local r, e = err()
assert(r == nil)
assert(tostring(e):find("failure1") ~= nil)
local r, e = ok2()
assert(r == "!")
assert(e == nil)
local r, e = err2()
assert(r == nil)
assert(tostring(e):find("failure2") ~= nil)
"#,
)
.exec()?;
Ok(())
}
#[test]
fn test_num_conversion() -> Result<()> {
let lua = Lua::new();
@@ -965,7 +927,7 @@ fn test_recursion() -> Result<()> {
Ok(())
})?;
lua.globals().set("f", f.clone())?;
lua.globals().set("f", &f)?;
f.call::<_, ()>(1)?;
Ok(())
@@ -1003,7 +965,7 @@ fn test_too_many_recursions() -> Result<()> {
let f = lua
.create_function(move |lua, ()| lua.globals().get::<_, Function>("f")?.call::<_, ()>(()))?;
lua.globals().set("f", f.clone())?;
lua.globals().set("f", &f)?;
assert!(f.call::<_, ()>(()).is_err());
Ok(())
+14 -1
View File
@@ -182,7 +182,7 @@ fn test_coroutine_panic() {
let thrd_main = lua.create_function(|_, ()| -> Result<()> {
panic!("test_panic");
})?;
lua.globals().set("main", thrd_main.clone())?;
lua.globals().set("main", &thrd_main)?;
let thrd: Thread = lua.create_thread(thrd_main)?;
thrd.resume(())
}) {
@@ -191,6 +191,19 @@ fn test_coroutine_panic() {
}
}
#[test]
fn test_thread_pointer() -> Result<()> {
let lua = Lua::new();
let func = lua.load("return 123").into_function()?;
let thread = lua.create_thread(func.clone())?;
assert_eq!(thread.to_pointer(), thread.clone().to_pointer());
assert_ne!(thread.to_pointer(), lua.current_thread().to_pointer());
Ok(())
}
#[cfg(all(feature = "unstable", not(feature = "send")))]
#[test]
fn test_owned_thread() -> Result<()> {
+19 -5
View File
@@ -58,7 +58,7 @@ fn test_methods() -> Result<()> {
fn check_methods(lua: &Lua, userdata: AnyUserData) -> Result<()> {
let globals = lua.globals();
globals.set("userdata", userdata.clone())?;
globals.set("userdata", &userdata)?;
lua.load(
r#"
function get_it()
@@ -342,7 +342,7 @@ fn test_userdata_take() -> Result<()> {
}
fn check_userdata_take(lua: &Lua, userdata: AnyUserData, rc: Arc<i64>) -> Result<()> {
lua.globals().set("userdata", userdata.clone())?;
lua.globals().set("userdata", &userdata)?;
assert_eq!(Arc::strong_count(&rc), 3);
{
let _value = userdata.borrow::<MyUserdata>()?;
@@ -474,7 +474,7 @@ fn test_functions() -> Result<()> {
let lua = Lua::new();
let globals = lua.globals();
let userdata = lua.create_userdata(MyUserData(42))?;
globals.set("userdata", userdata.clone())?;
globals.set("userdata", &userdata)?;
lua.load(
r#"
function get_it()
@@ -951,6 +951,20 @@ fn test_userdata_method_errors() -> Result<()> {
Ok(())
}
#[test]
fn test_userdata_pointer() -> Result<()> {
let lua = Lua::new();
let ud1 = lua.create_any_userdata("hello")?;
let ud2 = lua.create_any_userdata("hello")?;
assert_eq!(ud1.to_pointer(), ud1.clone().to_pointer());
// Different userdata objects with the same value should have different pointers
assert_ne!(ud1.to_pointer(), ud2.to_pointer());
Ok(())
}
#[cfg(all(feature = "unstable", not(feature = "send")))]
#[test]
fn test_owned_userdata() -> Result<()> {
@@ -991,9 +1005,9 @@ fn test_userdata_derive() -> Result<()> {
// More complex struct where generics and where clause
#[derive(Clone, Copy, mlua::FromLua)]
struct MyUserData2<'a, T>(&'a T)
struct MyUserData2<'a, T: ?Sized>(&'a T)
where
T: ?Sized;
T: Copy;
lua.register_userdata_type::<MyUserData2<'static, i32>>(|reg| {
reg.add_function("val", |_, this: MyUserData2<'static, i32>| Ok(*this.0));