#pragma once #include #include #include #include #include #define N(X) ::eosio::string_to_name(#X) namespace eosio { template bool dispatch( uint64_t code, uint64_t act ) { if( code == FirstAction::get_account() && FirstAction::get_name() == act ) { Contract().on( unpack_action_data() ); return true; } return false; } /** * This method will dynamically dispatch an incoming set of actions to * * ``` * static Contract::on( ActionType ) * ``` * * For this to work the Actions must be dervied from the * */ template bool dispatch( uint64_t code, uint64_t act ) { if( code == FirstAction::get_account() && FirstAction::get_name() == act ) { Contract().on( unpack_action_data() ); return true; } return eosio::dispatch( code, act ); } template bool execute_action( T* obj, void (Q::*func)(Args...) ) { size_t size = action_data_size(); //using malloc/free here potentially is not exception-safe, although WASM doesn't support exceptions constexpr size_t max_stack_buffer_size = 512; void* buffer = nullptr; if( size > 0 ) { buffer = max_stack_buffer_size < size ? malloc(size) : alloca(size); read_action_data( buffer, size ); } auto args = unpack...>>( (char*)buffer, size ); if ( max_stack_buffer_size < size ) { free(buffer); } auto f2 = [&]( auto... a ){ (obj->*func)( a... ); }; boost::mp11::tuple_apply( f2, args ); return true; } #define EOSIO_API_CALL( r, OP, elem ) \ case ::eosio::string_to_name( BOOST_PP_STRINGIZE(elem) ): \ eosio::execute_action( &thiscontract, &OP::elem ); \ break; #define EOSIO_API( TYPE, MEMBERS ) \ BOOST_PP_SEQ_FOR_EACH( EOSIO_API_CALL, TYPE, MEMBERS ) #define EOSIO_ABI( TYPE, MEMBERS ) \ extern "C" { \ void apply( uint64_t receiver, uint64_t code, uint64_t action ) { \ auto self = receiver; \ if( action == N(onerror)) { \ /* onerror is only valid if it is for the "eosio" code account and authorized by "eosio"'s "active permission */ \ eosio_assert(code == N(eosio), "onerror action's are only valid from the \"eosio\" system account"); \ } \ if( code == self || action == N(onerror) ) { \ TYPE thiscontract( self ); \ switch( action ) { \ EOSIO_API( TYPE, MEMBERS ) \ } \ /* does not allow destructor of thiscontract to run: eosio_exit(0); */ \ } \ } \ } \ /* template struct dispatcher { dispatcher( account_name code ):_contract(code){} template void dispatch( account_name action, FuncPtr ) { } T contract; }; void dispatch( account_name code, account_name action, */ }