Json RPC works

- adding call_fused() for tuple + functor
- fixed json handling of true,false, and null
- cast from value to tuple
This commit is contained in:
Daniel Larimer 2012-11-07 22:14:00 -05:00
parent a6541b825a
commit 031e2db4db
9 changed files with 91 additions and 31 deletions

View file

@ -4,16 +4,18 @@
#include <boost/preprocessor/repeat.hpp> #include <boost/preprocessor/repeat.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp> #include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp> #include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_trailing_params.hpp>
#include <boost/preprocessor/facilities/empty.hpp> #include <boost/preprocessor/facilities/empty.hpp>
namespace fc { namespace json { namespace fc { namespace json {
//static std::function<fc::future<R>( BOOST_PP_ENUM_PARAMS(n,A) ) >
namespace detail { namespace detail {
struct rpc_member { struct rpc_member {
#define RPC_MEMBER_FUNCTOR(z,n,IS_CONST) \ #define RPC_MEMBER_FUNCTOR(z,n,IS_CONST) \
template<typename R, typename C, typename P BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS( n, typename A)> \ template<typename R, typename C, typename P BOOST_PP_ENUM_TRAILING_PARAMS( n, typename A)> \
static fc::function<fc::future<R> BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,A) > \ static fc::function<fc::future<R> BOOST_PP_ENUM_TRAILING_PARAMS(n,A) > \
functor( P, R (C::*mem_func)(BOOST_PP_ENUM_PARAMS(n,A)) IS_CONST, \ functor( P, R (C::*mem_func)(BOOST_PP_ENUM_PARAMS(n,A)) IS_CONST, \
const rpc_connection::ptr& c = rpc_connection::ptr(), const char* name = nullptr ) { \ const rpc_connection::ptr& c = rpc_connection::ptr(), const char* name = nullptr ) { \
return [=](BOOST_PP_ENUM_BINARY_PARAMS(n,A,a))->fc::future<R>{ \ return [=](BOOST_PP_ENUM_BINARY_PARAMS(n,A,a))->fc::future<R>{ \

View file

@ -25,6 +25,7 @@ namespace fc { namespace json {
template<typename T> template<typename T>
struct pending_result_impl : virtual public promise<T>, virtual public pending_result { struct pending_result_impl : virtual public promise<T>, virtual public pending_result {
virtual void handle_result( const fc::value& s ) { virtual void handle_result( const fc::value& s ) {
slog( "cast %s", typeid(T).name() );
this->set_value( value_cast<T>(s) ); this->set_value( value_cast<T>(s) );
} }
protected: protected:
@ -40,13 +41,16 @@ namespace fc { namespace json {
}; };
template<typename R, typename Args> template<typename R, typename... Args>
struct rpc_server_method_impl : public rpc_server_method { struct rpc_server_method_impl : public rpc_server_method {
rpc_server_method_impl( const fc::function<R,Args>& f ):func(f){} //static_assert( fc::is_tuple<Args>::type::value, "params should be a tuple" );
rpc_server_method_impl( const fc::function<R,Args...>& f ):func(f){}
virtual value call( const value& v ) { virtual value call( const value& v ) {
return value( func( fc::value_cast<Args>( v ) ) ); // slog( "cast %s", typeid(Args).name() );
return value( call_fused( func, fc::value_cast<fc::tuple<Args...> >( v ) ) );
//return value( func( fc::value_cast<Args>( v )) );
} }
fc::function<R,Args> func; fc::function<R,Args...> func;
}; };
template<typename InterfaceType> template<typename InterfaceType>
@ -54,8 +58,8 @@ namespace fc { namespace json {
public: public:
add_method_visitor( const fc::ptr<InterfaceType>& p, fc::json::rpc_connection& c ):_ptr(p),_con(c){} add_method_visitor( const fc::ptr<InterfaceType>& p, fc::json::rpc_connection& c ):_ptr(p),_con(c){}
template<typename R, typename Args> template<typename R, typename... Args>
void operator()( const char* name, fc::function<R,Args>& meth); void operator()( const char* name, fc::function<R,Args...>& meth);
const fc::ptr<InterfaceType>& _ptr; const fc::ptr<InterfaceType>& _ptr;
fc::json::rpc_connection& _con; fc::json::rpc_connection& _con;
@ -91,6 +95,7 @@ namespace fc { namespace json {
template<typename R, typename Args > template<typename R, typename Args >
void add_method( const fc::string& name, const fc::function<R,Args>& a ) { void add_method( const fc::string& name, const fc::function<R,Args>& a ) {
static_assert( is_tuple<Args>::type::value, "is tuple" );
this->add_method( name, rpc_server_method::ptr(new detail::rpc_server_method_impl<R,Args>(a) ) ); this->add_method( name, rpc_server_method::ptr(new detail::rpc_server_method_impl<R,Args>(a) ) );
} }
@ -121,9 +126,10 @@ namespace fc { namespace json {
namespace detail { namespace detail {
template<typename InterfaceType> template<typename InterfaceType>
template<typename R, typename Args> template<typename R, typename... Args>
void add_method_visitor<InterfaceType>::operator()( const char* name, fc::function<R,Args>& meth) { void add_method_visitor<InterfaceType>::operator()( const char* name, fc::function<R,Args...>& meth) {
_con.add_method( name, rpc_server_method::ptr( new rpc_server_method_impl<R,Args>(meth) ) ); _con.add_method( name, rpc_server_method::ptr(
new rpc_server_method_impl<R,Args...>(meth) ) );
} }
} // namespace detail } // namespace detail

View file

@ -57,6 +57,7 @@ namespace fc {
#define ILIST_PARAMS(z,n,data) BOOST_PP_CAT(a,n)( fc::forward<BOOST_PP_CAT(AA,n)>( BOOST_PP_CAT(a,n) ) ) #define ILIST_PARAMS(z,n,data) BOOST_PP_CAT(a,n)( fc::forward<BOOST_PP_CAT(AA,n)>( BOOST_PP_CAT(a,n) ) )
#define ILIST_PARAMS_COPY(z,n,data) BOOST_PP_CAT(a,n)( t.BOOST_PP_CAT(a,n) ) #define ILIST_PARAMS_COPY(z,n,data) BOOST_PP_CAT(a,n)( t.BOOST_PP_CAT(a,n) )
#define VISIT_PARAMS(z,n,data) v(BOOST_PP_CAT(a,n)); #define VISIT_PARAMS(z,n,data) v(BOOST_PP_CAT(a,n));
#define LIST_MEMBERS_ON(z,n,data) data.BOOST_PP_CAT(a,n)
#define FORWARD_PARAMS(z,n,data) fc::forward<BOOST_PP_CAT(AA,n)>(BOOST_PP_CAT(a,n)) #define FORWARD_PARAMS(z,n,data) fc::forward<BOOST_PP_CAT(AA,n)>(BOOST_PP_CAT(a,n))
#define MEM_PARAMS(z,n,data) BOOST_PP_CAT(A,n) BOOST_PP_CAT(a,n); #define MEM_PARAMS(z,n,data) BOOST_PP_CAT(A,n) BOOST_PP_CAT(a,n);
#define TUPLE(z,n,unused) \ #define TUPLE(z,n,unused) \
@ -77,13 +78,20 @@ namespace fc {
template<BOOST_PP_ENUM_PARAMS( n, typename AA)> \ template<BOOST_PP_ENUM_PARAMS( n, typename AA)> \
tuple<BOOST_PP_ENUM_PARAMS(n,AA)> make_tuple( BOOST_PP_ENUM( n, RREF_PARAMS, unused) ) { \ tuple<BOOST_PP_ENUM_PARAMS(n,AA)> make_tuple( BOOST_PP_ENUM( n, RREF_PARAMS, unused) ) { \
return tuple<BOOST_PP_ENUM_PARAMS(n,AA)>( BOOST_PP_ENUM( n, FORWARD_PARAMS,unused ) ); \ return tuple<BOOST_PP_ENUM_PARAMS(n,AA)>( BOOST_PP_ENUM( n, FORWARD_PARAMS,unused ) ); \
} } \
template<typename Functor, typename Tuple> \
auto call_fused( Functor f, Tuple&& t ) \
-> decltype( f( BOOST_PP_ENUM( n, LIST_MEMBERS_ON, t) ) ) { \
return f( BOOST_PP_ENUM( n, LIST_MEMBERS_ON, t) ); \
}
template<BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(9, typename A, void)> struct tuple{}; template<BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(9, typename A, void)> struct tuple{};
BOOST_PP_REPEAT_FROM_TO( 1, 8, TUPLE, unused ) BOOST_PP_REPEAT_FROM_TO( 1, 8, TUPLE, unused )
#undef FORWARD_PARAMS #undef FORWARD_PARAMS
#undef RREF_PARAMS #undef RREF_PARAMS
#undef LIST_MEMBERS_ON
#undef ILIST_PARAMS #undef ILIST_PARAMS
#undef ILIST_PARAMS_COPY #undef ILIST_PARAMS_COPY
#undef VISIT_PARAMS #undef VISIT_PARAMS
@ -99,6 +107,18 @@ namespace fc {
inline tuple<> make_tuple(){ return tuple<>(); } inline tuple<> make_tuple(){ return tuple<>(); }
template<typename T>
struct is_tuple {
typedef fc::false_type type;
};
template<typename... T>
struct is_tuple<fc::tuple<T...> > {
typedef fc::true_type type;
};
/* /*
template<typename A> template<typename A>
struct tuple<A,void> { struct tuple<A,void> {

View file

@ -5,6 +5,9 @@
#include <fc/lexical_cast.hpp> #include <fc/lexical_cast.hpp>
#include <fc/numeric_cast.hpp> #include <fc/numeric_cast.hpp>
#include <fc/value_io.hpp> #include <fc/value_io.hpp>
#include <fc/tuple.hpp>
#include <typeinfo>
namespace fc { namespace fc {
@ -26,9 +29,9 @@ namespace fc {
virtual void operator()( const double& v ){ m_out = fc::numeric_cast<T>(v); } virtual void operator()( const double& v ){ m_out = fc::numeric_cast<T>(v); }
virtual void operator()( const bool& v ){ m_out = fc::numeric_cast<T>(v); } virtual void operator()( const bool& v ){ m_out = fc::numeric_cast<T>(v); }
virtual void operator()( const fc::string& v ) { m_out = fc::lexical_cast<T>(v); } virtual void operator()( const fc::string& v ) { m_out = fc::lexical_cast<T>(v); }
virtual void operator()( const value::object& ) { FC_THROW_MSG("bad cast"); } virtual void operator()( const value::object& ) { FC_THROW_MSG("bad cast"); }
virtual void operator()( const value::array& ) { FC_THROW_MSG("bad cast"); } virtual void operator()( const value::array& ) { FC_THROW_MSG("bad cast"); }
virtual void operator()( ) { FC_THROW_MSG("bad cast"); } virtual void operator()( ) { FC_THROW_MSG("bad cast"); }
private: private:
T& m_out; T& m_out;
}; };
@ -48,10 +51,10 @@ namespace fc {
virtual void operator()( const float& v ){ m_out = fc::lexical_cast<fc::string>(v); } virtual void operator()( const float& v ){ m_out = fc::lexical_cast<fc::string>(v); }
virtual void operator()( const double& v ){ m_out = fc::lexical_cast<fc::string>(v); } virtual void operator()( const double& v ){ m_out = fc::lexical_cast<fc::string>(v); }
virtual void operator()( const bool& v ){ m_out = fc::lexical_cast<fc::string>(v); } virtual void operator()( const bool& v ){ m_out = fc::lexical_cast<fc::string>(v); }
virtual void operator()( const fc::string& v ){ m_out = v; } virtual void operator()( const fc::string& v ){ m_out = v; }
virtual void operator()( const value::object& ) { FC_THROW_MSG("bad cast"); } virtual void operator()( const value::object& ) { FC_THROW_MSG("bad cast"); }
virtual void operator()( const value::array& ) { FC_THROW_MSG("bad cast"); } virtual void operator()( const value::array& ) { FC_THROW_MSG("bad cast"); }
virtual void operator()( ) { FC_THROW_MSG("bad cast"); } virtual void operator()( ) { FC_THROW_MSG("bad cast"); }
private: private:
fc::string& m_out; fc::string& m_out;
@ -122,14 +125,45 @@ namespace fc {
virtual void operator()( const value::array& ) { FC_THROW_MSG("bad cast");} virtual void operator()( const value::array& ) { FC_THROW_MSG("bad cast");}
virtual void operator()( ) { } virtual void operator()( ) { }
}; };
template<typename IsTuple=fc::false_type>
struct cast_if_tuple {
template<typename T>
static T cast( const value& v ) {
slog( "cast non tuple %s", typeid(T).name() );
T out;
v.visit(cast_visitor<T>(out));
return out;
}
};
template<>
struct cast_if_tuple<fc::true_type> {
struct member_visitor {
member_visitor( const value& v )
:_val(v),idx(0){}
template<typename Member>
void operator()( Member& m ) {
m = value_cast<Member>(_val[idx]);
++idx;
}
const value& _val;
int idx;
};
template<typename T>
static T cast( const value& v ) {
T out;
out.visit( member_visitor(v) );
slog( "cast tuple" );
// v.visit(cast_visitor<T>(out));
return out;
}
};
template<typename IsReflected=fc::false_type> template<typename IsReflected=fc::false_type>
struct cast_if_reflected { struct cast_if_reflected {
template<typename T> template<typename T>
static T cast( const value& v ) { static T cast( const value& v ) {
T out; return cast_if_tuple<typename is_tuple<T>::type>::template cast<T>(v);
v.visit(cast_visitor<T>(out));
return out;
} }
}; };

View file

@ -132,7 +132,7 @@ namespace fc {
} }
else { else {
if( !is_optional< typename fc::remove_reference<decltype(c.*p)>::type >::type::value ) { if( !is_optional< typename fc::remove_reference<decltype(c.*p)>::type >::type::value ) {
wlog( "unable to find name: '%1%'",name); wlog( "unable to find name: '%s'",name);
} }
} }
} }

View file

@ -587,7 +587,7 @@ char* read_key_val( value::object& obj, bool sc, char* in, char* end, fc::json::
if( sc ) { // if we expect a , if( sc ) { // if we expect a ,
if( *name != ',' ) { // but didn't get one if( *name != ',' ) { // but didn't get one
if( *name != '}' ) if( *name != '}' )
wlog( "expected ',' or '}' but got %1%", name ); // warn and accept name wlog( "expected ',' or '}' but got '%s'", name ); // warn and accept name
} else { // we got the exepcted , read the expected name } else { // we got the exepcted , read the expected name
name = fc::json::read_value( name_end, end, name_end ); name = fc::json::read_value( name_end, end, name_end );
} }
@ -757,15 +757,15 @@ fc::value to_value( char* start, char* end, error_collector& ec ) {
} }
case 'n': { case 'n': {
temp_set move_end(ve,'\0'); temp_set move_end(ve,'\0');
if( strcmp(s,"null" ) ) return value(); if( strcmp(s,"null" ) == 0) return value();
} }
case 't': { case 't': {
temp_set move_end(ve,'\0'); temp_set move_end(ve,'\0');
if( strcmp(s,"true" ) ) return true; if( strcmp(s,"true" ) == 0) return true;
} }
case 'f': { case 'f': {
temp_set move_end(ve,'\0'); temp_set move_end(ve,'\0');
if( strcmp(s,"false" ) ) return false; if( strcmp(s,"false" ) == 0) return false;
} }
default: default:

View file

@ -64,6 +64,7 @@ namespace fc { namespace json {
value nul; value nul;
const value& params = (p_itr != end) ? p_itr->val : nul; const value& params = (p_itr != end) ? p_itr->val : nul;
slog( "params '%s'", to_string( params ).c_str() );
if( id_itr != end ) { // capture reply if( id_itr != end ) { // capture reply
try { try {

View file

@ -33,11 +33,9 @@ namespace fc {
return *this; return *this;
} }
size_t stringstream::readsome( char* buf, size_t len ) { size_t stringstream::readsome( char* buf, size_t len ) {
slog("");
return my->ss.readsome(buf,len); return my->ss.readsome(buf,len);
} }
istream& stringstream::read( char* buf, size_t len ) { istream& stringstream::read( char* buf, size_t len ) {
slog("");
my->ss.read(buf,len); my->ss.read(buf,len);
return *this; return *this;
} }

View file

@ -9,9 +9,8 @@ namespace fc {
class tcp_socket::impl { class tcp_socket::impl {
public: public:
impl():_sock( fc::asio::default_io_service() ){ slog( "sock %p", this); } impl():_sock( fc::asio::default_io_service() ){ }
~impl(){ ~impl(){
slog( "~sock %p", this );
if( _sock.is_open() ) _sock.close(); if( _sock.is_open() ) _sock.close();
} }