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 lua.update_thread_ownership(th.thread(), Some(lua.state()));
256 Ok(th)
257 })
258 })
259 }
260
261 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 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 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 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 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 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 #[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_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 #[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 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 #[inline]
582 pub fn to_pointer(&self) -> *const c_void {
583 self.0.to_pointer()
584 }
585
586 #[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 #[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 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 #[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 #[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 #[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 #[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#[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
782pub trait LuaNativeFn<A: FromLuaMulti> {
784 type Output;
785
786 fn call(&self, args: A) -> Self::Output;
787}
788
789pub trait LuaNativeFnMut<A: FromLuaMulti> {
791 type Output;
792
793 fn call(&mut self, args: A) -> Self::Output;
794}
795
796#[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}