2018-09-28 14:55:09 +08:00
// sol3
2017-12-20 17:58:32 +08:00
2016-06-04 09:40:23 +08:00
// The MIT License (MIT)
2019-03-13 17:18:06 +08:00
// Copyright (c) 2013-2019 Rapptz, ThePhD and contributors
2016-06-04 09:40:23 +08:00
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# ifndef SOL_CALL_HPP
# define SOL_CALL_HPP
2019-02-11 04:02:40 +08:00
# include "property.hpp"
2016-07-08 04:52:39 +08:00
# include "protect.hpp"
2016-06-04 09:40:23 +08:00
# include "wrapper.hpp"
2018-03-10 11:27:49 +08:00
# include "trampoline.hpp"
2019-05-21 15:57:10 +08:00
# include "policies.hpp"
2016-06-04 09:40:23 +08:00
# include "stack.hpp"
2019-04-13 16:05:34 +08:00
# include "unique_usertype_traits.hpp"
2016-06-04 09:40:23 +08:00
2016-06-20 07:02:40 +08:00
namespace sol {
2018-09-28 13:27:38 +08:00
namespace u_detail {
2017-09-13 14:46:56 +08:00
2018-09-28 13:27:38 +08:00
} // namespace u_detail
2017-08-22 03:25:43 +08:00
2019-05-21 15:57:10 +08:00
namespace policy_detail {
2017-08-22 03:25:43 +08:00
template < int I , int . . . In >
2019-05-21 15:57:10 +08:00
inline void handle_policy ( static_stack_dependencies < I , In . . . > , lua_State * L , int & ) {
2019-02-11 04:02:40 +08:00
if constexpr ( sizeof . . . ( In ) = = 0 ) {
( void ) L ;
2017-08-22 03:25:43 +08:00
return ;
}
2019-02-11 04:02:40 +08:00
else {
absolute_index ai ( L , I ) ;
if ( type_of ( L , ai ) ! = type : : userdata ) {
return ;
}
lua_createtable ( L , static_cast < int > ( sizeof . . . ( In ) ) , 0 ) ;
stack_reference deps ( L , - 1 ) ;
auto per_dep = [ & L , & deps ] ( int i ) {
2018-12-20 12:17:15 +08:00
# if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK
2019-02-11 04:02:40 +08:00
luaL_checkstack ( L , 1 , detail : : not_enough_stack_space_generic ) ;
2018-12-20 12:17:15 +08:00
# endif // make sure stack doesn't overflow
2019-02-11 04:02:40 +08:00
lua_pushvalue ( L , i ) ;
luaL_ref ( L , deps . stack_index ( ) ) ;
} ;
( void ) per_dep ;
( void ) detail : : swallow { int ( ) , ( per_dep ( In ) , int ( ) ) . . . } ;
lua_setuservalue ( L , ai ) ;
}
2017-08-22 03:25:43 +08:00
}
template < int . . . In >
2019-05-21 15:57:10 +08:00
inline void handle_policy ( returns_self_with < In . . . > , lua_State * L , int & pushed ) {
2017-08-22 03:25:43 +08:00
pushed = stack : : push ( L , raw_index ( 1 ) ) ;
2019-05-21 15:57:10 +08:00
handle_policy ( static_stack_dependencies < - 1 , In . . . > ( ) , L , pushed ) ;
2017-08-22 03:25:43 +08:00
}
2019-05-21 15:57:10 +08:00
inline void handle_policy ( const stack_dependencies & sdeps , lua_State * L , int & ) {
2017-08-22 03:25:43 +08:00
absolute_index ai ( L , sdeps . target ) ;
if ( type_of ( L , ai ) ! = type : : userdata ) {
return ;
}
lua_createtable ( L , static_cast < int > ( sdeps . size ( ) ) , 0 ) ;
stack_reference deps ( L , - 1 ) ;
2018-12-20 12:17:15 +08:00
# if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK
luaL_checkstack ( L , static_cast < int > ( sdeps . size ( ) ) , detail : : not_enough_stack_space_generic ) ;
# endif // make sure stack doesn't overflow
2017-08-22 03:25:43 +08:00
for ( std : : size_t i = 0 ; i < sdeps . size ( ) ; + + i ) {
lua_pushvalue ( L , sdeps . stack_indices [ i ] ) ;
luaL_ref ( L , deps . stack_index ( ) ) ;
}
lua_setuservalue ( L , ai ) ;
}
2019-05-21 15:57:10 +08:00
template < typename P , meta : : disable < std : : is_base_of < detail : : policy_base_tag , meta : : unqualified_t < P > > > = meta : : enabler >
inline void handle_policy ( P & & p , lua_State * L , int & pushed ) {
2017-08-22 03:25:43 +08:00
pushed = std : : forward < P > ( p ) ( L , pushed ) ;
}
2019-05-21 15:57:10 +08:00
} // namespace policy_detail
2017-08-22 03:25:43 +08:00
2017-02-20 16:44:41 +08:00
namespace function_detail {
inline int no_construction_error ( lua_State * L ) {
return luaL_error ( L , " sol: cannot call this constructor (tagged as non-constructible) " ) ;
}
2017-09-13 14:46:56 +08:00
} // namespace function_detail
2017-02-20 16:44:41 +08:00
2016-06-20 07:02:40 +08:00
namespace call_detail {
template < typename R , typename W >
inline auto & pick ( std : : true_type , property_wrapper < R , W > & f ) {
2019-02-11 04:02:40 +08:00
return f . read ( ) ;
2016-06-20 07:02:40 +08:00
}
template < typename R , typename W >
inline auto & pick ( std : : false_type , property_wrapper < R , W > & f ) {
2019-02-11 04:02:40 +08:00
return f . write ( ) ;
2016-06-04 09:40:23 +08:00
}
2016-06-20 07:02:40 +08:00
template < typename T , typename List >
2017-03-16 15:07:20 +08:00
struct void_call : void_call < T , meta : : function_args_t < List > > { } ;
2016-06-20 07:02:40 +08:00
template < typename T , typename . . . Args >
struct void_call < T , types < Args . . . > > {
2017-09-13 14:46:56 +08:00
static void call ( Args . . . ) {
}
2016-06-20 07:02:40 +08:00
} ;
2017-08-22 03:25:43 +08:00
template < typename T , bool checked , bool clean_stack >
2016-06-20 07:02:40 +08:00
struct constructor_match {
2018-09-28 13:27:38 +08:00
T * obj_ ;
2016-06-20 07:02:40 +08:00
2019-02-11 04:02:40 +08:00
constructor_match ( T * o ) : obj_ ( o ) {
2017-09-13 14:46:56 +08:00
}
2016-06-20 07:02:40 +08:00
template < typename Fx , std : : size_t I , typename . . . R , typename . . . Args >
2018-12-20 12:17:15 +08:00
int operator ( ) ( types < Fx > , meta : : index_value < I > , types < R . . . > r , types < Args . . . > a , lua_State * L , int , int start ) const {
2019-02-11 04:02:40 +08:00
detail : : default_construct func { } ;
2018-09-28 13:27:38 +08:00
return stack : : call_into_lua < checked , clean_stack > ( r , a , L , start , func , obj_ ) ;
2016-06-04 09:40:23 +08:00
}
2016-06-20 07:02:40 +08:00
} ;
namespace overload_detail {
template < std : : size_t . . . M , typename Match , typename . . . Args >
2016-08-08 08:56:05 +08:00
inline int overload_match_arity ( types < > , std : : index_sequence < > , std : : index_sequence < M . . . > , Match & & , lua_State * L , int , int , Args & & . . . ) {
2016-06-20 07:02:40 +08:00
return luaL_error ( L , " sol: no matching function call takes this number of arguments and the specified types " ) ;
2016-06-04 09:40:23 +08:00
}
2016-06-20 07:02:40 +08:00
template < typename Fx , typename . . . Fxs , std : : size_t I , std : : size_t . . . In , std : : size_t . . . M , typename Match , typename . . . Args >
2019-02-11 04:02:40 +08:00
inline int overload_match_arity ( types < Fx , Fxs . . . > , std : : index_sequence < I , In . . . > , std : : index_sequence < M . . . > , Match & & matchfx , lua_State * L ,
int fxarity , int start , Args & & . . . args ) {
2017-06-14 04:34:18 +08:00
typedef lua_bind_traits < meta : : unwrap_unqualified_t < Fx > > traits ;
2016-06-20 07:02:40 +08:00
typedef meta : : tuple_types < typename traits : : return_type > return_types ;
typedef typename traits : : free_args_list args_list ;
// compile-time eliminate any functions that we know ahead of time are of improper arity
2019-11-09 12:53:48 +08:00
if constexpr ( ! traits : : runtime_variadics_t : : value
& & meta : : find_in_pack_v < meta : : index_value < traits : : free_arity > , meta : : index_value < M > . . . > : : value ) {
2019-02-11 04:02:40 +08:00
return overload_match_arity ( types < Fxs . . . > ( ) ,
std : : index_sequence < In . . . > ( ) ,
std : : index_sequence < M . . . > ( ) ,
std : : forward < Match > ( matchfx ) ,
L ,
fxarity ,
start ,
std : : forward < Args > ( args ) . . . ) ;
2016-06-20 07:02:40 +08:00
}
2019-02-11 04:02:40 +08:00
else {
if constexpr ( ! traits : : runtime_variadics_t : : value ) {
if ( traits : : free_arity ! = fxarity ) {
return overload_match_arity ( types < Fxs . . . > ( ) ,
2019-11-09 12:53:48 +08:00
std : : index_sequence < In . . . > ( ) ,
std : : index_sequence < traits : : free_arity , M . . . > ( ) ,
std : : forward < Match > ( matchfx ) ,
L ,
fxarity ,
start ,
std : : forward < Args > ( args ) . . . ) ;
2019-02-11 04:02:40 +08:00
}
}
stack : : record tracking { } ;
2019-03-10 23:09:52 +08:00
if ( ! stack : : stack_detail : : check_types ( args_list ( ) , L , start , no_panic , tracking ) ) {
2019-02-11 04:02:40 +08:00
return overload_match_arity ( types < Fxs . . . > ( ) ,
2019-11-09 12:53:48 +08:00
std : : index_sequence < In . . . > ( ) ,
std : : index_sequence < M . . . > ( ) ,
std : : forward < Match > ( matchfx ) ,
L ,
fxarity ,
start ,
std : : forward < Args > ( args ) . . . ) ;
2019-02-11 04:02:40 +08:00
}
return matchfx ( types < Fx > ( ) , meta : : index_value < I > ( ) , return_types ( ) , args_list ( ) , L , fxarity , start , std : : forward < Args > ( args ) . . . ) ;
2016-06-20 07:02:40 +08:00
}
2016-06-04 09:40:23 +08:00
}
2016-10-24 07:17:33 +08:00
template < std : : size_t . . . M , typename Match , typename . . . Args >
2019-02-11 04:02:40 +08:00
inline int overload_match_arity_single (
types < > , std : : index_sequence < > , std : : index_sequence < M . . . > , Match & & matchfx , lua_State * L , int fxarity , int start , Args & & . . . args ) {
return overload_match_arity ( types < > ( ) ,
std : : index_sequence < > ( ) ,
std : : index_sequence < M . . . > ( ) ,
std : : forward < Match > ( matchfx ) ,
L ,
fxarity ,
start ,
std : : forward < Args > ( args ) . . . ) ;
2016-10-24 07:17:33 +08:00
}
template < typename Fx , std : : size_t I , std : : size_t . . . M , typename Match , typename . . . Args >
2019-02-11 04:02:40 +08:00
inline int overload_match_arity_single (
types < Fx > , std : : index_sequence < I > , std : : index_sequence < M . . . > , Match & & matchfx , lua_State * L , int fxarity , int start , Args & & . . . args ) {
2017-06-14 04:34:18 +08:00
typedef lua_bind_traits < meta : : unwrap_unqualified_t < Fx > > traits ;
2016-10-24 07:17:33 +08:00
typedef meta : : tuple_types < typename traits : : return_type > return_types ;
typedef typename traits : : free_args_list args_list ;
// compile-time eliminate any functions that we know ahead of time are of improper arity
2019-02-11 04:02:40 +08:00
if constexpr ( ! traits : : runtime_variadics_t : : value
& & meta : : find_in_pack_v < meta : : index_value < traits : : free_arity > , meta : : index_value < M > . . . > : : value ) {
return overload_match_arity ( types < > ( ) ,
std : : index_sequence < > ( ) ,
std : : index_sequence < M . . . > ( ) ,
std : : forward < Match > ( matchfx ) ,
L ,
fxarity ,
start ,
std : : forward < Args > ( args ) . . . ) ;
2016-10-24 07:17:33 +08:00
}
2019-11-30 02:08:41 +08:00
if constexpr ( ! traits : : runtime_variadics_t : : value ) {
if ( traits : : free_arity ! = fxarity ) {
return overload_match_arity ( types < > ( ) ,
std : : index_sequence < > ( ) ,
std : : index_sequence < traits : : free_arity , M . . . > ( ) ,
std : : forward < Match > ( matchfx ) ,
L ,
fxarity ,
start ,
std : : forward < Args > ( args ) . . . ) ;
}
2016-10-24 07:17:33 +08:00
}
2018-12-20 12:17:15 +08:00
return matchfx ( types < Fx > ( ) , meta : : index_value < I > ( ) , return_types ( ) , args_list ( ) , L , fxarity , start , std : : forward < Args > ( args ) . . . ) ;
2016-10-24 07:17:33 +08:00
}
2019-02-11 04:02:40 +08:00
template < typename Fx , typename Fx1 , typename . . . Fxs , std : : size_t I , std : : size_t I1 , std : : size_t . . . In , std : : size_t . . . M , typename Match ,
typename . . . Args >
inline int overload_match_arity_single ( types < Fx , Fx1 , Fxs . . . > , std : : index_sequence < I , I1 , In . . . > , std : : index_sequence < M . . . > , Match & & matchfx ,
lua_State * L , int fxarity , int start , Args & & . . . args ) {
2017-06-14 04:34:18 +08:00
typedef lua_bind_traits < meta : : unwrap_unqualified_t < Fx > > traits ;
2016-10-24 07:17:33 +08:00
typedef meta : : tuple_types < typename traits : : return_type > return_types ;
typedef typename traits : : free_args_list args_list ;
// compile-time eliminate any functions that we know ahead of time are of improper arity
2019-11-09 12:53:48 +08:00
if constexpr ( ! traits : : runtime_variadics_t : : value
& & meta : : find_in_pack_v < meta : : index_value < traits : : free_arity > , meta : : index_value < M > . . . > : : value ) {
2019-02-11 04:02:40 +08:00
return overload_match_arity ( types < Fx1 , Fxs . . . > ( ) ,
std : : index_sequence < I1 , In . . . > ( ) ,
std : : index_sequence < M . . . > ( ) ,
std : : forward < Match > ( matchfx ) ,
L ,
fxarity ,
start ,
std : : forward < Args > ( args ) . . . ) ;
2016-10-24 07:17:33 +08:00
}
2019-02-11 04:02:40 +08:00
else {
if constexpr ( ! traits : : runtime_variadics_t : : value ) {
if ( traits : : free_arity ! = fxarity ) {
return overload_match_arity ( types < Fx1 , Fxs . . . > ( ) ,
2019-11-09 12:53:48 +08:00
std : : index_sequence < I1 , In . . . > ( ) ,
std : : index_sequence < traits : : free_arity , M . . . > ( ) ,
std : : forward < Match > ( matchfx ) ,
L ,
fxarity ,
start ,
std : : forward < Args > ( args ) . . . ) ;
2019-02-11 04:02:40 +08:00
}
}
stack : : record tracking { } ;
2019-03-10 23:09:52 +08:00
if ( ! stack : : stack_detail : : check_types ( args_list ( ) , L , start , no_panic , tracking ) ) {
2019-11-09 12:53:48 +08:00
return overload_match_arity ( types < Fx1 , Fxs . . . > ( ) ,
std : : index_sequence < I1 , In . . . > ( ) ,
std : : index_sequence < M . . . > ( ) ,
std : : forward < Match > ( matchfx ) ,
L ,
fxarity ,
start ,
std : : forward < Args > ( args ) . . . ) ;
2019-02-11 04:02:40 +08:00
}
return matchfx ( types < Fx > ( ) , meta : : index_value < I > ( ) , return_types ( ) , args_list ( ) , L , fxarity , start , std : : forward < Args > ( args ) . . . ) ;
2016-10-24 07:17:33 +08:00
}
}
2017-09-13 14:46:56 +08:00
} // namespace overload_detail
2016-06-07 03:46:53 +08:00
2016-06-20 07:02:40 +08:00
template < typename . . . Functions , typename Match , typename . . . Args >
inline int overload_match_arity ( Match & & matchfx , lua_State * L , int fxarity , int start , Args & & . . . args ) {
2019-02-11 04:02:40 +08:00
return overload_detail : : overload_match_arity_single ( types < Functions . . . > ( ) ,
std : : make_index_sequence < sizeof . . . ( Functions ) > ( ) ,
std : : index_sequence < > ( ) ,
std : : forward < Match > ( matchfx ) ,
L ,
fxarity ,
start ,
std : : forward < Args > ( args ) . . . ) ;
2016-06-04 09:40:23 +08:00
}
2016-06-20 07:02:40 +08:00
template < typename . . . Functions , typename Match , typename . . . Args >
inline int overload_match ( Match & & matchfx , lua_State * L , int start , Args & & . . . args ) {
int fxarity = lua_gettop ( L ) - ( start - 1 ) ;
return overload_match_arity < Functions . . . > ( std : : forward < Match > ( matchfx ) , L , fxarity , start , std : : forward < Args > ( args ) . . . ) ;
2016-06-04 09:40:23 +08:00
}
2016-06-20 07:02:40 +08:00
template < typename T , typename . . . TypeLists , typename Match , typename . . . Args >
2016-07-08 04:52:39 +08:00
inline int construct_match ( Match & & matchfx , lua_State * L , int fxarity , int start , Args & & . . . args ) {
2016-06-20 07:02:40 +08:00
// use same overload resolution matching as all other parts of the framework
2019-02-11 04:02:40 +08:00
return overload_match_arity < decltype ( void_call < T , TypeLists > : : call ) . . . > (
std : : forward < Match > ( matchfx ) , L , fxarity , start , std : : forward < Args > ( args ) . . . ) ;
2016-06-04 09:40:23 +08:00
}
2017-08-22 03:25:43 +08:00
template < typename T , bool checked , bool clean_stack , typename . . . TypeLists >
2018-11-10 02:53:46 +08:00
inline int construct_trampolined ( lua_State * L ) {
2016-10-22 05:32:27 +08:00
static const auto & meta = usertype_traits < T > : : metatable ( ) ;
2016-06-20 07:02:40 +08:00
int argcount = lua_gettop ( L ) ;
2018-01-29 11:21:13 +08:00
call_syntax syntax = argcount > 0 ? stack : : get_call_syntax ( L , usertype_traits < T > : : user_metatable ( ) , 1 ) : call_syntax : : dot ;
2016-06-20 07:02:40 +08:00
argcount - = static_cast < int > ( syntax ) ;
2016-06-08 08:32:10 +08:00
2017-10-03 05:32:58 +08:00
T * obj = detail : : usertype_allocate < T > ( L ) ;
2016-06-20 07:02:40 +08:00
reference userdataref ( L , - 1 ) ;
2019-04-04 21:38:23 +08:00
stack : : stack_detail : : undefined_metatable umf ( L , & meta [ 0 ] , & stack : : stack_detail : : set_undefined_methods_on < T > ) ;
umf ( ) ;
2016-06-20 07:02:40 +08:00
2019-11-30 02:08:41 +08:00
// put userdata at the first index
lua_insert ( L , 1 ) ;
2017-08-22 03:25:43 +08:00
construct_match < T , TypeLists . . . > ( constructor_match < T , checked , clean_stack > ( obj ) , L , argcount , 1 + static_cast < int > ( syntax ) ) ;
2016-06-20 07:02:40 +08:00
userdataref . push ( ) ;
2019-02-11 04:02:40 +08:00
return 1 ;
2018-11-10 02:53:46 +08:00
}
template < typename T , bool checked , bool clean_stack , typename . . . TypeLists >
inline int construct ( lua_State * L ) {
return detail : : static_trampoline < & construct_trampolined < T , checked , clean_stack , TypeLists . . . > > ( L ) ;
2016-06-08 08:32:10 +08:00
}
2017-08-22 03:25:43 +08:00
template < typename F , bool is_index , bool is_variable , bool checked , int boost , bool clean_stack , typename = void >
2016-06-20 07:02:40 +08:00
struct agnostic_lua_call_wrapper {
2017-08-25 02:39:02 +08:00
template < typename Fx , typename . . . Args >
static int call ( lua_State * L , Fx & & f , Args & & . . . args ) {
2020-03-31 12:22:46 +08:00
using uFx = meta : : unqualified_t < Fx > ;
static constexpr bool is_ref = is_lua_reference_v < uFx > ;
if constexpr ( is_ref ) {
2019-02-11 04:02:40 +08:00
if constexpr ( is_index ) {
return stack : : push ( L , std : : forward < Fx > ( f ) , std : : forward < Args > ( args ) . . . ) ;
}
else {
std : : forward < Fx > ( f ) = stack : : unqualified_get < F > ( L , boost + ( is_variable ? 3 : 1 ) ) ;
return 0 ;
}
2018-12-20 12:17:15 +08:00
}
else {
2020-03-31 12:22:46 +08:00
using wrap = wrapper < uFx > ;
2019-02-11 04:02:40 +08:00
using traits_type = typename wrap : : traits_type ;
using fp_t = typename traits_type : : function_pointer_type ;
constexpr bool is_function_pointer_convertible
2020-03-31 12:22:46 +08:00
= std : : is_class_v < uFx > & & std : : is_convertible_v < std : : decay_t < Fx > , fp_t > ;
2019-02-11 04:02:40 +08:00
if constexpr ( is_function_pointer_convertible ) {
fp_t fx = f ;
return agnostic_lua_call_wrapper < fp_t , is_index , is_variable , checked , boost , clean_stack > { } . call (
L , fx , std : : forward < Args > ( args ) . . . ) ;
}
else {
using returns_list = typename wrap : : returns_list ;
using args_list = typename wrap : : free_args_list ;
using caller = typename wrap : : caller ;
return stack : : call_into_lua < checked , clean_stack > (
returns_list ( ) , args_list ( ) , L , boost + 1 , caller ( ) , std : : forward < Fx > ( f ) , std : : forward < Args > ( args ) . . . ) ;
}
2018-12-20 12:17:15 +08:00
}
2018-09-28 13:27:38 +08:00
}
} ;
2019-02-11 04:02:40 +08:00
template < typename T , bool is_index , bool is_variable , bool checked , int boost , bool clean_stack , typename C >
struct agnostic_lua_call_wrapper < var_wrapper < T > , is_index , is_variable , checked , boost , clean_stack , C > {
2016-08-08 08:56:05 +08:00
template < typename F >
static int call ( lua_State * L , F & & f ) {
2019-02-11 04:02:40 +08:00
if constexpr ( is_index ) {
2019-02-11 05:40:37 +08:00
constexpr bool is_stack = is_stack_based_v < meta : : unqualified_t < decltype ( detail : : unwrap ( f . value ( ) ) ) > > ;
2019-02-11 04:02:40 +08:00
if constexpr ( clean_stack & & ! is_stack ) {
lua_settop ( L , 0 ) ;
}
2019-02-11 05:40:37 +08:00
return stack : : push_reference ( L , detail : : unwrap ( f . value ( ) ) ) ;
2017-08-22 03:25:43 +08:00
}
2019-02-11 04:02:40 +08:00
else {
if constexpr ( std : : is_const_v < meta : : unwrapped_t < T > > ) {
2019-11-09 12:53:48 +08:00
( void ) f ;
2019-02-11 04:02:40 +08:00
return luaL_error ( L , " sol: cannot write to a readonly (const) variable " ) ;
}
else {
using R = meta : : unwrapped_t < T > ;
if constexpr ( std : : is_assignable_v < std : : add_lvalue_reference_t < meta : : unqualified_t < R > > , R > ) {
2019-02-11 05:40:37 +08:00
detail : : unwrap ( f . value ( ) ) = stack : : unqualified_get < meta : : unwrapped_t < T > > ( L , boost + ( is_variable ? 3 : 1 ) ) ;
2019-02-11 04:02:40 +08:00
if ( clean_stack ) {
lua_settop ( L , 0 ) ;
}
return 0 ;
}
else {
return luaL_error ( L , " sol: cannot write to this variable: copy assignment/constructor not available " ) ;
}
}
2017-08-22 03:25:43 +08:00
}
2016-08-07 05:29:07 +08:00
}
} ;
2017-08-22 03:25:43 +08:00
template < bool is_index , bool is_variable , bool checked , int boost , bool clean_stack , typename C >
2017-09-06 01:58:17 +08:00
struct agnostic_lua_call_wrapper < lua_CFunction_ref , is_index , is_variable , checked , boost , clean_stack , C > {
static int call ( lua_State * L , lua_CFunction_ref f ) {
2016-06-20 07:02:40 +08:00
return f ( L ) ;
}
} ;
2016-06-04 09:40:23 +08:00
2017-08-22 03:25:43 +08:00
template < bool is_index , bool is_variable , bool checked , int boost , bool clean_stack , typename C >
struct agnostic_lua_call_wrapper < lua_CFunction , is_index , is_variable , checked , boost , clean_stack , C > {
2016-06-20 07:02:40 +08:00
static int call ( lua_State * L , lua_CFunction f ) {
return f ( L ) ;
}
} ;
2017-08-06 07:20:28 +08:00
2018-04-18 00:29:03 +08:00
# if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE
2017-08-22 03:25:43 +08:00
template < bool is_index , bool is_variable , bool checked , int boost , bool clean_stack , typename C >
struct agnostic_lua_call_wrapper < detail : : lua_CFunction_noexcept , is_index , is_variable , checked , boost , clean_stack , C > {
2017-06-17 12:43:26 +08:00
static int call ( lua_State * L , detail : : lua_CFunction_noexcept f ) {
return f ( L ) ;
}
} ;
# endif // noexcept function types
2016-06-04 09:40:23 +08:00
2017-08-22 03:25:43 +08:00
template < bool is_index , bool is_variable , bool checked , int boost , bool clean_stack , typename C >
2019-02-11 04:02:40 +08:00
struct agnostic_lua_call_wrapper < detail : : no_prop , is_index , is_variable , checked , boost , clean_stack , C > {
static int call ( lua_State * L , const detail : : no_prop & ) {
2016-06-20 07:02:40 +08:00
return luaL_error ( L , is_index ? " sol: cannot read from a writeonly property " : " sol: cannot write to a readonly property " ) ;
}
} ;
2016-06-04 09:40:23 +08:00
2017-08-22 03:25:43 +08:00
template < bool is_index , bool is_variable , bool checked , int boost , bool clean_stack , typename C >
struct agnostic_lua_call_wrapper < no_construction , is_index , is_variable , checked , boost , clean_stack , C > {
2016-06-30 02:08:26 +08:00
static int call ( lua_State * L , const no_construction & ) {
2017-02-20 16:44:41 +08:00
return function_detail : : no_construction_error ( L ) ;
2016-06-23 01:26:27 +08:00
}
} ;
2017-08-22 03:25:43 +08:00
template < typename . . . Args , bool is_index , bool is_variable , bool checked , int boost , bool clean_stack , typename C >
struct agnostic_lua_call_wrapper < bases < Args . . . > , is_index , is_variable , checked , boost , clean_stack , C > {
2016-06-30 02:08:26 +08:00
static int call ( lua_State * , const bases < Args . . . > & ) {
2016-06-23 01:26:27 +08:00
// Uh. How did you even call this, lul
return 0 ;
}
} ;
2017-08-22 03:25:43 +08:00
template < typename T , bool is_index , bool is_variable , bool checked , int boost , bool clean_stack , typename C >
struct agnostic_lua_call_wrapper < std : : reference_wrapper < T > , is_index , is_variable , checked , boost , clean_stack , C > {
2017-06-14 04:34:18 +08:00
static int call ( lua_State * L , std : : reference_wrapper < T > f ) {
2019-02-11 04:02:40 +08:00
agnostic_lua_call_wrapper < T , is_index , is_variable , checked , boost , clean_stack > alcw { } ;
return alcw . call ( L , f . get ( ) ) ;
2017-06-14 04:34:18 +08:00
}
} ;
2019-02-11 04:02:40 +08:00
template < typename T , typename F , bool is_index , bool is_variable , bool checked = detail : : default_safe_function_calls , int boost = 0 ,
bool clean_stack = true , typename = void >
struct lua_call_wrapper {
template < typename Fx , typename . . . Args >
static int call ( lua_State * L , Fx & & fx , Args & & . . . args ) {
if constexpr ( std : : is_member_function_pointer_v < F > ) {
using wrap = wrapper < F > ;
using object_type = typename wrap : : object_type ;
if constexpr ( sizeof . . . ( Args ) < 1 ) {
2019-03-15 04:15:43 +08:00
using Ta = meta : : conditional_t < std : : is_void_v < T > , object_type , T > ;
2020-03-31 12:22:46 +08:00
static_assert ( std : : is_base_of_v < object_type , Ta > , " It seems like you might have accidentally bound a class type with a member function method that does not correspond to the class. For example, there could be a small type in your new_usertype<T>(...) binding, where you specify one class \" T \" but then bind member methods from a complete unrelated class. Check things over! " ) ;
2018-04-18 00:29:03 +08:00
# if defined(SOL_SAFE_USERTYPE) && SOL_SAFE_USERTYPE
2019-02-11 04:02:40 +08:00
auto maybeo = stack : : check_get < Ta * > ( L , 1 ) ;
if ( ! maybeo | | maybeo . value ( ) = = nullptr ) {
return luaL_error ( L ,
" sol: received nil for 'self' argument (use ':' for accessing member functions, make sure member variables are "
" preceeded by the "
" actual object with '.' syntax) " ) ;
}
object_type * o = static_cast < object_type * > ( maybeo . value ( ) ) ;
return call ( L , std : : forward < Fx > ( fx ) , * o ) ;
2016-06-23 01:26:27 +08:00
# else
2019-02-11 04:02:40 +08:00
object_type & o = static_cast < object_type & > ( * stack : : unqualified_get < non_null < Ta * > > ( L , 1 ) ) ;
return call ( L , std : : forward < Fx > ( fx ) , o ) ;
2016-06-23 01:26:27 +08:00
# endif // Safety
2016-06-20 07:02:40 +08:00
}
2019-02-11 04:02:40 +08:00
else {
using returns_list = typename wrap : : returns_list ;
using args_list = typename wrap : : args_list ;
using caller = typename wrap : : caller ;
return stack : : call_into_lua < checked , clean_stack > (
returns_list ( ) , args_list ( ) , L , boost + ( is_variable ? 3 : 2 ) , caller ( ) , std : : forward < Fx > ( fx ) , std : : forward < Args > ( args ) . . . ) ;
}
2016-06-04 09:40:23 +08:00
}
2019-02-11 04:02:40 +08:00
else if constexpr ( std : : is_member_object_pointer_v < F > ) {
using wrap = wrapper < F > ;
using object_type = typename wrap : : object_type ;
2019-02-11 05:40:37 +08:00
if constexpr ( is_index ) {
if constexpr ( sizeof . . . ( Args ) < 1 ) {
2019-03-15 04:15:43 +08:00
using Ta = meta : : conditional_t < std : : is_void_v < T > , object_type , T > ;
2020-03-31 12:22:46 +08:00
static_assert ( std : : is_base_of_v < object_type , Ta > , " It seems like you might have accidentally bound a class type with a member function method that does not correspond to the class. For example, there could be a small type in your new_usertype<T>(...) binding, where you specify one class \" T \" but then bind member methods from a complete unrelated class. Check things over! " ) ;
2019-02-11 05:40:37 +08:00
# if defined(SOL_SAFE_USERTYPE) && SOL_SAFE_USERTYPE
auto maybeo = stack : : check_get < Ta * > ( L , 1 ) ;
if ( ! maybeo | | maybeo . value ( ) = = nullptr ) {
if ( is_variable ) {
return luaL_error ( L , " sol: 'self' argument is lua_nil (bad '.' access?) " ) ;
}
return luaL_error ( L , " sol: 'self' argument is lua_nil (pass 'self' as first argument) " ) ;
}
object_type * o = static_cast < object_type * > ( maybeo . value ( ) ) ;
return call ( L , std : : forward < Fx > ( fx ) , * o ) ;
# else
object_type & o = static_cast < object_type & > ( * stack : : get < non_null < Ta * > > ( L , 1 ) ) ;
return call ( L , std : : forward < Fx > ( fx ) , o ) ;
# endif // Safety
}
else {
using returns_list = typename wrap : : returns_list ;
using caller = typename wrap : : caller ;
2019-11-09 12:53:48 +08:00
return stack : : call_into_lua < checked , clean_stack > ( returns_list ( ) ,
types < > ( ) ,
L ,
boost + ( is_variable ? 3 : 2 ) ,
caller ( ) ,
std : : forward < Fx > ( fx ) ,
std : : forward < Args > ( args ) . . . ) ;
2019-02-11 05:40:37 +08:00
}
2019-02-11 04:02:40 +08:00
}
else {
2019-02-11 05:40:37 +08:00
using traits_type = lua_bind_traits < F > ;
using return_type = typename traits_type : : return_type ;
constexpr bool is_const = std : : is_const_v < std : : remove_reference_t < return_type > > ;
if constexpr ( is_const ) {
2019-02-11 04:02:40 +08:00
( void ) fx ;
2019-02-11 05:40:37 +08:00
( void ) detail : : swallow { 0 , ( static_cast < void > ( args ) , 0 ) . . . } ;
return luaL_error ( L , " sol: cannot write to a readonly (const) variable " ) ;
2019-02-11 04:02:40 +08:00
}
else {
2019-02-11 05:40:37 +08:00
using u_return_type = meta : : unqualified_t < return_type > ;
constexpr bool is_assignable = std : : is_copy_assignable_v < u_return_type > | | std : : is_array_v < u_return_type > ;
if constexpr ( ! is_assignable ) {
( void ) fx ;
( void ) detail : : swallow { 0 , ( ( void ) args , 0 ) . . . } ;
return luaL_error ( L , " sol: cannot write to this variable: copy assignment/constructor not available " ) ;
2019-02-11 04:02:40 +08:00
}
else {
2019-02-11 05:40:37 +08:00
using args_list = typename wrap : : args_list ;
using caller = typename wrap : : caller ;
if constexpr ( sizeof . . . ( Args ) > 0 ) {
return stack : : call_into_lua < checked , clean_stack > ( types < void > ( ) ,
2019-11-09 12:53:48 +08:00
args_list ( ) ,
L ,
boost + ( is_variable ? 3 : 2 ) ,
caller ( ) ,
std : : forward < Fx > ( fx ) ,
std : : forward < Args > ( args ) . . . ) ;
2019-02-11 05:40:37 +08:00
}
else {
2019-03-15 04:15:43 +08:00
using Ta = meta : : conditional_t < std : : is_void_v < T > , object_type , T > ;
2019-11-09 12:53:48 +08:00
# if defined(SOL_SAFE_USERTYPE) && SOL_SAFE_USERTYPE
2019-02-11 05:40:37 +08:00
auto maybeo = stack : : check_get < Ta * > ( L , 1 ) ;
if ( ! maybeo | | maybeo . value ( ) = = nullptr ) {
if ( is_variable ) {
return luaL_error ( L , " sol: received nil for 'self' argument (bad '.' access?) " ) ;
}
return luaL_error ( L , " sol: received nil for 'self' argument (pass 'self' as first argument) " ) ;
2019-02-11 04:02:40 +08:00
}
2019-02-11 05:40:37 +08:00
object_type * po = static_cast < object_type * > ( maybeo . value ( ) ) ;
object_type & o = * po ;
2019-11-09 12:53:48 +08:00
# else
2019-02-11 05:40:37 +08:00
object_type & o = static_cast < object_type & > ( * stack : : get < non_null < Ta * > > ( L , 1 ) ) ;
2019-11-09 12:53:48 +08:00
# endif // Safety
2019-02-11 05:40:37 +08:00
return stack : : call_into_lua < checked , clean_stack > (
2019-11-09 12:53:48 +08:00
types < void > ( ) , args_list ( ) , L , boost + ( is_variable ? 3 : 2 ) , caller ( ) , std : : forward < Fx > ( fx ) , o ) ;
2019-02-11 04:02:40 +08:00
}
}
}
}
}
else {
agnostic_lua_call_wrapper < F , is_index , is_variable , checked , boost , clean_stack > alcw { } ;
return alcw . call ( L , std : : forward < Fx > ( fx ) , std : : forward < Args > ( args ) . . . ) ;
}
2016-07-09 13:12:33 +08:00
}
2016-06-20 07:02:40 +08:00
} ;
2016-06-04 09:40:23 +08:00
2019-02-11 04:02:40 +08:00
template < typename T , typename F , bool is_index , bool is_variable , bool checked , int boost , bool clean_stack , typename C >
struct lua_call_wrapper < T , readonly_wrapper < F > , is_index , is_variable , checked , boost , clean_stack , C > {
using traits_type = lua_bind_traits < F > ;
using wrap = wrapper < F > ;
using object_type = typename wrap : : object_type ;
static int call ( lua_State * L , readonly_wrapper < F > & & rw ) {
if constexpr ( ! is_index ) {
( void ) rw ;
return luaL_error ( L , " sol: cannot write to a sol::readonly variable " ) ;
}
else {
lua_call_wrapper < T , F , true , is_variable , checked , boost , clean_stack , C > lcw ;
2019-02-11 18:50:35 +08:00
return lcw . call ( L , std : : move ( rw . value ( ) ) ) ;
2019-02-11 04:02:40 +08:00
}
}
static int call ( lua_State * L , readonly_wrapper < F > & & rw , object_type & o ) {
if constexpr ( ! is_index ) {
( void ) o ;
return call ( L , std : : move ( rw ) ) ;
}
else {
lua_call_wrapper < T , F , true , is_variable , checked , boost , clean_stack , C > lcw ;
2019-02-11 05:40:37 +08:00
return lcw . call ( L , rw . value ( ) , o ) ;
2019-02-11 04:02:40 +08:00
}
}
static int call ( lua_State * L , const readonly_wrapper < F > & rw ) {
if constexpr ( ! is_index ) {
( void ) rw ;
return luaL_error ( L , " sol: cannot write to a sol::readonly variable " ) ;
}
else {
lua_call_wrapper < T , F , true , is_variable , checked , boost , clean_stack , C > lcw ;
2019-02-11 05:40:37 +08:00
return lcw . call ( L , rw . value ( ) ) ;
2019-02-11 04:02:40 +08:00
}
}
static int call ( lua_State * L , const readonly_wrapper < F > & rw , object_type & o ) {
if constexpr ( ! is_index ) {
( void ) o ;
return call ( L , rw ) ;
}
else {
lua_call_wrapper < T , F , true , is_variable , checked , boost , clean_stack , C > lcw ;
2019-02-11 05:40:37 +08:00
return lcw . call ( L , rw . value ( ) , o ) ;
2019-02-11 04:02:40 +08:00
}
}
2017-05-29 22:32:37 +08:00
} ;
2017-08-22 03:25:43 +08:00
template < typename T , typename . . . Args , bool is_index , bool is_variable , bool checked , int boost , bool clean_stack , typename C >
struct lua_call_wrapper < T , constructor_list < Args . . . > , is_index , is_variable , checked , boost , clean_stack , C > {
2016-08-08 08:56:05 +08:00
typedef constructor_list < Args . . . > F ;
2016-06-20 07:02:40 +08:00
static int call ( lua_State * L , F & ) {
2018-03-16 05:16:28 +08:00
const auto & meta = usertype_traits < T > : : metatable ( ) ;
2016-06-20 07:02:40 +08:00
int argcount = lua_gettop ( L ) ;
2018-01-29 11:21:13 +08:00
call_syntax syntax = argcount > 0 ? stack : : get_call_syntax ( L , usertype_traits < T > : : user_metatable ( ) , 1 ) : call_syntax : : dot ;
2016-06-20 07:02:40 +08:00
argcount - = static_cast < int > ( syntax ) ;
2016-06-07 03:46:53 +08:00
2017-10-03 05:32:58 +08:00
T * obj = detail : : usertype_allocate < T > ( L ) ;
2016-06-07 03:46:53 +08:00
reference userdataref ( L , - 1 ) ;
2019-04-04 21:38:23 +08:00
stack : : stack_detail : : undefined_metatable umf ( L , & meta [ 0 ] , & stack : : stack_detail : : set_undefined_methods_on < T > ) ;
umf ( ) ;
2016-06-07 03:46:53 +08:00
2019-11-30 02:08:41 +08:00
// put userdata at the first index
lua_insert ( L , 1 ) ;
construct_match < T , Args . . . > ( constructor_match < T , checked , clean_stack > ( obj ) , L , argcount , boost + 1 + 1 + static_cast < int > ( syntax ) ) ;
2016-06-07 03:46:53 +08:00
userdataref . push ( ) ;
return 1 ;
}
} ;
2017-08-22 03:25:43 +08:00
template < typename T , typename . . . Cxs , bool is_index , bool is_variable , bool checked , int boost , bool clean_stack , typename C >
struct lua_call_wrapper < T , constructor_wrapper < Cxs . . . > , is_index , is_variable , checked , boost , clean_stack , C > {
2016-08-08 08:56:05 +08:00
typedef constructor_wrapper < Cxs . . . > F ;
2016-06-20 07:02:40 +08:00
struct onmatch {
template < typename Fx , std : : size_t I , typename . . . R , typename . . . Args >
2018-12-20 12:17:15 +08:00
int operator ( ) ( types < Fx > , meta : : index_value < I > , types < R . . . > r , types < Args . . . > a , lua_State * L , int , int start , F & f ) {
2018-03-16 05:16:28 +08:00
const auto & meta = usertype_traits < T > : : metatable ( ) ;
2017-10-03 05:32:58 +08:00
T * obj = detail : : usertype_allocate < T > ( L ) ;
2016-07-29 01:33:08 +08:00
reference userdataref ( L , - 1 ) ;
2019-04-04 21:38:23 +08:00
stack : : stack_detail : : undefined_metatable umf ( L , & meta [ 0 ] , & stack : : stack_detail : : set_undefined_methods_on < T > ) ;
umf ( ) ;
2018-09-28 13:27:38 +08:00
2016-09-14 12:02:15 +08:00
auto & func = std : : get < I > ( f . functions ) ;
2019-11-30 02:08:41 +08:00
// put userdata at the first index
lua_insert ( L , 1 ) ;
stack : : call_into_lua < checked , clean_stack > ( r , a , L , boost + 1 + start , func , detail : : implicit_wrapper < T > ( obj ) ) ;
2016-06-20 07:02:40 +08:00
userdataref . push ( ) ;
return 1 ;
}
} ;
static int call ( lua_State * L , F & f ) {
2018-01-29 11:21:13 +08:00
call_syntax syntax = stack : : get_call_syntax ( L , usertype_traits < T > : : user_metatable ( ) , 1 ) ;
2016-06-20 07:02:40 +08:00
int syntaxval = static_cast < int > ( syntax ) ;
int argcount = lua_gettop ( L ) - syntaxval ;
2016-07-08 04:52:39 +08:00
return construct_match < T , meta : : pop_front_type_t < meta : : function_args_t < Cxs > > . . . > ( onmatch ( ) , L , argcount , 1 + syntaxval , f ) ;
2016-06-20 07:02:40 +08:00
}
} ;
2016-06-07 03:46:53 +08:00
2019-02-11 04:02:40 +08:00
template < typename T , typename Fx , bool is_index , bool is_variable , bool checked , int boost , bool clean_stack , typename C >
struct lua_call_wrapper < T , destructor_wrapper < Fx > , is_index , is_variable , checked , boost , clean_stack , C > {
2016-06-07 03:46:53 +08:00
2019-03-29 11:18:59 +08:00
template < typename F >
static int call ( lua_State * L , F & & f ) {
2019-02-11 04:02:40 +08:00
if constexpr ( std : : is_void_v < Fx > ) {
return detail : : usertype_alloc_destruct < T > ( L ) ;
}
else {
2019-03-29 11:18:59 +08:00
using uFx = meta : : unqualified_t < Fx > ;
lua_call_wrapper < T , uFx , is_index , is_variable , checked , boost , clean_stack > lcw { } ;
return lcw . call ( L , std : : forward < F > ( f ) . fx ) ;
2019-02-11 04:02:40 +08:00
}
2018-03-16 05:16:28 +08:00
}
2016-06-20 07:02:40 +08:00
} ;
2016-06-07 03:46:53 +08:00
2017-08-22 03:25:43 +08:00
template < typename T , typename . . . Fs , bool is_index , bool is_variable , bool checked , int boost , bool clean_stack , typename C >
struct lua_call_wrapper < T , overload_set < Fs . . . > , is_index , is_variable , checked , boost , clean_stack , C > {
2016-06-20 07:02:40 +08:00
typedef overload_set < Fs . . . > F ;
2016-06-08 08:32:10 +08:00
2016-06-20 07:02:40 +08:00
struct on_match {
template < typename Fx , std : : size_t I , typename . . . R , typename . . . Args >
2018-12-20 12:17:15 +08:00
int operator ( ) ( types < Fx > , meta : : index_value < I > , types < R . . . > , types < Args . . . > , lua_State * L , int , int , F & fx ) {
2016-09-14 12:02:15 +08:00
auto & f = std : : get < I > ( fx . functions ) ;
2019-02-11 04:02:40 +08:00
return lua_call_wrapper < T , Fx , is_index , is_variable , checked , boost > { } . call ( L , f ) ;
2016-08-17 13:16:44 +08:00
}
} ;
static int call ( lua_State * L , F & fx ) {
return overload_match_arity < Fs . . . > ( on_match ( ) , L , lua_gettop ( L ) , 1 , fx ) ;
}
} ;
2017-08-22 03:25:43 +08:00
template < typename T , typename . . . Fs , bool is_index , bool is_variable , bool checked , int boost , bool clean_stack , typename C >
struct lua_call_wrapper < T , factory_wrapper < Fs . . . > , is_index , is_variable , checked , boost , clean_stack , C > {
2016-08-17 13:16:44 +08:00
typedef factory_wrapper < Fs . . . > F ;
struct on_match {
template < typename Fx , std : : size_t I , typename . . . R , typename . . . Args >
2018-12-20 12:17:15 +08:00
int operator ( ) ( types < Fx > , meta : : index_value < I > , types < R . . . > , types < Args . . . > , lua_State * L , int , int , F & fx ) {
2016-09-14 12:02:15 +08:00
auto & f = std : : get < I > ( fx . functions ) ;
2019-02-11 04:02:40 +08:00
return lua_call_wrapper < T , Fx , is_index , is_variable , checked , boost , clean_stack > { } . call ( L , f ) ;
2016-06-20 07:02:40 +08:00
}
} ;
static int call ( lua_State * L , F & fx ) {
2017-01-10 12:25:28 +08:00
return overload_match_arity < Fs . . . > ( on_match ( ) , L , lua_gettop ( L ) - boost , 1 + boost , fx ) ;
2016-06-08 08:32:10 +08:00
}
} ;
2017-08-22 03:25:43 +08:00
template < typename T , typename R , typename W , bool is_index , bool is_variable , bool checked , int boost , bool clean_stack , typename C >
struct lua_call_wrapper < T , property_wrapper < R , W > , is_index , is_variable , checked , boost , clean_stack , C > {
2019-03-15 04:15:43 +08:00
typedef meta : : conditional_t < is_index , R , W > P ;
2016-08-08 08:56:05 +08:00
typedef meta : : unqualified_t < P > U ;
2017-04-26 07:44:53 +08:00
typedef wrapper < U > wrap ;
2016-08-08 08:56:05 +08:00
typedef lua_bind_traits < U > traits_type ;
2017-04-26 07:44:53 +08:00
typedef meta : : unqualified_t < typename traits_type : : template arg_at < 0 > > object_type ;
2016-08-08 08:56:05 +08:00
2019-02-11 04:02:40 +08:00
template < typename F , typename . . . Args >
static int call ( lua_State * L , F & & f , Args & & . . . args ) {
2019-11-09 12:53:48 +08:00
constexpr bool is_specialized = meta : : any < std : : is_same < U , detail : : no_prop > ,
2019-02-11 04:02:40 +08:00
meta : : is_specialization_of < U , var_wrapper > ,
meta : : is_specialization_of < U , constructor_wrapper > ,
meta : : is_specialization_of < U , constructor_list > ,
std : : is_member_pointer < U > > : : value ;
if constexpr ( is_specialized ) {
if constexpr ( is_index ) {
decltype ( auto ) p = f . read ( ) ;
lua_call_wrapper < T , meta : : unqualified_t < decltype ( p ) > , is_index , is_variable , checked , boost , clean_stack > lcw { } ;
return lcw . call ( L , p , std : : forward < Args > ( args ) . . . ) ;
}
else {
decltype ( auto ) p = f . write ( ) ;
lua_call_wrapper < T , meta : : unqualified_t < decltype ( p ) > , is_index , is_variable , checked , boost , clean_stack > lcw { } ;
return lcw . call ( L , p , std : : forward < Args > ( args ) . . . ) ;
2016-08-08 08:56:05 +08:00
}
}
2019-02-11 04:02:40 +08:00
else {
constexpr bool non_class_object_type = meta : : any < std : : is_void < object_type > ,
2019-11-09 12:53:48 +08:00
meta : : boolean < lua_type_of < meta : : unwrap_unqualified_t < object_type > > : : value ! = type : : userdata > > : : value ;
2019-02-11 04:02:40 +08:00
if constexpr ( non_class_object_type ) {
// The type being void means we don't have any arguments, so it might be a free functions?
using args_list = typename traits_type : : free_args_list ;
using returns_list = typename wrap : : returns_list ;
using caller = typename wrap : : caller ;
if constexpr ( is_index ) {
decltype ( auto ) pf = f . read ( ) ;
return stack : : call_into_lua < checked , clean_stack > (
returns_list ( ) , args_list ( ) , L , boost + ( is_variable ? 3 : 2 ) , caller ( ) , pf ) ;
}
else {
decltype ( auto ) pf = f . write ( ) ;
return stack : : call_into_lua < checked , clean_stack > (
returns_list ( ) , args_list ( ) , L , boost + ( is_variable ? 3 : 2 ) , caller ( ) , pf ) ;
}
}
else {
using args_list = meta : : pop_front_type_t < typename traits_type : : free_args_list > ;
using Ta = T ;
using Oa = std : : remove_pointer_t < object_type > ;
# if defined(SOL_SAFE_USERTYPE) && SOL_SAFE_USERTYPE
auto maybeo = stack : : check_get < Ta * > ( L , 1 ) ;
if ( ! maybeo | | maybeo . value ( ) = = nullptr ) {
if ( is_variable ) {
return luaL_error ( L , " sol: 'self' argument is lua_nil (bad '.' access?) " ) ;
}
return luaL_error ( L , " sol: 'self' argument is lua_nil (pass 'self' as first argument) " ) ;
}
Oa * o = static_cast < Oa * > ( maybeo . value ( ) ) ;
2016-08-08 08:56:05 +08:00
# else
2019-02-11 04:02:40 +08:00
Oa * o = static_cast < Oa * > ( stack : : get < non_null < Ta * > > ( L , 1 ) ) ;
2016-08-08 08:56:05 +08:00
# endif // Safety
2019-02-11 04:02:40 +08:00
using returns_list = typename wrap : : returns_list ;
using caller = typename wrap : : caller ;
if constexpr ( is_index ) {
decltype ( auto ) pf = f . read ( ) ;
return stack : : call_into_lua < checked , clean_stack > (
returns_list ( ) , args_list ( ) , L , boost + ( is_variable ? 3 : 2 ) , caller ( ) , pf , detail : : implicit_wrapper < Oa > ( * o ) ) ;
}
else {
decltype ( auto ) pf = f . write ( ) ;
return stack : : call_into_lua < checked , clean_stack > (
returns_list ( ) , args_list ( ) , L , boost + ( is_variable ? 3 : 2 ) , caller ( ) , pf , detail : : implicit_wrapper < Oa > ( * o ) ) ;
}
}
}
2016-08-08 08:56:05 +08:00
}
} ;
2017-08-22 03:25:43 +08:00
template < typename T , typename V , bool is_index , bool is_variable , bool checked , int boost , bool clean_stack , typename C >
struct lua_call_wrapper < T , protect_t < V > , is_index , is_variable , checked , boost , clean_stack , C > {
2016-07-08 04:52:39 +08:00
typedef protect_t < V > F ;
2016-07-09 13:12:33 +08:00
template < typename . . . Args >
static int call ( lua_State * L , F & fx , Args & & . . . args ) {
2019-02-11 04:02:40 +08:00
return lua_call_wrapper < T , V , is_index , is_variable , true , boost , clean_stack > { } . call ( L , fx . value , std : : forward < Args > ( args ) . . . ) ;
2016-07-08 04:52:39 +08:00
}
} ;
2019-05-21 15:57:10 +08:00
template < typename T , typename F , typename . . . Policies , bool is_index , bool is_variable , bool checked , int boost , bool clean_stack , typename C >
struct lua_call_wrapper < T , policy_wrapper < F , Policies . . . > , is_index , is_variable , checked , boost , clean_stack , C > {
typedef policy_wrapper < F , Policies . . . > P ;
2017-08-22 03:25:43 +08:00
template < std : : size_t . . . In >
static int call ( std : : index_sequence < In . . . > , lua_State * L , P & fx ) {
2019-02-11 04:02:40 +08:00
int pushed = lua_call_wrapper < T , F , is_index , is_variable , checked , boost , false , C > { } . call ( L , fx . value ) ;
2019-05-21 15:57:10 +08:00
( void ) detail : : swallow { int ( ) , ( policy_detail : : handle_policy ( std : : get < In > ( fx . policies ) , L , pushed ) , int ( ) ) . . . } ;
2017-08-22 03:25:43 +08:00
return pushed ;
}
static int call ( lua_State * L , P & fx ) {
typedef typename P : : indices indices ;
return call ( indices ( ) , L , fx ) ;
}
} ;
2019-01-26 16:23:38 +08:00
template < typename T , typename Y , bool is_index , bool is_variable , bool checked , int boost , bool clean_stack , typename C >
struct lua_call_wrapper < T , yielding_t < Y > , is_index , is_variable , checked , boost , clean_stack , C > {
template < typename F >
static int call ( lua_State * L , F & & f ) {
return lua_call_wrapper < T , meta : : unqualified_t < Y > , is_index , is_variable , checked , boost , clean_stack > { } . call ( L , f . func ) ;
}
} ;
2017-08-22 03:25:43 +08:00
template < typename T , typename Sig , typename P , bool is_index , bool is_variable , bool checked , int boost , bool clean_stack , typename C >
struct lua_call_wrapper < T , function_arguments < Sig , P > , is_index , is_variable , checked , boost , clean_stack , C > {
2019-02-11 04:02:40 +08:00
static int call ( lua_State * L , const function_arguments < Sig , P > & f ) {
lua_call_wrapper < T , meta : : unqualified_t < P > , is_index , is_variable , checked , boost , clean_stack > lcw { } ;
return lcw . call ( L , std : : get < 0 > ( f . arguments ) ) ;
}
static int call ( lua_State * L , function_arguments < Sig , P > & & f ) {
lua_call_wrapper < T , meta : : unqualified_t < P > , is_index , is_variable , checked , boost , clean_stack > lcw { } ;
return lcw . call ( L , std : : get < 0 > ( std : : move ( f . arguments ) ) ) ;
2016-09-14 00:37:08 +08:00
}
} ;
2019-02-11 04:02:40 +08:00
template < typename T , bool is_index , bool is_variable , int boost = 0 , bool checked = detail : : default_safe_function_calls , bool clean_stack = true ,
typename Fx , typename . . . Args >
2016-07-09 13:12:33 +08:00
inline int call_wrapped ( lua_State * L , Fx & & fx , Args & & . . . args ) {
2019-01-26 16:09:37 +08:00
using uFx = meta : : unqualified_t < Fx > ;
2019-02-11 04:02:40 +08:00
if constexpr ( meta : : is_specialization_of_v < uFx , yielding_t > ) {
2019-01-26 16:09:37 +08:00
using real_fx = meta : : unqualified_t < decltype ( std : : forward < Fx > ( fx ) . func ) > ;
2019-02-11 04:02:40 +08:00
lua_call_wrapper < T , real_fx , is_index , is_variable , checked , boost , clean_stack > lcw { } ;
2020-01-17 18:22:52 +08:00
return lcw . call ( L , std : : forward < Fx > ( fx ) . func , std : : forward < Args > ( args ) . . . ) ;
2019-01-26 16:09:37 +08:00
}
else {
2019-02-11 04:02:40 +08:00
lua_call_wrapper < T , uFx , is_index , is_variable , checked , boost , clean_stack > lcw { } ;
return lcw . call ( L , std : : forward < Fx > ( fx ) , std : : forward < Args > ( args ) . . . ) ;
2019-01-26 16:09:37 +08:00
}
2016-06-08 08:32:10 +08:00
}
2019-11-09 12:53:48 +08:00
template < typename T , bool is_index , bool is_variable , typename F , int start = 1 , bool checked = detail : : default_safe_function_calls ,
bool clean_stack = true >
2016-07-08 04:52:39 +08:00
inline int call_user ( lua_State * L ) {
2018-06-16 01:19:09 +08:00
auto & fx = stack : : unqualified_get < user < F > > ( L , upvalue_index ( start ) ) ;
2020-01-17 18:22:52 +08:00
using uFx = meta : : unqualified_t < F > ;
int nr = call_wrapped < T , is_index , is_variable , 0 , checked , clean_stack > ( L , fx ) ;
if constexpr ( meta : : is_specialization_of_v < uFx , yielding_t > ) {
return lua_yield ( L , nr ) ;
}
else {
return nr ;
}
2016-07-08 04:52:39 +08:00
}
2016-06-20 07:02:40 +08:00
template < typename T , typename = void >
struct is_var_bind : std : : false_type { } ;
2016-06-04 09:40:23 +08:00
2016-06-20 07:02:40 +08:00
template < typename T >
struct is_var_bind < T , std : : enable_if_t < std : : is_member_object_pointer < T > : : value > > : std : : true_type { } ;
2016-06-04 09:40:23 +08:00
2018-12-20 12:17:15 +08:00
template < typename T >
struct is_var_bind < T , std : : enable_if_t < is_lua_reference_or_proxy < T > : : value > > : std : : true_type { } ;
2016-06-20 07:02:40 +08:00
template < >
2019-02-11 04:02:40 +08:00
struct is_var_bind < detail : : no_prop > : std : : true_type { } ;
2016-06-04 09:40:23 +08:00
2016-06-20 07:02:40 +08:00
template < typename R , typename W >
struct is_var_bind < property_wrapper < R , W > > : std : : true_type { } ;
2016-06-04 09:40:23 +08:00
2016-08-07 05:29:07 +08:00
template < typename T >
struct is_var_bind < var_wrapper < T > > : std : : true_type { } ;
2017-05-29 22:32:37 +08:00
template < typename T >
2017-08-22 03:25:43 +08:00
struct is_var_bind < readonly_wrapper < T > > : is_var_bind < meta : : unqualified_t < T > > { } ;
2019-05-21 15:57:10 +08:00
template < typename F , typename . . . Policies >
struct is_var_bind < policy_wrapper < F , Policies . . . > > : is_var_bind < meta : : unqualified_t < F > > { } ;
2017-09-13 14:46:56 +08:00
} // namespace call_detail
2016-06-04 09:40:23 +08:00
2016-06-20 07:02:40 +08:00
template < typename T >
struct is_variable_binding : call_detail : : is_var_bind < meta : : unqualified_t < T > > { } ;
2016-06-04 09:40:23 +08:00
2018-12-20 12:17:15 +08:00
template < typename T >
using is_var_wrapper = meta : : is_specialization_of < T , var_wrapper > ;
2016-06-20 07:02:40 +08:00
template < typename T >
struct is_function_binding : meta : : neg < is_variable_binding < T > > { } ;
2016-06-04 09:40:23 +08:00
2017-09-13 14:46:56 +08:00
} // namespace sol
2016-06-04 09:40:23 +08:00
2016-07-08 04:52:39 +08:00
# endif // SOL_CALL_HPP