mlua/
function.rs

1use std::cell::RefCell;
2use std::os::raw::{c_int, c_void};
3use std::{mem, ptr, slice};
4
5use crate::error::{Error, Result};
6use crate::state::Lua;
7use crate::table::Table;
8use crate::traits::{FromLuaMulti, IntoLua, IntoLuaMulti, LuaNativeFn, LuaNativeFnMut};
9use crate::types::{Callback, LuaType, MaybeSend, ValueRef};
10use crate::util::{
11    assert_stack, check_stack, linenumber_to_usize, pop_error, ptr_to_lossy_str, ptr_to_str, StackGuard,
12};
13use crate::value::Value;
14
15#[cfg(feature = "async")]
16use {
17    crate::thread::AsyncThread,
18    crate::traits::LuaNativeAsyncFn,
19    crate::types::AsyncCallback,
20    std::future::{self, Future},
21    std::pin::{pin, Pin},
22    std::task::{Context, Poll},
23};
24
25/// Handle to an internal Lua function.
26#[derive(Clone, Debug, PartialEq)]
27pub struct Function(pub(crate) ValueRef);
28
29/// Contains information about a function.
30///
31/// Please refer to the [`Lua Debug Interface`] for more information.
32///
33/// [`Lua Debug Interface`]: https://www.lua.org/manual/5.4/manual.html#4.7
34#[derive(Clone, Debug)]
35pub struct FunctionInfo {
36    /// A (reasonable) name of the function (`None` if the name cannot be found).
37    pub name: Option<String>,
38    /// Explains the `name` field (can be `global`/`local`/`method`/`field`/`upvalue`/etc).
39    ///
40    /// Always `None` for Luau.
41    pub name_what: Option<&'static str>,
42    /// A string `Lua` if the function is a Lua function, `C` if it is a C function, `main` if it is
43    /// the main part of a chunk.
44    pub what: &'static str,
45    /// Source of the chunk that created the function.
46    pub source: Option<String>,
47    /// A "printable" version of `source`, to be used in error messages.
48    pub short_src: Option<String>,
49    /// The line number where the definition of the function starts.
50    pub line_defined: Option<usize>,
51    /// The line number where the definition of the function ends (not set by Luau).
52    pub last_line_defined: Option<usize>,
53}
54
55/// Luau function coverage snapshot.
56#[cfg(any(feature = "luau", doc))]
57#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
58#[derive(Clone, Debug, PartialEq, Eq)]
59pub struct CoverageInfo {
60    pub function: Option<String>,
61    pub line_defined: i32,
62    pub depth: i32,
63    pub hits: Vec<i32>,
64}
65
66impl Function {
67    /// Calls the function, passing `args` as function arguments.
68    ///
69    /// The function's return values are converted to the generic type `R`.
70    ///
71    /// # Examples
72    ///
73    /// Call Lua's built-in `tostring` function:
74    ///
75    /// ```
76    /// # use mlua::{Function, Lua, Result};
77    /// # fn main() -> Result<()> {
78    /// # let lua = Lua::new();
79    /// let globals = lua.globals();
80    ///
81    /// let tostring: Function = globals.get("tostring")?;
82    ///
83    /// assert_eq!(tostring.call::<String>(123)?, "123");
84    ///
85    /// # Ok(())
86    /// # }
87    /// ```
88    ///
89    /// Call a function with multiple arguments:
90    ///
91    /// ```
92    /// # use mlua::{Function, Lua, Result};
93    /// # fn main() -> Result<()> {
94    /// # let lua = Lua::new();
95    /// let sum: Function = lua.load(
96    ///     r#"
97    ///         function(a, b)
98    ///             return a + b
99    ///         end
100    /// "#).eval()?;
101    ///
102    /// assert_eq!(sum.call::<u32>((3, 4))?, 3 + 4);
103    ///
104    /// # Ok(())
105    /// # }
106    /// ```
107    pub fn call<R: FromLuaMulti>(&self, args: impl IntoLuaMulti) -> Result<R> {
108        let lua = self.0.lua.lock();
109        let state = lua.state();
110        unsafe {
111            let _sg = StackGuard::new(state);
112            check_stack(state, 2)?;
113
114            // Push error handler
115            lua.push_error_traceback();
116            let stack_start = ffi::lua_gettop(state);
117            // Push function and the arguments
118            lua.push_ref(&self.0);
119            let nargs = args.push_into_stack_multi(&lua)?;
120            // Call the function
121            let ret = ffi::lua_pcall(state, nargs, ffi::LUA_MULTRET, stack_start);
122            if ret != ffi::LUA_OK {
123                return Err(pop_error(state, ret));
124            }
125            // Get the results
126            let nresults = ffi::lua_gettop(state) - stack_start;
127            R::from_stack_multi(nresults, &lua)
128        }
129    }
130
131    /// Returns a future that, when polled, calls `self`, passing `args` as function arguments,
132    /// and drives the execution.
133    ///
134    /// Internally it wraps the function to an [`AsyncThread`]. The returned type implements
135    /// `Future<Output = Result<R>>` and can be awaited.
136    ///
137    /// # Examples
138    ///
139    /// ```
140    /// use std::time::Duration;
141    /// # use mlua::{Lua, Result};
142    /// # #[tokio::main]
143    /// # async fn main() -> Result<()> {
144    /// # let lua = Lua::new();
145    ///
146    /// let sleep = lua.create_async_function(move |_lua, n: u64| async move {
147    ///     tokio::time::sleep(Duration::from_millis(n)).await;
148    ///     Ok(())
149    /// })?;
150    ///
151    /// sleep.call_async::<()>(10).await?;
152    ///
153    /// # Ok(())
154    /// # }
155    /// ```
156    ///
157    /// [`AsyncThread`]: crate::AsyncThread
158    #[cfg(feature = "async")]
159    #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
160    pub fn call_async<R>(&self, args: impl IntoLuaMulti) -> AsyncCallFuture<R>
161    where
162        R: FromLuaMulti,
163    {
164        let lua = self.0.lua.lock();
165        AsyncCallFuture(unsafe {
166            lua.create_recycled_thread(self).and_then(|th| {
167                let mut th = th.into_async(args)?;
168                th.set_recyclable(true);
169                Ok(th)
170            })
171        })
172    }
173
174    /// Returns a function that, when called, calls `self`, passing `args` as the first set of
175    /// arguments.
176    ///
177    /// If any arguments are passed to the returned function, they will be passed after `args`.
178    ///
179    /// # Examples
180    ///
181    /// ```
182    /// # use mlua::{Function, Lua, Result};
183    /// # fn main() -> Result<()> {
184    /// # let lua = Lua::new();
185    /// let sum: Function = lua.load(
186    ///     r#"
187    ///         function(a, b)
188    ///             return a + b
189    ///         end
190    /// "#).eval()?;
191    ///
192    /// let bound_a = sum.bind(1)?;
193    /// assert_eq!(bound_a.call::<u32>(2)?, 1 + 2);
194    ///
195    /// let bound_a_and_b = sum.bind(13)?.bind(57)?;
196    /// assert_eq!(bound_a_and_b.call::<u32>(())?, 13 + 57);
197    ///
198    /// # Ok(())
199    /// # }
200    /// ```
201    pub fn bind(&self, args: impl IntoLuaMulti) -> Result<Function> {
202        unsafe extern "C-unwind" fn args_wrapper_impl(state: *mut ffi::lua_State) -> c_int {
203            let nargs = ffi::lua_gettop(state);
204            let nbinds = ffi::lua_tointeger(state, ffi::lua_upvalueindex(1)) as c_int;
205            ffi::luaL_checkstack(state, nbinds, ptr::null());
206
207            for i in 0..nbinds {
208                ffi::lua_pushvalue(state, ffi::lua_upvalueindex(i + 2));
209            }
210            if nargs > 0 {
211                ffi::lua_rotate(state, 1, nbinds);
212            }
213
214            nargs + nbinds
215        }
216
217        let lua = self.0.lua.lock();
218        let state = lua.state();
219
220        let args = args.into_lua_multi(lua.lua())?;
221        let nargs = args.len() as c_int;
222
223        if nargs == 0 {
224            return Ok(self.clone());
225        }
226
227        if nargs + 1 > ffi::LUA_MAX_UPVALUES {
228            return Err(Error::BindError);
229        }
230
231        let args_wrapper = unsafe {
232            let _sg = StackGuard::new(state);
233            check_stack(state, nargs + 3)?;
234
235            ffi::lua_pushinteger(state, nargs as ffi::lua_Integer);
236            for arg in &args {
237                lua.push_value(arg)?;
238            }
239            protect_lua!(state, nargs + 1, 1, fn(state) {
240                ffi::lua_pushcclosure(state, args_wrapper_impl, ffi::lua_gettop(state));
241            })?;
242
243            Function(lua.pop_ref())
244        };
245
246        let lua = lua.lua();
247        lua.load(
248            r#"
249            local func, args_wrapper = ...
250            return function(...)
251                return func(args_wrapper(...))
252            end
253            "#,
254        )
255        .try_cache()
256        .set_name("=__mlua_bind")
257        .call((self, args_wrapper))
258    }
259
260    /// Returns the environment of the Lua function.
261    ///
262    /// By default Lua functions shares a global environment.
263    ///
264    /// This function always returns `None` for Rust/C functions.
265    pub fn environment(&self) -> Option<Table> {
266        let lua = self.0.lua.lock();
267        let state = lua.state();
268        unsafe {
269            let _sg = StackGuard::new(state);
270            assert_stack(state, 1);
271
272            lua.push_ref(&self.0);
273            if ffi::lua_iscfunction(state, -1) != 0 {
274                return None;
275            }
276
277            #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
278            ffi::lua_getfenv(state, -1);
279            #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
280            for i in 1..=255 {
281                // Traverse upvalues until we find the _ENV one
282                match ffi::lua_getupvalue(state, -1, i) {
283                    s if s.is_null() => break,
284                    s if std::ffi::CStr::from_ptr(s as _) == c"_ENV" => break,
285                    _ => ffi::lua_pop(state, 1),
286                }
287            }
288
289            if ffi::lua_type(state, -1) != ffi::LUA_TTABLE {
290                return None;
291            }
292            Some(Table(lua.pop_ref()))
293        }
294    }
295
296    /// Sets the environment of the Lua function.
297    ///
298    /// The environment is a table that is used as the global environment for the function.
299    /// Returns `true` if environment successfully changed, `false` otherwise.
300    ///
301    /// This function does nothing for Rust/C functions.
302    pub fn set_environment(&self, env: Table) -> Result<bool> {
303        let lua = self.0.lua.lock();
304        let state = lua.state();
305        unsafe {
306            let _sg = StackGuard::new(state);
307            check_stack(state, 2)?;
308
309            lua.push_ref(&self.0);
310            if ffi::lua_iscfunction(state, -1) != 0 {
311                return Ok(false);
312            }
313
314            #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
315            {
316                lua.push_ref(&env.0);
317                ffi::lua_setfenv(state, -2);
318            }
319            #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
320            for i in 1..=255 {
321                match ffi::lua_getupvalue(state, -1, i) {
322                    s if s.is_null() => return Ok(false),
323                    s if std::ffi::CStr::from_ptr(s as _) == c"_ENV" => {
324                        ffi::lua_pop(state, 1);
325                        // Create an anonymous function with the new environment
326                        let f_with_env = lua
327                            .lua()
328                            .load("return _ENV")
329                            .set_environment(env)
330                            .try_cache()
331                            .into_function()?;
332                        lua.push_ref(&f_with_env.0);
333                        ffi::lua_upvaluejoin(state, -2, i, -1, 1);
334                        break;
335                    }
336                    _ => ffi::lua_pop(state, 1),
337                }
338            }
339
340            Ok(true)
341        }
342    }
343
344    /// Returns information about the function.
345    ///
346    /// Corresponds to the `>Sn` what mask for [`lua_getinfo`] when applied to the function.
347    ///
348    /// [`lua_getinfo`]: https://www.lua.org/manual/5.4/manual.html#lua_getinfo
349    pub fn info(&self) -> FunctionInfo {
350        let lua = self.0.lua.lock();
351        let state = lua.state();
352        unsafe {
353            let _sg = StackGuard::new(state);
354            assert_stack(state, 1);
355
356            let mut ar: ffi::lua_Debug = mem::zeroed();
357            lua.push_ref(&self.0);
358            #[cfg(not(feature = "luau"))]
359            let res = ffi::lua_getinfo(state, cstr!(">Sn"), &mut ar);
360            #[cfg(feature = "luau")]
361            let res = ffi::lua_getinfo(state, -1, cstr!("sn"), &mut ar);
362            mlua_assert!(res != 0, "lua_getinfo failed with `>Sn`");
363
364            FunctionInfo {
365                name: ptr_to_lossy_str(ar.name).map(|s| s.into_owned()),
366                #[cfg(not(feature = "luau"))]
367                name_what: match ptr_to_str(ar.namewhat) {
368                    Some("") => None,
369                    val => val,
370                },
371                #[cfg(feature = "luau")]
372                name_what: None,
373                what: ptr_to_str(ar.what).unwrap_or("main"),
374                source: ptr_to_lossy_str(ar.source).map(|s| s.into_owned()),
375                #[cfg(not(feature = "luau"))]
376                short_src: ptr_to_lossy_str(ar.short_src.as_ptr()).map(|s| s.into_owned()),
377                #[cfg(feature = "luau")]
378                short_src: ptr_to_lossy_str(ar.short_src).map(|s| s.into_owned()),
379                line_defined: linenumber_to_usize(ar.linedefined),
380                #[cfg(not(feature = "luau"))]
381                last_line_defined: linenumber_to_usize(ar.lastlinedefined),
382                #[cfg(feature = "luau")]
383                last_line_defined: None,
384            }
385        }
386    }
387
388    /// Dumps the function as a binary chunk.
389    ///
390    /// If `strip` is true, the binary representation may not include all debug information
391    /// about the function, to save space.
392    ///
393    /// For Luau a [`Compiler`] can be used to compile Lua chunks to bytecode.
394    ///
395    /// [`Compiler`]: crate::chunk::Compiler
396    #[cfg(not(feature = "luau"))]
397    #[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
398    pub fn dump(&self, strip: bool) -> Vec<u8> {
399        unsafe extern "C-unwind" fn writer(
400            _state: *mut ffi::lua_State,
401            buf: *const c_void,
402            buf_len: usize,
403            data: *mut c_void,
404        ) -> c_int {
405            let data = &mut *(data as *mut Vec<u8>);
406            let buf = slice::from_raw_parts(buf as *const u8, buf_len);
407            data.extend_from_slice(buf);
408            0
409        }
410
411        let lua = self.0.lua.lock();
412        let state = lua.state();
413        let mut data: Vec<u8> = Vec::new();
414        unsafe {
415            let _sg = StackGuard::new(state);
416            assert_stack(state, 1);
417
418            lua.push_ref(&self.0);
419            let data_ptr = &mut data as *mut Vec<u8> as *mut c_void;
420            ffi::lua_dump(state, writer, data_ptr, strip as i32);
421            ffi::lua_pop(state, 1);
422        }
423
424        data
425    }
426
427    /// Retrieves recorded coverage information about this Lua function including inner calls.
428    ///
429    /// This function takes a callback as an argument and calls it providing [`CoverageInfo`]
430    /// snapshot per each executed inner function.
431    ///
432    /// Recording of coverage information is controlled by [`Compiler::set_coverage_level`] option.
433    ///
434    /// [`Compiler::set_coverage_level`]: crate::chunk::Compiler::set_coverage_level
435    #[cfg(any(feature = "luau", doc))]
436    #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
437    pub fn coverage<F>(&self, func: F)
438    where
439        F: FnMut(CoverageInfo),
440    {
441        use std::ffi::CStr;
442        use std::os::raw::c_char;
443
444        unsafe extern "C-unwind" fn callback<F: FnMut(CoverageInfo)>(
445            data: *mut c_void,
446            function: *const c_char,
447            line_defined: c_int,
448            depth: c_int,
449            hits: *const c_int,
450            size: usize,
451        ) {
452            let function = if !function.is_null() {
453                Some(CStr::from_ptr(function).to_string_lossy().to_string())
454            } else {
455                None
456            };
457            let rust_callback = &*(data as *const RefCell<F>);
458            if let Ok(mut rust_callback) = rust_callback.try_borrow_mut() {
459                // Call the Rust callback with CoverageInfo
460                rust_callback(CoverageInfo {
461                    function,
462                    line_defined,
463                    depth,
464                    hits: slice::from_raw_parts(hits, size).to_vec(),
465                });
466            }
467        }
468
469        let lua = self.0.lua.lock();
470        let state = lua.state();
471        unsafe {
472            let _sg = StackGuard::new(state);
473            assert_stack(state, 1);
474
475            lua.push_ref(&self.0);
476            let func = RefCell::new(func);
477            let func_ptr = &func as *const RefCell<F> as *mut c_void;
478            ffi::lua_getcoverage(state, -1, func_ptr, callback::<F>);
479        }
480    }
481
482    /// Converts this function to a generic C pointer.
483    ///
484    /// There is no way to convert the pointer back to its original value.
485    ///
486    /// Typically this function is used only for hashing and debug information.
487    #[inline]
488    pub fn to_pointer(&self) -> *const c_void {
489        self.0.to_pointer()
490    }
491
492    /// Creates a deep clone of the Lua function.
493    ///
494    /// Copies the function prototype and all its upvalues to the
495    /// newly created function.
496    /// This function returns shallow clone (same handle) for Rust/C functions.
497    #[cfg(any(feature = "luau", doc))]
498    #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
499    pub fn deep_clone(&self) -> Result<Self> {
500        let lua = self.0.lua.lock();
501        let state = lua.state();
502        unsafe {
503            let _sg = StackGuard::new(state);
504            check_stack(state, 2)?;
505
506            lua.push_ref(&self.0);
507            if ffi::lua_iscfunction(state, -1) != 0 {
508                return Ok(self.clone());
509            }
510
511            if lua.unlikely_memory_error() {
512                ffi::lua_clonefunction(state, -1);
513            } else {
514                protect_lua!(state, 1, 1, fn(state) ffi::lua_clonefunction(state, -1))?;
515            }
516            Ok(Function(lua.pop_ref()))
517        }
518    }
519}
520
521struct WrappedFunction(pub(crate) Callback);
522
523#[cfg(feature = "async")]
524struct WrappedAsyncFunction(pub(crate) AsyncCallback);
525
526impl Function {
527    /// Wraps a Rust function or closure, returning an opaque type that implements [`IntoLua`]
528    /// trait.
529    #[inline]
530    pub fn wrap<F, A, R>(func: F) -> impl IntoLua
531    where
532        F: LuaNativeFn<A, Output = Result<R>> + MaybeSend + 'static,
533        A: FromLuaMulti,
534        R: IntoLuaMulti,
535    {
536        WrappedFunction(Box::new(move |lua, nargs| unsafe {
537            let args = A::from_stack_args(nargs, 1, None, lua)?;
538            func.call(args)?.push_into_stack_multi(lua)
539        }))
540    }
541
542    /// Wraps a Rust mutable closure, returning an opaque type that implements [`IntoLua`] trait.
543    pub fn wrap_mut<F, A, R>(func: F) -> impl IntoLua
544    where
545        F: LuaNativeFnMut<A, Output = Result<R>> + MaybeSend + 'static,
546        A: FromLuaMulti,
547        R: IntoLuaMulti,
548    {
549        let func = RefCell::new(func);
550        WrappedFunction(Box::new(move |lua, nargs| unsafe {
551            let mut func = func.try_borrow_mut().map_err(|_| Error::RecursiveMutCallback)?;
552            let args = A::from_stack_args(nargs, 1, None, lua)?;
553            func.call(args)?.push_into_stack_multi(lua)
554        }))
555    }
556
557    /// Wraps a Rust function or closure, returning an opaque type that implements [`IntoLua`]
558    /// trait.
559    ///
560    /// This function is similar to [`Function::wrap`] but any returned `Result` will be converted
561    /// to a `ok, err` tuple without throwing an exception.
562    #[inline]
563    pub fn wrap_raw<F, A>(func: F) -> impl IntoLua
564    where
565        F: LuaNativeFn<A> + MaybeSend + 'static,
566        A: FromLuaMulti,
567    {
568        WrappedFunction(Box::new(move |lua, nargs| unsafe {
569            let args = A::from_stack_args(nargs, 1, None, lua)?;
570            func.call(args).push_into_stack_multi(lua)
571        }))
572    }
573
574    /// Wraps a Rust mutable closure, returning an opaque type that implements [`IntoLua`] trait.
575    ///
576    /// This function is similar to [`Function::wrap_mut`] but any returned `Result` will be
577    /// converted to a `ok, err` tuple without throwing an exception.
578    #[inline]
579    pub fn wrap_raw_mut<F, A>(func: F) -> impl IntoLua
580    where
581        F: LuaNativeFnMut<A> + MaybeSend + 'static,
582        A: FromLuaMulti,
583    {
584        let func = RefCell::new(func);
585        WrappedFunction(Box::new(move |lua, nargs| unsafe {
586            let mut func = func.try_borrow_mut().map_err(|_| Error::RecursiveMutCallback)?;
587            let args = A::from_stack_args(nargs, 1, None, lua)?;
588            func.call(args).push_into_stack_multi(lua)
589        }))
590    }
591
592    /// Wraps a Rust async function or closure, returning an opaque type that implements [`IntoLua`]
593    /// trait.
594    #[cfg(feature = "async")]
595    #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
596    pub fn wrap_async<F, A, R>(func: F) -> impl IntoLua
597    where
598        F: LuaNativeAsyncFn<A, Output = Result<R>> + MaybeSend + 'static,
599        A: FromLuaMulti,
600        R: IntoLuaMulti,
601    {
602        WrappedAsyncFunction(Box::new(move |rawlua, nargs| unsafe {
603            let args = match A::from_stack_args(nargs, 1, None, rawlua) {
604                Ok(args) => args,
605                Err(e) => return Box::pin(future::ready(Err(e))),
606            };
607            let lua = rawlua.lua();
608            let fut = func.call(args);
609            Box::pin(async move { fut.await?.push_into_stack_multi(lua.raw_lua()) })
610        }))
611    }
612
613    /// Wraps a Rust async function or closure, returning an opaque type that implements [`IntoLua`]
614    /// trait.
615    ///
616    /// This function is similar to [`Function::wrap_async`] but any returned `Result` will be
617    /// converted to a `ok, err` tuple without throwing an exception.
618    #[cfg(feature = "async")]
619    #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
620    pub fn wrap_raw_async<F, A>(func: F) -> impl IntoLua
621    where
622        F: LuaNativeAsyncFn<A> + MaybeSend + 'static,
623        A: FromLuaMulti,
624    {
625        WrappedAsyncFunction(Box::new(move |rawlua, nargs| unsafe {
626            let args = match A::from_stack_args(nargs, 1, None, rawlua) {
627                Ok(args) => args,
628                Err(e) => return Box::pin(future::ready(Err(e))),
629            };
630            let lua = rawlua.lua();
631            let fut = func.call(args);
632            Box::pin(async move { fut.await.push_into_stack_multi(lua.raw_lua()) })
633        }))
634    }
635}
636
637impl IntoLua for WrappedFunction {
638    #[inline]
639    fn into_lua(self, lua: &Lua) -> Result<Value> {
640        lua.lock().create_callback(self.0).map(Value::Function)
641    }
642}
643
644#[cfg(feature = "async")]
645impl IntoLua for WrappedAsyncFunction {
646    #[inline]
647    fn into_lua(self, lua: &Lua) -> Result<Value> {
648        lua.lock().create_async_callback(self.0).map(Value::Function)
649    }
650}
651
652impl LuaType for Function {
653    const TYPE_ID: c_int = ffi::LUA_TFUNCTION;
654}
655
656#[cfg(feature = "async")]
657#[must_use = "futures do nothing unless you `.await` or poll them"]
658pub struct AsyncCallFuture<R: FromLuaMulti>(Result<AsyncThread<R>>);
659
660#[cfg(feature = "async")]
661impl<R: FromLuaMulti> AsyncCallFuture<R> {
662    pub(crate) fn error(err: Error) -> Self {
663        AsyncCallFuture(Err(err))
664    }
665}
666
667#[cfg(feature = "async")]
668impl<R: FromLuaMulti> Future for AsyncCallFuture<R> {
669    type Output = Result<R>;
670
671    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
672        let this = self.get_mut();
673        match &mut this.0 {
674            Ok(thread) => pin!(thread).poll(cx),
675            Err(err) => Poll::Ready(Err(err.clone())),
676        }
677    }
678}
679
680#[cfg(test)]
681mod assertions {
682    use super::*;
683
684    #[cfg(not(feature = "send"))]
685    static_assertions::assert_not_impl_any!(Function: Send);
686    #[cfg(feature = "send")]
687    static_assertions::assert_impl_all!(Function: Send, Sync);
688
689    #[cfg(all(feature = "async", feature = "send"))]
690    static_assertions::assert_impl_all!(AsyncCallFuture<()>: Send);
691}