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/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_trailing_params.hpp>
#include <boost/preprocessor/facilities/empty.hpp>
namespace fc { namespace json {
//static std::function<fc::future<R>( BOOST_PP_ENUM_PARAMS(n,A) ) >
namespace detail {
struct rpc_member {
#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)> \
static fc::function<fc::future<R> BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,A) > \
template<typename R, typename C, typename P BOOST_PP_ENUM_TRAILING_PARAMS( n, typename 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, \
const rpc_connection::ptr& c = rpc_connection::ptr(), const char* name = nullptr ) { \
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>
struct pending_result_impl : virtual public promise<T>, virtual public pending_result {
virtual void handle_result( const fc::value& s ) {
slog( "cast %s", typeid(T).name() );
this->set_value( value_cast<T>(s) );
}
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 {
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 ) {
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>
@ -54,8 +58,8 @@ namespace fc { namespace json {
public:
add_method_visitor( const fc::ptr<InterfaceType>& p, fc::json::rpc_connection& c ):_ptr(p),_con(c){}
template<typename R, typename Args>
void operator()( const char* name, fc::function<R,Args>& meth);
template<typename R, typename... Args>
void operator()( const char* name, fc::function<R,Args...>& meth);
const fc::ptr<InterfaceType>& _ptr;
fc::json::rpc_connection& _con;
@ -91,6 +95,7 @@ namespace fc { namespace json {
template<typename R, typename Args >
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) ) );
}
@ -121,9 +126,10 @@ namespace fc { namespace json {
namespace detail {
template<typename InterfaceType>
template<typename R, typename Args>
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) ) );
template<typename R, typename... Args>
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) ) );
}
} // 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_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 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 MEM_PARAMS(z,n,data) BOOST_PP_CAT(A,n) BOOST_PP_CAT(a,n);
#define TUPLE(z,n,unused) \
@ -77,13 +78,20 @@ namespace fc {
template<BOOST_PP_ENUM_PARAMS( n, typename AA)> \
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 ) ); \
}
} \
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{};
BOOST_PP_REPEAT_FROM_TO( 1, 8, TUPLE, unused )
#undef FORWARD_PARAMS
#undef RREF_PARAMS
#undef LIST_MEMBERS_ON
#undef ILIST_PARAMS
#undef ILIST_PARAMS_COPY
#undef VISIT_PARAMS
@ -99,6 +107,18 @@ namespace fc {
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>
struct tuple<A,void> {

View file

@ -5,6 +5,9 @@
#include <fc/lexical_cast.hpp>
#include <fc/numeric_cast.hpp>
#include <fc/value_io.hpp>
#include <fc/tuple.hpp>
#include <typeinfo>
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 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 value::object& ) { 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()( const value::object& ) { FC_THROW_MSG("bad cast"); }
virtual void operator()( const value::array& ) { FC_THROW_MSG("bad cast"); }
virtual void operator()( ) { FC_THROW_MSG("bad cast"); }
private:
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 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 fc::string& v ){ m_out = v; }
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()( ) { FC_THROW_MSG("bad cast"); }
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::array& ) { FC_THROW_MSG("bad cast"); }
virtual void operator()( ) { FC_THROW_MSG("bad cast"); }
private:
fc::string& m_out;
@ -122,14 +125,45 @@ namespace fc {
virtual void operator()( const value::array& ) { FC_THROW_MSG("bad cast");}
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>
struct cast_if_reflected {
template<typename T>
static T cast( const value& v ) {
T out;
v.visit(cast_visitor<T>(out));
return out;
return cast_if_tuple<typename is_tuple<T>::type>::template cast<T>(v);
}
};

View file

@ -132,7 +132,7 @@ namespace fc {
}
else {
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( *name != ',' ) { // but didn't get one
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
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': {
temp_set move_end(ve,'\0');
if( strcmp(s,"null" ) ) return value();
if( strcmp(s,"null" ) == 0) return value();
}
case 't': {
temp_set move_end(ve,'\0');
if( strcmp(s,"true" ) ) return true;
if( strcmp(s,"true" ) == 0) return true;
}
case 'f': {
temp_set move_end(ve,'\0');
if( strcmp(s,"false" ) ) return false;
if( strcmp(s,"false" ) == 0) return false;
}
default:

View file

@ -64,6 +64,7 @@ namespace fc { namespace json {
value 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
try {

View file

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

View file

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