mlua/tests/thread.rs

197 lines
5.8 KiB
Rust
Raw Permalink Normal View History

2018-02-09 23:52:05 -05:00
use std::panic::catch_unwind;
2019-10-14 17:21:30 -04:00
use mlua::{Error, Function, Lua, Result, Thread, ThreadStatus};
2018-02-09 23:52:05 -05:00
#[test]
2019-09-28 10:23:17 -04:00
fn test_thread() -> Result<()> {
2019-10-14 17:21:30 -04:00
let lua = Lua::new();
2019-09-28 10:23:17 -04:00
let thread = lua.create_thread(
lua.load(
r#"
function (s)
local sum = s
for i = 1,4 do
sum = sum + coroutine.yield(sum)
2018-02-09 23:52:05 -05:00
end
return sum
end
2018-02-09 23:52:05 -05:00
"#,
2019-09-27 12:38:24 -04:00
)
2019-09-28 10:23:17 -04:00
.eval()?,
)?;
2018-02-09 23:52:05 -05:00
assert_eq!(thread.status(), ThreadStatus::Resumable);
2019-09-28 10:23:17 -04:00
assert_eq!(thread.resume::<_, i64>(0)?, 0);
2018-02-09 23:52:05 -05:00
assert_eq!(thread.status(), ThreadStatus::Resumable);
2019-09-28 10:23:17 -04:00
assert_eq!(thread.resume::<_, i64>(1)?, 1);
2018-02-09 23:52:05 -05:00
assert_eq!(thread.status(), ThreadStatus::Resumable);
2019-09-28 10:23:17 -04:00
assert_eq!(thread.resume::<_, i64>(2)?, 3);
2018-02-09 23:52:05 -05:00
assert_eq!(thread.status(), ThreadStatus::Resumable);
2019-09-28 10:23:17 -04:00
assert_eq!(thread.resume::<_, i64>(3)?, 6);
2018-02-09 23:52:05 -05:00
assert_eq!(thread.status(), ThreadStatus::Resumable);
2019-09-28 10:23:17 -04:00
assert_eq!(thread.resume::<_, i64>(4)?, 10);
2018-02-09 23:52:05 -05:00
assert_eq!(thread.status(), ThreadStatus::Unresumable);
2019-09-28 10:23:17 -04:00
let accumulate = lua.create_thread(
lua.load(
r#"
function (sum)
while true do
sum = sum + coroutine.yield(sum)
2018-02-09 23:52:05 -05:00
end
end
2018-02-09 23:52:05 -05:00
"#,
2019-09-27 12:38:24 -04:00
)
2019-09-28 10:23:17 -04:00
.eval::<Function>()?,
)?;
2018-02-09 23:52:05 -05:00
for i in 0..4 {
2019-09-28 10:23:17 -04:00
accumulate.resume::<_, ()>(i)?;
2018-02-09 23:52:05 -05:00
}
2019-09-28 10:23:17 -04:00
assert_eq!(accumulate.resume::<_, i64>(4)?, 10);
2018-02-09 23:52:05 -05:00
assert_eq!(accumulate.status(), ThreadStatus::Resumable);
assert!(accumulate.resume::<_, ()>("error").is_err());
assert_eq!(accumulate.status(), ThreadStatus::Error);
2018-09-24 22:13:42 -04:00
let thread = lua
2019-09-28 10:23:17 -04:00
.load(
2018-08-05 09:51:39 -04:00
r#"
2019-09-28 10:23:17 -04:00
coroutine.create(function ()
while true do
coroutine.yield(42)
end
end)
"#,
2019-09-27 12:38:24 -04:00
)
2019-09-28 10:23:17 -04:00
.eval::<Thread>()?;
2018-02-09 23:52:05 -05:00
assert_eq!(thread.status(), ThreadStatus::Resumable);
2019-09-28 10:23:17 -04:00
assert_eq!(thread.resume::<_, i64>(())?, 42);
2018-02-09 23:52:05 -05:00
2018-09-24 22:13:42 -04:00
let thread: Thread = lua
2019-09-28 10:23:17 -04:00
.load(
2018-08-05 09:51:39 -04:00
r#"
2019-09-28 10:23:17 -04:00
coroutine.create(function(arg)
assert(arg == 42)
local yieldarg = coroutine.yield(123)
assert(yieldarg == 43)
return 987
end)
"#,
2019-09-27 12:38:24 -04:00
)
2019-09-28 10:23:17 -04:00
.eval()?;
2018-02-09 23:52:05 -05:00
2019-09-28 10:23:17 -04:00
assert_eq!(thread.resume::<_, u32>(42)?, 123);
assert_eq!(thread.resume::<_, u32>(43)?, 987);
2018-02-09 23:52:05 -05:00
match thread.resume::<_, u32>(()) {
Err(Error::CoroutineInactive) => {}
Err(_) => panic!("resuming dead coroutine error is not CoroutineInactive kind"),
_ => panic!("resuming dead coroutine did not return error"),
}
2019-09-28 10:23:17 -04:00
Ok(())
2018-02-09 23:52:05 -05:00
}
2021-05-05 06:11:32 -04:00
#[test]
2022-03-23 17:13:48 -04:00
#[cfg(any(
feature = "lua54",
all(feature = "luajit", feature = "vendored"),
feature = "luau",
))]
2021-05-05 06:11:32 -04:00
fn test_thread_reset() -> Result<()> {
use mlua::{AnyUserData, UserData};
use std::sync::Arc;
let lua = Lua::new();
struct MyUserData(Arc<()>);
impl UserData for MyUserData {}
let arc = Arc::new(());
let func: Function = lua.load(r#"function(ud) coroutine.yield(ud) end"#).eval()?;
let thread = lua.create_thread(func.clone())?;
for _ in 0..2 {
assert_eq!(thread.status(), ThreadStatus::Resumable);
let _ = thread.resume::<_, AnyUserData>(MyUserData(arc.clone()))?;
assert_eq!(thread.status(), ThreadStatus::Resumable);
assert_eq!(Arc::strong_count(&arc), 2);
thread.resume::<_, ()>(())?;
assert_eq!(thread.status(), ThreadStatus::Unresumable);
thread.reset(func.clone())?;
lua.gc_collect()?;
assert_eq!(Arc::strong_count(&arc), 1);
}
2022-03-23 17:13:48 -04:00
// Check for errors
let func: Function = lua.load(r#"function(ud) error("test error") end"#).eval()?;
let thread = lua.create_thread(func.clone())?;
let _ = thread.resume::<_, AnyUserData>(MyUserData(arc.clone()));
assert_eq!(thread.status(), ThreadStatus::Error);
assert_eq!(Arc::strong_count(&arc), 2);
2021-05-05 06:11:32 -04:00
#[cfg(feature = "lua54")]
{
assert!(thread.reset(func.clone()).is_err());
2022-01-29 07:36:09 -05:00
// Reset behavior has changed in Lua v5.4.4
// It's became possible to force reset thread by popping error object
assert!(matches!(
thread.status(),
ThreadStatus::Unresumable | ThreadStatus::Error
));
// Would pass in 5.4.4
// assert!(thread.reset(func.clone()).is_ok());
// assert_eq!(thread.status(), ThreadStatus::Resumable);
2021-05-05 06:11:32 -04:00
}
2022-03-23 17:13:48 -04:00
#[cfg(any(feature = "lua54", feature = "luau"))]
{
assert!(thread.reset(func.clone()).is_ok());
assert_eq!(thread.status(), ThreadStatus::Resumable);
}
2021-05-05 06:11:32 -04:00
Ok(())
}
2018-02-09 23:52:05 -05:00
#[test]
2021-06-18 18:13:56 -04:00
fn test_coroutine_from_closure() -> Result<()> {
2019-10-14 17:21:30 -04:00
let lua = Lua::new();
2019-09-28 10:23:17 -04:00
let thrd_main = lua.create_function(|_, ()| Ok(()))?;
lua.globals().set("main", thrd_main)?;
2019-10-14 17:21:30 -04:00
2020-05-08 07:42:40 -04:00
#[cfg(any(
feature = "lua54",
feature = "lua53",
feature = "lua52",
2022-02-19 09:15:15 -05:00
feature = "luajit",
feature = "luau"
2020-05-08 07:42:40 -04:00
))]
2019-09-28 10:23:17 -04:00
let thrd: Thread = lua.load("coroutine.create(main)").eval()?;
#[cfg(feature = "lua51")]
2019-10-14 17:21:30 -04:00
let thrd: Thread = lua
.load("coroutine.create(function(...) return main(unpack(arg)) end)")
.eval()?;
2019-09-28 10:23:17 -04:00
thrd.resume::<_, ()>(())?;
Ok(())
2018-02-09 23:52:05 -05:00
}
#[test]
2021-06-18 18:13:56 -04:00
fn test_coroutine_panic() {
match catch_unwind(|| -> Result<()> {
// check that coroutines propagate panics correctly
2019-10-14 17:21:30 -04:00
let lua = Lua::new();
let thrd_main = lua.create_function(|_, ()| -> Result<()> {
panic!("test_panic");
})?;
lua.globals().set("main", thrd_main.clone())?;
let thrd: Thread = lua.create_thread(thrd_main)?;
thrd.resume(())
}) {
2018-02-09 23:52:05 -05:00
Ok(r) => panic!("coroutine panic not propagated, instead returned {:?}", r),
Err(p) => assert!(*p.downcast::<&str>().unwrap() == "test_panic"),
2018-02-09 23:52:05 -05:00
}
}