@@ -2,8 +2,7 @@ use std::fmt;
22use std:: os:: raw:: { c_int, c_void} ;
33
44use crate :: error:: { Error , Result } ;
5- #[ allow( unused) ]
6- use crate :: state:: Lua ;
5+ use crate :: function:: Function ;
76use crate :: state:: RawLua ;
87use crate :: traits:: { FromLuaMulti , IntoLuaMulti } ;
98use crate :: types:: { LuaType , ValueRef } ;
@@ -42,6 +41,26 @@ pub enum ThreadStatus {
4241 Error ,
4342}
4443
44+ /// Internal representation of a Lua thread status.
45+ ///
46+ /// The number in `New` and `Yielded` variants is the number of arguments pushed
47+ /// to the thread stack.
48+ #[ derive( Clone , Copy ) ]
49+ enum ThreadStatusInner {
50+ New ,
51+ Running ,
52+ Yielded ,
53+ Finished ,
54+ Error ,
55+ }
56+
57+ impl ThreadStatusInner {
58+ #[ inline( always) ]
59+ fn is_resumable ( self ) -> bool {
60+ matches ! ( self , ThreadStatusInner :: New | ThreadStatusInner :: Yielded )
61+ }
62+ }
63+
4564/// Handle to an internal Lua thread (coroutine).
4665#[ derive( Clone ) ]
4766pub struct Thread ( pub ( crate ) ValueRef , pub ( crate ) * mut ffi:: lua_State ) ;
@@ -122,7 +141,7 @@ impl Thread {
122141 R : FromLuaMulti ,
123142 {
124143 let lua = self . 0 . lua . lock ( ) ;
125- if self . status_inner ( & lua) != ThreadStatus :: Resumable {
144+ if ! self . status_inner ( & lua) . is_resumable ( ) {
126145 return Err ( Error :: CoroutineUnresumable ) ;
127146 }
128147
@@ -170,23 +189,27 @@ impl Thread {
170189
171190 /// Gets the status of the thread.
172191 pub fn status ( & self ) -> ThreadStatus {
173- self . status_inner ( & self . 0 . lua . lock ( ) )
192+ match self . status_inner ( & self . 0 . lua . lock ( ) ) {
193+ ThreadStatusInner :: New | ThreadStatusInner :: Yielded => ThreadStatus :: Resumable ,
194+ ThreadStatusInner :: Running => ThreadStatus :: Running ,
195+ ThreadStatusInner :: Finished => ThreadStatus :: Finished ,
196+ ThreadStatusInner :: Error => ThreadStatus :: Error ,
197+ }
174198 }
175199
176200 /// Gets the status of the thread (internal implementation).
177- pub ( crate ) fn status_inner ( & self , lua : & RawLua ) -> ThreadStatus {
201+ fn status_inner ( & self , lua : & RawLua ) -> ThreadStatusInner {
178202 let thread_state = self . state ( ) ;
179203 if thread_state == lua. state ( ) {
180204 // The thread is currently running
181- return ThreadStatus :: Running ;
205+ return ThreadStatusInner :: Running ;
182206 }
183207 let status = unsafe { ffi:: lua_status ( thread_state) } ;
184- if status != ffi:: LUA_OK && status != ffi:: LUA_YIELD {
185- ThreadStatus :: Error
186- } else if status == ffi:: LUA_YIELD || unsafe { ffi:: lua_gettop ( thread_state) > 0 } {
187- ThreadStatus :: Resumable
188- } else {
189- ThreadStatus :: Finished
208+ match status {
209+ ffi:: LUA_YIELD => ThreadStatusInner :: Yielded ,
210+ ffi:: LUA_OK if unsafe { ffi:: lua_gettop ( thread_state) } > 0 => ThreadStatusInner :: New ,
211+ ffi:: LUA_OK => ThreadStatusInner :: Finished ,
212+ _ => ThreadStatusInner :: Error ,
190213 }
191214 }
192215
@@ -198,7 +221,7 @@ impl Thread {
198221 #[ cfg_attr( docsrs, doc( cfg( not( feature = "luau" ) ) ) ) ]
199222 pub fn set_hook < F > ( & self , triggers : HookTriggers , callback : F )
200223 where
201- F : Fn ( & Lua , Debug ) -> Result < crate :: VmState > + MaybeSend + ' static ,
224+ F : Fn ( & crate :: Lua , Debug ) -> Result < crate :: VmState > + MaybeSend + ' static ,
202225 {
203226 let lua = self . 0 . lua . lock ( ) ;
204227 unsafe {
@@ -215,32 +238,37 @@ impl Thread {
215238 /// In Luau: resets to the initial state of a newly created Lua thread.
216239 /// Lua threads in arbitrary states (like yielded or errored) can be reset properly.
217240 ///
218- /// Sets a Lua function for the thread afterwards .
241+ /// Other Lua versions can reset only new or finished threads .
219242 ///
220- /// Requires `feature = "lua54"` OR `feature = "luau"` .
243+ /// Sets a Lua function for the thread afterwards .
221244 ///
222245 /// [Lua 5.4]: https://www.lua.org/manual/5.4/manual.html#lua_closethread
223- #[ cfg( any( feature = "lua54" , feature = "luau" ) ) ]
224- #[ cfg_attr( docsrs, doc( cfg( any( feature = "lua54" , feature = "luau" ) ) ) ) ]
225- pub fn reset ( & self , func : crate :: function:: Function ) -> Result < ( ) > {
246+ pub fn reset ( & self , func : Function ) -> Result < ( ) > {
226247 let lua = self . 0 . lua . lock ( ) ;
227- if self . status_inner ( & lua) == ThreadStatus :: Running {
228- return Err ( Error :: runtime ( "cannot reset a running thread" ) ) ;
248+ let thread_state = self . state ( ) ;
249+ match self . status_inner ( & lua) {
250+ ThreadStatusInner :: Running => return Err ( Error :: runtime ( "cannot reset a running thread" ) ) ,
251+ // Any Lua can reuse new or finished thread
252+ ThreadStatusInner :: New => unsafe { ffi:: lua_settop ( thread_state, 0 ) } ,
253+ ThreadStatusInner :: Finished => { }
254+ #[ cfg( not( any( feature = "lua54" , feature = "luau" ) ) ) ]
255+ _ => return Err ( Error :: runtime ( "cannot reset non-finished thread" ) ) ,
256+ #[ cfg( any( feature = "lua54" , feature = "luau" ) ) ]
257+ _ => unsafe {
258+ #[ cfg( all( feature = "lua54" , not( feature = "vendored" ) ) ) ]
259+ let status = ffi:: lua_resetthread ( thread_state) ;
260+ #[ cfg( all( feature = "lua54" , feature = "vendored" ) ) ]
261+ let status = ffi:: lua_closethread ( thread_state, lua. state ( ) ) ;
262+ #[ cfg( feature = "lua54" ) ]
263+ if status != ffi:: LUA_OK {
264+ return Err ( pop_error ( thread_state, status) ) ;
265+ }
266+ #[ cfg( feature = "luau" ) ]
267+ ffi:: lua_resetthread ( thread_state) ;
268+ } ,
229269 }
230270
231- let thread_state = self . state ( ) ;
232271 unsafe {
233- #[ cfg( all( feature = "lua54" , not( feature = "vendored" ) ) ) ]
234- let status = ffi:: lua_resetthread ( thread_state) ;
235- #[ cfg( all( feature = "lua54" , feature = "vendored" ) ) ]
236- let status = ffi:: lua_closethread ( thread_state, lua. state ( ) ) ;
237- #[ cfg( feature = "lua54" ) ]
238- if status != ffi:: LUA_OK {
239- return Err ( pop_error ( thread_state, status) ) ;
240- }
241- #[ cfg( feature = "luau" ) ]
242- ffi:: lua_resetthread ( thread_state) ;
243-
244272 // Push function to the top of the thread stack
245273 ffi:: lua_xpush ( lua. ref_thread ( ) , thread_state, func. 0 . index ) ;
246274
@@ -393,30 +421,19 @@ impl LuaType for Thread {
393421
394422#[ cfg( feature = "async" ) ]
395423impl < A , R > AsyncThread < A , R > {
396- #[ inline]
424+ #[ inline( always ) ]
397425 pub ( crate ) fn set_recyclable ( & mut self , recyclable : bool ) {
398426 self . recycle = recyclable;
399427 }
400428}
401429
402430#[ cfg( feature = "async" ) ]
403- #[ cfg( any( feature = "lua54" , feature = "luau" ) ) ]
404431impl < A , R > Drop for AsyncThread < A , R > {
405432 fn drop ( & mut self ) {
406433 if self . recycle {
407434 if let Some ( lua) = self . thread . 0 . lua . try_lock ( ) {
408- unsafe {
409- // For Lua 5.4 this also closes all pending to-be-closed variables
410- if !lua. recycle_thread ( & mut self . thread ) {
411- #[ cfg( feature = "lua54" ) ]
412- if self . thread . status_inner ( & lua) == ThreadStatus :: Error {
413- #[ cfg( not( feature = "vendored" ) ) ]
414- ffi:: lua_resetthread ( self . thread . state ( ) ) ;
415- #[ cfg( feature = "vendored" ) ]
416- ffi:: lua_closethread ( self . thread . state ( ) , lua. state ( ) ) ;
417- }
418- }
419- }
435+ // For Lua 5.4 this also closes all pending to-be-closed variables
436+ unsafe { lua. recycle_thread ( & mut self . thread ) } ;
420437 }
421438 }
422439 }
@@ -428,7 +445,7 @@ impl<A: IntoLuaMulti, R: FromLuaMulti> Stream for AsyncThread<A, R> {
428445
429446 fn poll_next ( self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Option < Self :: Item > > {
430447 let lua = self . thread . 0 . lua . lock ( ) ;
431- if self . thread . status_inner ( & lua) != ThreadStatus :: Resumable {
448+ if ! self . thread . status_inner ( & lua) . is_resumable ( ) {
432449 return Poll :: Ready ( None ) ;
433450 }
434451
@@ -466,7 +483,7 @@ impl<A: IntoLuaMulti, R: FromLuaMulti> Future for AsyncThread<A, R> {
466483
467484 fn poll ( self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Self :: Output > {
468485 let lua = self . thread . 0 . lua . lock ( ) ;
469- if self . thread . status_inner ( & lua) != ThreadStatus :: Resumable {
486+ if ! self . thread . status_inner ( & lua) . is_resumable ( ) {
470487 return Poll :: Ready ( Err ( Error :: CoroutineUnresumable ) ) ;
471488 }
472489
@@ -506,7 +523,7 @@ impl<A: IntoLuaMulti, R: FromLuaMulti> Future for AsyncThread<A, R> {
506523#[ cfg( feature = "async" ) ]
507524#[ inline( always) ]
508525unsafe fn is_poll_pending ( state : * mut ffi:: lua_State ) -> bool {
509- ffi:: lua_tolightuserdata ( state, -1 ) == Lua :: poll_pending ( ) . 0
526+ ffi:: lua_tolightuserdata ( state, -1 ) == crate :: Lua :: poll_pending ( ) . 0
510527}
511528
512529#[ cfg( feature = "async" ) ]
0 commit comments