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.try_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        self.try_dump(strip).expect("cannot dump function")
498    }
499
500    // Like `dump`, but returns an error if stack growth or dumping fails.
501    #[cfg(not(feature = "luau"))]
502    pub(crate) fn try_dump(&self, strip: bool) -> Result<Vec<u8>> {
503        unsafe extern "C-unwind" fn writer(
504            _state: *mut ffi::lua_State,
505            buf: *const c_void,
506            buf_len: usize,
507            data_ptr: *mut c_void,
508        ) -> c_int {
509            // If `data` is null, then it's a signal that write is finished.
510            if !data_ptr.is_null() && buf_len > 0 {
511                let data = &mut *(data_ptr as *mut Vec<u8>);
512                let buf = slice::from_raw_parts(buf as *const u8, buf_len);
513                data.extend_from_slice(buf);
514            }
515            0
516        }
517
518        let lua = self.0.lua.lock();
519        let state = lua.state();
520        let mut data: Vec<u8> = Vec::new();
521        unsafe {
522            let _sg = StackGuard::new(state);
523            // Lua 5.5 allocates an auxiliary table while dumping
524            let protect = cfg!(feature = "lua55") && !lua.unlikely_memory_error();
525            check_stack(state, if protect { 4 } else { 1 })?;
526
527            lua.push_ref(&self.0);
528            if ffi::lua_iscfunction(state, -1) != 0 {
529                return Ok(data);
530            }
531            let data_ptr = &mut data as *mut Vec<u8> as *mut c_void;
532            let status = protect_lua_mem!(state, if protect, 1, 0, |state| {
533                ffi::lua_dump(state, writer, data_ptr, strip as i32)
534            })?;
535            if status != 0 {
536                return Err(pop_error(state, status));
537            }
538        }
539
540        Ok(data)
541    }
542
543    /// Retrieves recorded coverage information about this Lua function including inner calls.
544    ///
545    /// This function takes a callback as an argument and calls it providing [`CoverageInfo`]
546    /// snapshot per each executed inner function.
547    ///
548    /// Recording of coverage information is controlled by [`Compiler::set_coverage_level`] option.
549    ///
550    /// [`Compiler::set_coverage_level`]: crate::chunk::Compiler::set_coverage_level
551    #[cfg(any(feature = "luau", doc))]
552    #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
553    pub fn coverage<F>(&self, func: F)
554    where
555        F: FnMut(CoverageInfo),
556    {
557        use std::panic::{AssertUnwindSafe, catch_unwind, resume_unwind};
558
559        unsafe extern "C-unwind" fn callback<F: FnMut(CoverageInfo)>(
560            data: *mut c_void,
561            function: *const std::os::raw::c_char,
562            line_defined: c_int,
563            depth: c_int,
564            hits: *const c_int,
565            size: usize,
566        ) {
567            let rust_callback = &*(data as *const RefCell<(F, std::thread::Result<()>)>);
568            if let Ok(mut rust_callback) = rust_callback.try_borrow_mut() {
569                let (func, result) = &mut *rust_callback;
570                if result.is_ok() {
571                    *result = catch_unwind(AssertUnwindSafe(|| {
572                        func(CoverageInfo {
573                            function: ptr_to_lossy_str(function).map(|s| s.into_owned()),
574                            line_defined,
575                            depth,
576                            hits: slice::from_raw_parts(hits, size).to_vec(),
577                        });
578                    }));
579                }
580            }
581        }
582
583        let lua = self.0.lua.lock();
584        let state = lua.state();
585        unsafe {
586            let _sg = StackGuard::new(state);
587            assert_stack(state, 1);
588
589            lua.push_ref(&self.0);
590            let func: RefCell<(F, std::thread::Result<()>)> = RefCell::new((func, Ok(())));
591            let func_ptr = &func as *const _ as *mut c_void;
592            ffi::lua_getcoverage(state, -1, func_ptr, callback::<F>);
593            // Resume only after Luau has freed its coverage buffer.
594            func.into_inner().1.unwrap_or_else(|panic| resume_unwind(panic));
595        }
596    }
597
598    /// Converts this function to a generic C pointer.
599    ///
600    /// There is no way to convert the pointer back to its original value.
601    ///
602    /// Typically this function is used only for hashing and debug information.
603    #[inline]
604    pub fn to_pointer(&self) -> *const c_void {
605        self.0.to_pointer()
606    }
607
608    /// Creates a deep clone of the Lua function.
609    ///
610    /// Copies the function prototype and all its upvalues to the
611    /// newly created function.
612    /// This function returns shallow clone (same handle) for Rust/C functions.
613    #[cfg(any(feature = "luau", doc))]
614    #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
615    pub fn deep_clone(&self) -> Result<Self> {
616        let lua = self.0.lua.lock();
617        let state = lua.state();
618        unsafe {
619            let _sg = StackGuard::new(state);
620            check_stack(state, 2)?;
621
622            lua.push_ref(&self.0);
623            if ffi::lua_iscfunction(state, -1) != 0 {
624                return Ok(self.clone());
625            }
626
627            protect_lua_mem!(lua, 1, 1, fn(state) ffi::lua_clonefunction(state, -1))?;
628            Ok(Function(lua.try_pop_ref()?))
629        }
630    }
631}
632
633struct WrappedFunction(pub(crate) Callback);
634
635#[cfg(feature = "async")]
636struct WrappedAsyncFunction(pub(crate) AsyncCallback);
637
638impl Function {
639    /// Wraps a Rust function or closure, returning an opaque type that implements the [`IntoLua`]
640    /// trait.
641    #[inline]
642    pub fn wrap<F, A, R, E>(func: F) -> impl IntoLua
643    where
644        F: LuaNativeFn<A, Output = StdResult<R, E>> + MaybeSend + 'static,
645        A: FromLuaMulti,
646        R: IntoLuaMulti,
647        E: ExternalError,
648    {
649        WrappedFunction(Box::new(move |lua, nargs| unsafe {
650            let args = A::from_stack_args(nargs, 1, None, lua)?;
651            func.call(args).into_lua_err()?.push_into_stack_multi(lua)
652        }))
653    }
654
655    /// Wraps a Rust mutable closure, returning an opaque type that implements [`IntoLua`] trait.
656    pub fn wrap_mut<F, A, R, E>(func: F) -> impl IntoLua
657    where
658        F: LuaNativeFnMut<A, Output = StdResult<R, E>> + MaybeSend + 'static,
659        A: FromLuaMulti,
660        R: IntoLuaMulti,
661        E: ExternalError,
662    {
663        let func = RefCell::new(func);
664        WrappedFunction(Box::new(move |lua, nargs| unsafe {
665            let mut func = func.try_borrow_mut().map_err(|_| Error::RecursiveMutCallback)?;
666            let args = A::from_stack_args(nargs, 1, None, lua)?;
667            func.call(args).into_lua_err()?.push_into_stack_multi(lua)
668        }))
669    }
670
671    /// Wraps a Rust function or closure, returning an opaque type that implements [`IntoLua`]
672    /// trait.
673    ///
674    /// This function is similar to [`Function::wrap`] but any returned `Result` will be converted
675    /// to a `ok, err` tuple without throwing an exception.
676    #[inline]
677    pub fn wrap_raw<F, A>(func: F) -> impl IntoLua
678    where
679        F: LuaNativeFn<A> + MaybeSend + 'static,
680        F::Output: IntoLuaMulti,
681        A: FromLuaMulti,
682    {
683        WrappedFunction(Box::new(move |lua, nargs| unsafe {
684            let args = A::from_stack_args(nargs, 1, None, lua)?;
685            func.call(args).push_into_stack_multi(lua)
686        }))
687    }
688
689    /// Wraps a Rust mutable closure, returning an opaque type that implements [`IntoLua`] trait.
690    ///
691    /// This function is similar to [`Function::wrap_mut`] but any returned `Result` will be
692    /// converted to a `ok, err` tuple without throwing an exception.
693    #[inline]
694    pub fn wrap_raw_mut<F, A>(func: F) -> impl IntoLua
695    where
696        F: LuaNativeFnMut<A> + MaybeSend + 'static,
697        F::Output: IntoLuaMulti,
698        A: FromLuaMulti,
699    {
700        let func = RefCell::new(func);
701        WrappedFunction(Box::new(move |lua, nargs| unsafe {
702            let mut func = func.try_borrow_mut().map_err(|_| Error::RecursiveMutCallback)?;
703            let args = A::from_stack_args(nargs, 1, None, lua)?;
704            func.call(args).push_into_stack_multi(lua)
705        }))
706    }
707
708    /// Wraps a Rust async function or closure, returning an opaque type that implements [`IntoLua`]
709    /// trait.
710    #[cfg(feature = "async")]
711    #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
712    pub fn wrap_async<F, A, R, E>(func: F) -> impl IntoLua
713    where
714        F: LuaNativeAsyncFn<A, Output = StdResult<R, E>> + MaybeSend + 'static,
715        A: FromLuaMulti,
716        R: IntoLuaMulti,
717        E: ExternalError,
718    {
719        WrappedAsyncFunction(Box::new(move |rawlua, nargs| unsafe {
720            let args = match A::from_stack_args(nargs, 1, None, rawlua) {
721                Ok(args) => args,
722                Err(e) => return Box::pin(future::ready(Err(e))),
723            };
724            let lua = rawlua.lua();
725            let fut = func.call(args);
726            Box::pin(async move { fut.await.into_lua_err()?.push_into_stack_multi(lua.raw_lua()) })
727        }))
728    }
729
730    /// Wraps a Rust async function or closure, returning an opaque type that implements [`IntoLua`]
731    /// trait.
732    ///
733    /// This function is similar to [`Function::wrap_async`] but any returned `Result` will be
734    /// converted to a `ok, err` tuple without throwing an exception.
735    #[cfg(feature = "async")]
736    #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
737    pub fn wrap_raw_async<F, A>(func: F) -> impl IntoLua
738    where
739        F: LuaNativeAsyncFn<A> + MaybeSend + 'static,
740        F::Output: IntoLuaMulti,
741        A: FromLuaMulti,
742    {
743        WrappedAsyncFunction(Box::new(move |rawlua, nargs| unsafe {
744            let args = match A::from_stack_args(nargs, 1, None, rawlua) {
745                Ok(args) => args,
746                Err(e) => return Box::pin(future::ready(Err(e))),
747            };
748            let lua = rawlua.lua();
749            let fut = func.call(args);
750            Box::pin(async move { fut.await.push_into_stack_multi(lua.raw_lua()) })
751        }))
752    }
753}
754
755impl IntoLua for WrappedFunction {
756    #[inline]
757    fn into_lua(self, lua: &Lua) -> Result<Value> {
758        lua.lock().create_callback(self.0).map(Value::Function)
759    }
760}
761
762#[cfg(feature = "async")]
763impl IntoLua for WrappedAsyncFunction {
764    #[inline]
765    fn into_lua(self, lua: &Lua) -> Result<Value> {
766        lua.lock().create_async_callback(self.0).map(Value::Function)
767    }
768}
769
770impl LuaType for Function {
771    const TYPE_ID: c_int = ffi::LUA_TFUNCTION;
772}
773
774/// Future for asynchronous function calls.
775#[cfg(feature = "async")]
776#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
777#[must_use = "futures do nothing unless you `.await` or poll them"]
778pub struct AsyncCallFuture<R: FromLuaMulti>(Result<AsyncThread<R>>);
779
780#[cfg(feature = "async")]
781impl<R: FromLuaMulti> AsyncCallFuture<R> {
782    pub(crate) fn error(err: Error) -> Self {
783        AsyncCallFuture(Err(err))
784    }
785}
786
787#[cfg(feature = "async")]
788impl<R: FromLuaMulti> Future for AsyncCallFuture<R> {
789    type Output = Result<R>;
790
791    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
792        let this = self.get_mut();
793        match &mut this.0 {
794            Ok(thread) => pin!(thread).poll(cx),
795            Err(err) => Poll::Ready(Err(err.clone())),
796        }
797    }
798}
799
800/// A trait for types that can be used as Lua functions.
801pub trait LuaNativeFn<A: FromLuaMulti> {
802    type Output;
803
804    fn call(&self, args: A) -> Self::Output;
805}
806
807/// A trait for types with mutable state that can be used as Lua functions.
808pub trait LuaNativeFnMut<A: FromLuaMulti> {
809    type Output;
810
811    fn call(&mut self, args: A) -> Self::Output;
812}
813
814/// A trait for types that returns a future and can be used as Lua functions.
815#[cfg(feature = "async")]
816#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
817pub trait LuaNativeAsyncFn<A: FromLuaMulti> {
818    type Output;
819
820    fn call(&self, args: A) -> impl Future<Output = Self::Output> + MaybeSend + 'static;
821}
822
823macro_rules! impl_lua_native_fn {
824    ($($A:ident),*) => {
825        impl<FN, $($A,)* R> LuaNativeFn<($($A,)*)> for FN
826        where
827            FN: Fn($($A,)*) -> R + MaybeSend + 'static,
828            ($($A,)*): FromLuaMulti,
829        {
830            type Output = R;
831
832            #[allow(non_snake_case)]
833            fn call(&self, args: ($($A,)*)) -> Self::Output {
834                let ($($A,)*) = args;
835                self($($A,)*)
836            }
837        }
838
839        impl<FN, $($A,)* R> LuaNativeFnMut<($($A,)*)> for FN
840        where
841            FN: FnMut($($A,)*) -> R + MaybeSend + 'static,
842            ($($A,)*): FromLuaMulti,
843        {
844            type Output = R;
845
846            #[allow(non_snake_case)]
847            fn call(&mut self, args: ($($A,)*)) -> Self::Output {
848                let ($($A,)*) = args;
849                self($($A,)*)
850            }
851        }
852
853        #[cfg(feature = "async")]
854        impl<FN, $($A,)* Fut, R> LuaNativeAsyncFn<($($A,)*)> for FN
855        where
856            FN: Fn($($A,)*) -> Fut + MaybeSend + 'static,
857            ($($A,)*): FromLuaMulti,
858            Fut: Future<Output = R> + MaybeSend + 'static,
859        {
860            type Output = R;
861
862            #[allow(non_snake_case)]
863            fn call(&self, args: ($($A,)*)) -> impl Future<Output = Self::Output> + MaybeSend + 'static {
864                let ($($A,)*) = args;
865                self($($A,)*)
866            }
867        }
868    };
869}
870
871impl_lua_native_fn!();
872impl_lua_native_fn!(A);
873impl_lua_native_fn!(A, B);
874impl_lua_native_fn!(A, B, C);
875impl_lua_native_fn!(A, B, C, D);
876impl_lua_native_fn!(A, B, C, D, E);
877impl_lua_native_fn!(A, B, C, D, E, F);
878impl_lua_native_fn!(A, B, C, D, E, F, G);
879impl_lua_native_fn!(A, B, C, D, E, F, G, H);
880impl_lua_native_fn!(A, B, C, D, E, F, G, H, I);
881impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J);
882impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K);
883impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K, L);
884impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K, L, M);
885impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
886impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
887impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
888
889#[cfg(test)]
890mod assertions {
891    use super::*;
892
893    #[cfg(not(feature = "send"))]
894    static_assertions::assert_not_impl_any!(Function: Send);
895    #[cfg(feature = "send")]
896    static_assertions::assert_impl_all!(Function: Send, Sync);
897
898    #[cfg(all(feature = "async", feature = "send"))]
899    static_assertions::assert_impl_all!(AsyncCallFuture<()>: Send);
900}