Skip to main content

mlua/
function.rs

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