@@ -37,6 +37,7 @@ use crate::{buffer::Buffer, chunk::Compiler};
37
37
use {
38
38
crate :: types:: LightUserData ,
39
39
std:: future:: { self , Future } ,
40
+ std:: task:: Poll ,
40
41
} ;
41
42
42
43
#[ cfg( feature = "serde" ) ]
@@ -2079,6 +2080,101 @@ impl Lua {
2079
2080
LightUserData ( & ASYNC_POLL_TERMINATE as * const u8 as * mut std:: os:: raw:: c_void )
2080
2081
}
2081
2082
2083
+ #[ cfg( feature = "async" ) ]
2084
+ #[ inline( always) ]
2085
+ pub ( crate ) fn poll_yield ( ) -> LightUserData {
2086
+ static ASYNC_POLL_YIELD : u8 = 0 ;
2087
+ LightUserData ( & ASYNC_POLL_YIELD as * const u8 as * mut std:: os:: raw:: c_void )
2088
+ }
2089
+
2090
+ /// Suspends the current async function, returning the provided arguments to caller.
2091
+ ///
2092
+ /// This function is similar to [`coroutine.yield`] but allow yeilding Rust functions
2093
+ /// and passing values to the caller.
2094
+ /// Please note that you cannot cross [`Thread`] boundaries (e.g. calling `yield_with` on one
2095
+ /// thread and resuming on another).
2096
+ ///
2097
+ /// # Examples
2098
+ ///
2099
+ /// Async iterator:
2100
+ ///
2101
+ /// ```
2102
+ /// # use mlua::{Lua, Result};
2103
+ ///
2104
+ /// async fn generator(lua: Lua, _: ()) -> Result<()> {
2105
+ /// for i in 0..10 {
2106
+ /// lua.yield_with::<()>(i).await?;
2107
+ /// }
2108
+ /// Ok(())
2109
+ /// }
2110
+ ///
2111
+ /// fn main() -> Result<()> {
2112
+ /// let lua = Lua::new();
2113
+ /// lua.globals().set("generator", lua.create_async_function(generator)?)?;
2114
+ ///
2115
+ /// lua.load(r#"
2116
+ /// local n = 0
2117
+ /// for i in coroutine.wrap(generator) do
2118
+ /// n = n + i
2119
+ /// end
2120
+ /// assert(n == 45)
2121
+ /// "#)
2122
+ /// .exec()
2123
+ /// }
2124
+ /// ```
2125
+ ///
2126
+ /// Exchange values on yield:
2127
+ ///
2128
+ /// ```
2129
+ /// # use mlua::{Lua, Result, Value};
2130
+ ///
2131
+ /// async fn pingpong(lua: Lua, mut val: i32) -> Result<()> {
2132
+ /// loop {
2133
+ /// val = lua.yield_with::<i32>(val).await? + 1;
2134
+ /// }
2135
+ /// Ok(())
2136
+ /// }
2137
+ ///
2138
+ /// # fn main() -> Result<()> {
2139
+ /// let lua = Lua::new();
2140
+ ///
2141
+ /// let co = lua.create_thread(lua.create_async_function(pingpong)?)?;
2142
+ /// assert_eq!(co.resume::<i32>(1)?, 1);
2143
+ /// assert_eq!(co.resume::<i32>(2)?, 3);
2144
+ /// assert_eq!(co.resume::<i32>(3)?, 4);
2145
+ ///
2146
+ /// # Ok(())
2147
+ /// # }
2148
+ /// ```
2149
+ ///
2150
+ /// [`coroutine.yield`]: https://www.lua.org/manual/5.4/manual.html#pdf-coroutine.yield
2151
+ #[ cfg( feature = "async" ) ]
2152
+ #[ cfg_attr( docsrs, doc( cfg( feature = "async" ) ) ) ]
2153
+ pub async fn yield_with < R : FromLuaMulti > ( & self , args : impl IntoLuaMulti ) -> Result < R > {
2154
+ let mut args = Some ( args. into_lua_multi ( self ) ?) ;
2155
+ future:: poll_fn ( move |_cx| match args. take ( ) {
2156
+ Some ( args) => unsafe {
2157
+ let lua = self . lock ( ) ;
2158
+ lua. push ( Self :: poll_yield ( ) ) ?; // yield marker
2159
+ if args. len ( ) <= 1 {
2160
+ lua. push ( args. front ( ) ) ?;
2161
+ } else {
2162
+ lua. push ( lua. create_sequence_from ( & args) ?) ?;
2163
+ }
2164
+ lua. push ( args. len ( ) ) ?;
2165
+ Poll :: Pending
2166
+ } ,
2167
+ None => unsafe {
2168
+ let lua = self . lock ( ) ;
2169
+ let state = lua. state ( ) ;
2170
+ let _sg = StackGuard :: with_top ( state, 0 ) ;
2171
+ let nvals = ffi:: lua_gettop ( state) ;
2172
+ Poll :: Ready ( R :: from_stack_multi ( nvals, & lua) )
2173
+ } ,
2174
+ } )
2175
+ . await
2176
+ }
2177
+
2082
2178
/// Returns a weak reference to the Lua instance.
2083
2179
///
2084
2180
/// This is useful for creating a reference to the Lua instance that does not prevent it from
0 commit comments