1use 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#[derive(Clone, Debug, PartialEq)]
102pub struct Function(pub(crate) ValueRef);
103
104#[derive(Clone, Debug)]
110#[non_exhaustive]
111pub struct FunctionInfo {
112 pub name: Option<String>,
114 pub name_what: Option<&'static str>,
118 pub what: &'static str,
121 pub source: Option<String>,
123 pub short_src: Option<String>,
125 pub line_defined: Option<usize>,
127 pub last_line_defined: Option<usize>,
129 pub num_upvalues: u8,
131 #[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 #[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#[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 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 lua.push_error_traceback();
202 let stack_start = ffi::lua_gettop(state);
203 lua.push_ref(&self.0);
205 let nargs = args.push_into_stack_multi(&lua)?;
206 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 let nresults = ffi::lua_gettop(state) - stack_start;
213 R::from_stack_multi(nresults, &lua)
214 }
215 }
216
217 #[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 Ok(th)
256 })
257 })
258 }
259
260 pub fn bind(&self, args: impl IntoLuaMulti) -> Result<Function> {
288 unsafe extern "C-unwind" fn args_wrapper_impl(state: *mut ffi::lua_State) -> c_int {
289 let nargs = ffi::lua_gettop(state);
290 let nbinds = ffi::lua_tointeger(state, ffi::lua_upvalueindex(1)) as c_int;
291 ffi::luaL_checkstack(state, nbinds, ptr::null());
292
293 for i in 0..nbinds {
294 ffi::lua_pushvalue(state, ffi::lua_upvalueindex(i + 2));
295 }
296 if nargs > 0 {
297 ffi::lua_rotate(state, 1, nbinds);
298 }
299
300 nargs + nbinds
301 }
302
303 let lua = self.0.lua.lock();
304 let state = lua.state();
305
306 let args = args.into_lua_multi(lua.lua())?;
307 let nargs = args.len() as c_int;
308
309 if nargs == 0 {
310 return Ok(self.clone());
311 }
312
313 if nargs + 1 > ffi::LUA_MAX_UPVALUES {
314 return Err(Error::BindError);
315 }
316
317 let args_wrapper = unsafe {
318 let _sg = StackGuard::new(state);
319 check_stack(state, nargs + 3)?;
320
321 ffi::lua_pushinteger(state, nargs as ffi::lua_Integer);
322 for arg in &args {
323 lua.push_value(arg)?;
324 }
325 protect_lua!(state, nargs + 1, 1, fn(state) {
326 ffi::lua_pushcclosure(state, args_wrapper_impl, ffi::lua_gettop(state));
327 })?;
328
329 Function(lua.pop_ref())
330 };
331
332 let lua = lua.lua();
333 lua.load(
334 r#"
335 local func, args_wrapper = ...
336 return function(...)
337 return func(args_wrapper(...))
338 end
339 "#,
340 )
341 .try_cache()
342 .set_name("=__mlua_bind")
343 .call((self, args_wrapper))
344 }
345
346 pub fn environment(&self) -> Option<Table> {
352 let lua = self.0.lua.lock();
353 let state = lua.state();
354 unsafe {
355 let _sg = StackGuard::new(state);
356 assert_stack(state, 1);
357
358 lua.push_ref(&self.0);
359 if ffi::lua_iscfunction(state, -1) != 0 {
360 return None;
361 }
362
363 #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
364 ffi::lua_getfenv(state, -1);
365 #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52"))]
366 for i in 1..=255 {
367 match ffi::lua_getupvalue(state, -1, i) {
369 s if s.is_null() => break,
370 s if std::ffi::CStr::from_ptr(s as _) == c"_ENV" => break,
371 _ => ffi::lua_pop(state, 1),
372 }
373 }
374
375 if ffi::lua_type(state, -1) != ffi::LUA_TTABLE {
376 return None;
377 }
378 Some(Table(lua.pop_ref()))
379 }
380 }
381
382 pub fn set_environment(&self, env: Table) -> Result<bool> {
389 let lua = self.0.lua.lock();
390 let state = lua.state();
391 unsafe {
392 let _sg = StackGuard::new(state);
393 check_stack(state, 2)?;
394
395 lua.push_ref(&self.0);
396 if ffi::lua_iscfunction(state, -1) != 0 {
397 return Ok(false);
398 }
399
400 #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
401 {
402 lua.push_ref(&env.0);
403 ffi::lua_setfenv(state, -2);
404 }
405 #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52"))]
406 for i in 1..=255 {
407 match ffi::lua_getupvalue(state, -1, i) {
408 s if s.is_null() => return Ok(false),
409 s if std::ffi::CStr::from_ptr(s as _) == c"_ENV" => {
410 ffi::lua_pop(state, 1);
411 let f_with_env = lua
413 .lua()
414 .load("return _ENV")
415 .set_environment(env)
416 .try_cache()
417 .into_function()?;
418 lua.push_ref(&f_with_env.0);
419 ffi::lua_upvaluejoin(state, -2, i, -1, 1);
420 break;
421 }
422 _ => ffi::lua_pop(state, 1),
423 }
424 }
425
426 Ok(true)
427 }
428 }
429
430 pub fn info(&self) -> FunctionInfo {
437 let lua = self.0.lua.lock();
438 let state = lua.state();
439 unsafe {
440 let _sg = StackGuard::new(state);
441 assert_stack(state, 1);
442
443 let mut ar: ffi::lua_Debug = mem::zeroed();
444 lua.push_ref(&self.0);
445
446 #[cfg(not(feature = "luau"))]
447 let res = ffi::lua_getinfo(state, cstr!(">Snu"), &mut ar);
448 #[cfg(not(feature = "luau"))]
449 mlua_assert!(res != 0, "lua_getinfo failed with `>Snu`");
450
451 #[cfg(feature = "luau")]
452 let res = ffi::lua_getinfo(state, -1, cstr!("snau"), &mut ar);
453 #[cfg(feature = "luau")]
454 mlua_assert!(res != 0, "lua_getinfo failed with `snau`");
455
456 FunctionInfo {
457 name: ptr_to_lossy_str(ar.name).map(|s| s.into_owned()),
458 #[cfg(not(feature = "luau"))]
459 name_what: match ptr_to_str(ar.namewhat) {
460 Some("") => None,
461 val => val,
462 },
463 #[cfg(feature = "luau")]
464 name_what: None,
465 what: ptr_to_str(ar.what).unwrap_or("main"),
466 source: ptr_to_lossy_str(ar.source).map(|s| s.into_owned()),
467 #[cfg(not(feature = "luau"))]
468 short_src: ptr_to_lossy_str(ar.short_src.as_ptr()).map(|s| s.into_owned()),
469 #[cfg(feature = "luau")]
470 short_src: ptr_to_lossy_str(ar.short_src).map(|s| s.into_owned()),
471 line_defined: linenumber_to_usize(ar.linedefined),
472 #[cfg(not(feature = "luau"))]
473 last_line_defined: linenumber_to_usize(ar.lastlinedefined),
474 #[cfg(feature = "luau")]
475 last_line_defined: None,
476 #[cfg(not(feature = "luau"))]
477 num_upvalues: ar.nups as _,
478 #[cfg(feature = "luau")]
479 num_upvalues: ar.nupvals,
480 #[cfg(not(any(feature = "lua51", feature = "luajit")))]
481 num_params: ar.nparams,
482 #[cfg(not(any(feature = "lua51", feature = "luajit")))]
483 is_vararg: ar.isvararg != 0,
484 }
485 }
486 }
487
488 #[cfg(not(feature = "luau"))]
497 #[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
498 pub fn dump(&self, strip: bool) -> Vec<u8> {
499 unsafe extern "C-unwind" fn writer(
500 _state: *mut ffi::lua_State,
501 buf: *const c_void,
502 buf_len: usize,
503 data_ptr: *mut c_void,
504 ) -> c_int {
505 if !data_ptr.is_null() && buf_len > 0 {
507 let data = &mut *(data_ptr as *mut Vec<u8>);
508 let buf = slice::from_raw_parts(buf as *const u8, buf_len);
509 data.extend_from_slice(buf);
510 }
511 0
512 }
513
514 let lua = self.0.lua.lock();
515 let state = lua.state();
516 let mut data: Vec<u8> = Vec::new();
517 unsafe {
518 let _sg = StackGuard::new(state);
519 assert_stack(state, 1);
520
521 lua.push_ref(&self.0);
522 let data_ptr = &mut data as *mut Vec<u8> as *mut c_void;
523 ffi::lua_dump(state, writer, data_ptr, strip as i32);
524 ffi::lua_pop(state, 1);
525 }
526
527 data
528 }
529
530 #[cfg(any(feature = "luau", doc))]
539 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
540 pub fn coverage<F>(&self, func: F)
541 where
542 F: FnMut(CoverageInfo),
543 {
544 use std::ffi::CStr;
545 use std::os::raw::c_char;
546
547 unsafe extern "C-unwind" fn callback<F: FnMut(CoverageInfo)>(
548 data: *mut c_void,
549 function: *const c_char,
550 line_defined: c_int,
551 depth: c_int,
552 hits: *const c_int,
553 size: usize,
554 ) {
555 let function = if !function.is_null() {
556 Some(CStr::from_ptr(function).to_string_lossy().to_string())
557 } else {
558 None
559 };
560 let rust_callback = &*(data as *const RefCell<F>);
561 if let Ok(mut rust_callback) = rust_callback.try_borrow_mut() {
562 rust_callback(CoverageInfo {
564 function,
565 line_defined,
566 depth,
567 hits: slice::from_raw_parts(hits, size).to_vec(),
568 });
569 }
570 }
571
572 let lua = self.0.lua.lock();
573 let state = lua.state();
574 unsafe {
575 let _sg = StackGuard::new(state);
576 assert_stack(state, 1);
577
578 lua.push_ref(&self.0);
579 let func = RefCell::new(func);
580 let func_ptr = &func as *const RefCell<F> as *mut c_void;
581 ffi::lua_getcoverage(state, -1, func_ptr, callback::<F>);
582 }
583 }
584
585 #[inline]
591 pub fn to_pointer(&self) -> *const c_void {
592 self.0.to_pointer()
593 }
594
595 #[cfg(any(feature = "luau", doc))]
601 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
602 pub fn deep_clone(&self) -> Result<Self> {
603 let lua = self.0.lua.lock();
604 let state = lua.state();
605 unsafe {
606 let _sg = StackGuard::new(state);
607 check_stack(state, 2)?;
608
609 lua.push_ref(&self.0);
610 if ffi::lua_iscfunction(state, -1) != 0 {
611 return Ok(self.clone());
612 }
613
614 if lua.unlikely_memory_error() {
615 ffi::lua_clonefunction(state, -1);
616 } else {
617 protect_lua!(state, 1, 1, fn(state) ffi::lua_clonefunction(state, -1))?;
618 }
619 Ok(Function(lua.pop_ref()))
620 }
621 }
622}
623
624struct WrappedFunction(pub(crate) Callback);
625
626#[cfg(feature = "async")]
627struct WrappedAsyncFunction(pub(crate) AsyncCallback);
628
629impl Function {
630 #[inline]
633 pub fn wrap<F, A, R, E>(func: F) -> impl IntoLua
634 where
635 F: LuaNativeFn<A, Output = StdResult<R, E>> + MaybeSend + 'static,
636 A: FromLuaMulti,
637 R: IntoLuaMulti,
638 E: ExternalError,
639 {
640 WrappedFunction(Box::new(move |lua, nargs| unsafe {
641 let args = A::from_stack_args(nargs, 1, None, lua)?;
642 func.call(args).into_lua_err()?.push_into_stack_multi(lua)
643 }))
644 }
645
646 pub fn wrap_mut<F, A, R, E>(func: F) -> impl IntoLua
648 where
649 F: LuaNativeFnMut<A, Output = StdResult<R, E>> + MaybeSend + 'static,
650 A: FromLuaMulti,
651 R: IntoLuaMulti,
652 E: ExternalError,
653 {
654 let func = RefCell::new(func);
655 WrappedFunction(Box::new(move |lua, nargs| unsafe {
656 let mut func = func.try_borrow_mut().map_err(|_| Error::RecursiveMutCallback)?;
657 let args = A::from_stack_args(nargs, 1, None, lua)?;
658 func.call(args).into_lua_err()?.push_into_stack_multi(lua)
659 }))
660 }
661
662 #[inline]
668 pub fn wrap_raw<F, A>(func: F) -> impl IntoLua
669 where
670 F: LuaNativeFn<A> + MaybeSend + 'static,
671 F::Output: IntoLuaMulti,
672 A: FromLuaMulti,
673 {
674 WrappedFunction(Box::new(move |lua, nargs| unsafe {
675 let args = A::from_stack_args(nargs, 1, None, lua)?;
676 func.call(args).push_into_stack_multi(lua)
677 }))
678 }
679
680 #[inline]
685 pub fn wrap_raw_mut<F, A>(func: F) -> impl IntoLua
686 where
687 F: LuaNativeFnMut<A> + MaybeSend + 'static,
688 F::Output: IntoLuaMulti,
689 A: FromLuaMulti,
690 {
691 let func = RefCell::new(func);
692 WrappedFunction(Box::new(move |lua, nargs| unsafe {
693 let mut func = func.try_borrow_mut().map_err(|_| Error::RecursiveMutCallback)?;
694 let args = A::from_stack_args(nargs, 1, None, lua)?;
695 func.call(args).push_into_stack_multi(lua)
696 }))
697 }
698
699 #[cfg(feature = "async")]
702 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
703 pub fn wrap_async<F, A, R, E>(func: F) -> impl IntoLua
704 where
705 F: LuaNativeAsyncFn<A, Output = StdResult<R, E>> + MaybeSend + 'static,
706 A: FromLuaMulti,
707 R: IntoLuaMulti,
708 E: ExternalError,
709 {
710 WrappedAsyncFunction(Box::new(move |rawlua, nargs| unsafe {
711 let args = match A::from_stack_args(nargs, 1, None, rawlua) {
712 Ok(args) => args,
713 Err(e) => return Box::pin(future::ready(Err(e))),
714 };
715 let lua = rawlua.lua();
716 let fut = func.call(args);
717 Box::pin(async move { fut.await.into_lua_err()?.push_into_stack_multi(lua.raw_lua()) })
718 }))
719 }
720
721 #[cfg(feature = "async")]
727 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
728 pub fn wrap_raw_async<F, A>(func: F) -> impl IntoLua
729 where
730 F: LuaNativeAsyncFn<A> + MaybeSend + 'static,
731 F::Output: IntoLuaMulti,
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#[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
791pub trait LuaNativeFn<A: FromLuaMulti> {
793 type Output;
794
795 fn call(&self, args: A) -> Self::Output;
796}
797
798pub trait LuaNativeFnMut<A: FromLuaMulti> {
800 type Output;
801
802 fn call(&mut self, args: A) -> Self::Output;
803}
804
805#[cfg(feature = "async")]
807pub trait LuaNativeAsyncFn<A: FromLuaMulti> {
808 type Output;
809
810 fn call(&self, args: A) -> impl Future<Output = Self::Output> + MaybeSend + 'static;
811}
812
813macro_rules! impl_lua_native_fn {
814 ($($A:ident),*) => {
815 impl<FN, $($A,)* R> LuaNativeFn<($($A,)*)> for FN
816 where
817 FN: Fn($($A,)*) -> R + MaybeSend + 'static,
818 ($($A,)*): FromLuaMulti,
819 {
820 type Output = R;
821
822 #[allow(non_snake_case)]
823 fn call(&self, args: ($($A,)*)) -> Self::Output {
824 let ($($A,)*) = args;
825 self($($A,)*)
826 }
827 }
828
829 impl<FN, $($A,)* R> LuaNativeFnMut<($($A,)*)> for FN
830 where
831 FN: FnMut($($A,)*) -> R + MaybeSend + 'static,
832 ($($A,)*): FromLuaMulti,
833 {
834 type Output = R;
835
836 #[allow(non_snake_case)]
837 fn call(&mut self, args: ($($A,)*)) -> Self::Output {
838 let ($($A,)*) = args;
839 self($($A,)*)
840 }
841 }
842
843 #[cfg(feature = "async")]
844 impl<FN, $($A,)* Fut, R> LuaNativeAsyncFn<($($A,)*)> for FN
845 where
846 FN: Fn($($A,)*) -> Fut + MaybeSend + 'static,
847 ($($A,)*): FromLuaMulti,
848 Fut: Future<Output = R> + MaybeSend + 'static,
849 {
850 type Output = R;
851
852 #[allow(non_snake_case)]
853 fn call(&self, args: ($($A,)*)) -> impl Future<Output = Self::Output> + MaybeSend + 'static {
854 let ($($A,)*) = args;
855 self($($A,)*)
856 }
857 }
858 };
859}
860
861impl_lua_native_fn!();
862impl_lua_native_fn!(A);
863impl_lua_native_fn!(A, B);
864impl_lua_native_fn!(A, B, C);
865impl_lua_native_fn!(A, B, C, D);
866impl_lua_native_fn!(A, B, C, D, E);
867impl_lua_native_fn!(A, B, C, D, E, F);
868impl_lua_native_fn!(A, B, C, D, E, F, G);
869impl_lua_native_fn!(A, B, C, D, E, F, G, H);
870impl_lua_native_fn!(A, B, C, D, E, F, G, H, I);
871impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J);
872impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K);
873impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K, L);
874impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K, L, M);
875impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
876impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
877impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
878
879#[cfg(test)]
880mod assertions {
881 use super::*;
882
883 #[cfg(not(feature = "send"))]
884 static_assertions::assert_not_impl_any!(Function: Send);
885 #[cfg(feature = "send")]
886 static_assertions::assert_impl_all!(Function: Send, Sync);
887
888 #[cfg(all(feature = "async", feature = "send"))]
889 static_assertions::assert_impl_all!(AsyncCallFuture<()>: Send);
890}