Add shortcuts to check thread status (Thread::is_resumable(), Thread::is_finished() etc)

This commit is contained in:
Alex Orlenko
2026-02-28 11:46:05 +00:00
parent bf0c96908f
commit 47e6a37323
5 changed files with 52 additions and 29 deletions
+25
View File
@@ -259,6 +259,31 @@ impl Thread {
}
}
/// Returns `true` if this thread is resumable (meaning it can be resumed by calling
/// [`Thread::resume`]).
#[inline(always)]
pub fn is_resumable(&self) -> bool {
self.status() == ThreadStatus::Resumable
}
/// Returns `true` if this thread is currently running.
#[inline(always)]
pub fn is_running(&self) -> bool {
self.status() == ThreadStatus::Running
}
/// Returns `true` if this thread has finished executing.
#[inline(always)]
pub fn is_finished(&self) -> bool {
self.status() == ThreadStatus::Finished
}
/// Returns `true` if this thread has raised a Lua error during execution.
#[inline(always)]
pub fn is_error(&self) -> bool {
self.status() == ThreadStatus::Error
}
/// Sets a hook function that will periodically be called as Lua code executes.
///
/// This function is similar or [`Lua::set_hook`] except that it sets for the thread.
+2 -2
View File
@@ -7,7 +7,7 @@ use futures_util::stream::TryStreamExt;
use tokio::sync::Mutex;
use mlua::{
Error, Function, Lua, LuaOptions, MultiValue, ObjectLike, Result, StdLib, Table, ThreadStatus, UserData,
Error, Function, Lua, LuaOptions, MultiValue, ObjectLike, Result, StdLib, Table, UserData,
UserDataMethods, UserDataRef, Value,
};
@@ -714,7 +714,7 @@ fn test_async_yield_with() -> Result<()> {
assert_eq!(thread.resume::<(i32, i32)>((10, 11))?, (21, 110));
assert_eq!(thread.resume::<(i32, i32)>((11, 12))?, (23, 132));
assert_eq!(thread.resume::<(i32, i32)>((12, 13))?, (0, 0));
assert_eq!(thread.status(), ThreadStatus::Finished);
assert!(thread.is_finished());
Ok(())
}
+4 -4
View File
@@ -4,7 +4,7 @@ use std::sync::atomic::{AtomicI64, Ordering};
use std::sync::{Arc, Mutex};
use mlua::debug::DebugEvent;
use mlua::{Error, HookTriggers, Lua, Result, ThreadStatus, Value, VmState};
use mlua::{Error, HookTriggers, Lua, Result, Value, VmState};
#[test]
fn test_hook_triggers() {
@@ -281,14 +281,14 @@ fn test_hook_yield() -> Result<()> {
assert!(co.resume::<()>(()).is_ok());
assert!(co.resume::<()>(()).is_ok());
assert!(co.resume::<()>(()).is_ok());
assert!(co.status() == ThreadStatus::Finished);
assert!(co.is_finished());
}
#[cfg(any(feature = "lua51", feature = "lua52", feature = "luajit"))]
{
assert!(
matches!(co.resume::<()>(()), Err(Error::RuntimeError(err)) if err.contains("attempt to yield from a hook"))
);
assert!(co.status() == ThreadStatus::Error);
assert!(co.is_error());
}
Ok(())
@@ -321,7 +321,7 @@ fn test_global_hook() -> Result<()> {
thread.resume::<()>(()).unwrap();
lua.remove_global_hook();
thread.resume::<()>(()).unwrap();
assert_eq!(thread.status(), ThreadStatus::Finished);
assert!(thread.is_finished());
assert_eq!(counter.load(Ordering::Relaxed), 3);
Ok(())
+3 -5
View File
@@ -6,9 +6,7 @@ use std::os::raw::c_void;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicPtr, AtomicU64, Ordering};
use mlua::{
Compiler, Error, Function, Lua, LuaOptions, Result, StdLib, Table, ThreadStatus, Value, Vector, VmState,
};
use mlua::{Compiler, Error, Function, Lua, LuaOptions, Result, StdLib, Table, Value, Vector, VmState};
#[test]
fn test_version() -> Result<()> {
@@ -324,11 +322,11 @@ fn test_interrupts() -> Result<()> {
.into_function()?,
)?;
co.resume::<()>(())?;
assert_eq!(co.status(), ThreadStatus::Resumable);
assert!(co.is_resumable());
let result: i32 = co.resume(())?;
assert_eq!(result, 6);
assert_eq!(yield_count.load(Ordering::Relaxed), 7);
assert_eq!(co.status(), ThreadStatus::Finished);
assert!(co.is_finished());
// Test no yielding at non-yieldable points
yield_count.store(0, Ordering::Relaxed);
+18 -18
View File
@@ -1,6 +1,6 @@
use std::panic::catch_unwind;
use mlua::{Error, Function, IntoLua, Lua, Result, Thread, ThreadStatus, Value};
use mlua::{Error, Function, IntoLua, Lua, Result, Thread, Value};
#[test]
fn test_thread() -> Result<()> {
@@ -21,17 +21,17 @@ fn test_thread() -> Result<()> {
.eval()?,
)?;
assert_eq!(thread.status(), ThreadStatus::Resumable);
assert!(thread.is_resumable());
assert_eq!(thread.resume::<i64>(0)?, 0);
assert_eq!(thread.status(), ThreadStatus::Resumable);
assert!(thread.is_resumable());
assert_eq!(thread.resume::<i64>(1)?, 1);
assert_eq!(thread.status(), ThreadStatus::Resumable);
assert!(thread.is_resumable());
assert_eq!(thread.resume::<i64>(2)?, 3);
assert_eq!(thread.status(), ThreadStatus::Resumable);
assert!(thread.is_resumable());
assert_eq!(thread.resume::<i64>(3)?, 6);
assert_eq!(thread.status(), ThreadStatus::Resumable);
assert!(thread.is_resumable());
assert_eq!(thread.resume::<i64>(4)?, 10);
assert_eq!(thread.status(), ThreadStatus::Finished);
assert!(thread.is_finished());
let accumulate = lua.create_thread(
lua.load(
@@ -50,9 +50,9 @@ fn test_thread() -> Result<()> {
accumulate.resume::<()>(i)?;
}
assert_eq!(accumulate.resume::<i64>(4)?, 10);
assert_eq!(accumulate.status(), ThreadStatus::Resumable);
assert!(accumulate.is_resumable());
assert!(accumulate.resume::<()>("error").is_err());
assert_eq!(accumulate.status(), ThreadStatus::Error);
assert!(accumulate.is_error());
let thread = lua
.load(
@@ -65,7 +65,7 @@ fn test_thread() -> Result<()> {
"#,
)
.eval::<Thread>()?;
assert_eq!(thread.status(), ThreadStatus::Resumable);
assert!(thread.is_resumable());
assert_eq!(thread.resume::<i64>(())?, 42);
let thread: Thread = lua
@@ -92,7 +92,7 @@ fn test_thread() -> Result<()> {
// Already running thread must be unresumable
let thread = lua.create_thread(lua.create_function(|lua, ()| {
assert_eq!(lua.current_thread().status(), ThreadStatus::Running);
assert!(lua.current_thread().is_running());
let result = lua.current_thread().resume::<()>(());
assert!(
matches!(result, Err(Error::CoroutineUnresumable)),
@@ -123,12 +123,12 @@ fn test_thread_reset() -> Result<()> {
assert!(thread.reset(func.clone()).is_ok());
for _ in 0..2 {
assert_eq!(thread.status(), ThreadStatus::Resumable);
assert!(thread.is_resumable());
let _ = thread.resume::<AnyUserData>(MyUserData(arc.clone()))?;
assert_eq!(thread.status(), ThreadStatus::Resumable);
assert!(thread.is_resumable());
assert_eq!(Arc::strong_count(&arc), 2);
thread.resume::<()>(())?;
assert_eq!(thread.status(), ThreadStatus::Finished);
assert!(thread.is_finished());
thread.reset(func.clone())?;
lua.gc_collect()?;
assert_eq!(Arc::strong_count(&arc), 1);
@@ -138,21 +138,21 @@ fn test_thread_reset() -> Result<()> {
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!(thread.is_error());
assert_eq!(Arc::strong_count(&arc), 2);
#[cfg(any(feature = "lua55", feature = "lua54"))]
{
assert!(thread.reset(func.clone()).is_err());
// 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::Finished));
assert!(thread.is_finished());
assert!(thread.reset(func.clone()).is_ok());
assert_eq!(thread.status(), ThreadStatus::Resumable);
assert!(thread.is_resumable());
}
#[cfg(any(feature = "lua55", feature = "lua54", feature = "luau"))]
{
assert!(thread.reset(func.clone()).is_ok());
assert_eq!(thread.status(), ThreadStatus::Resumable);
assert!(thread.is_resumable());
}
// Try reset running thread