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