Bytemaster's Boost Libraries
|
00001 #ifndef _BOOST_RPC_PROTOCOL_BUFFERS_HPP_ 00002 #define _BOOST_RPC_PROTOCOL_BUFFERS_HPP_ 00003 #include <boost/rpc/datastream/datastream.hpp> 00004 #include <boost/rpc/varint.hpp> 00005 #include <boost/rpc/errors.hpp> 00006 #include <boost/rpc/required.hpp> 00007 #include <boost/reflect/reflect.hpp> 00008 #include <boost/optional.hpp> 00009 #include <boost/throw_exception.hpp> 00010 #include <boost/fusion/container/vector.hpp> 00011 #include <boost/fusion/algorithm.hpp> 00012 #include <boost/fusion/support/is_sequence.hpp> 00013 #include <boost/fusion/sequence/intrinsic/size.hpp> 00014 00015 #include <iostream> 00016 #include <boost/cmt/log/log.hpp> 00017 00018 namespace boost { namespace rpc { namespace protocol_buffer { 00019 00020 namespace detail { 00021 00022 enum protocol_buf_wire_types 00023 { 00024 varint = 0, 00025 bit64 = 1, 00026 length_delimited = 2, 00027 bit8 = 3, // custom 00028 bit16 = 4, // custom 00029 bit32 = 5, 00030 bit0 = 6 // field is either there or not, size 0 00031 }; 00032 00033 template<typename T, int fund, uint32_t size> 00034 struct get_wire_type_impl{ enum wire_type { value = length_delimited }; }; 00035 00036 template<> 00037 struct get_wire_type_impl<unsigned_int,0,1>{ enum wire_type { value = varint }; }; 00038 template<> 00039 struct get_wire_type_impl<signed_int,0,1> { enum wire_type { value = varint }; }; 00040 00041 template<typename T> 00042 struct get_wire_type_impl<T,1,1>{ enum wire_type { value = bit8 }; }; 00043 template<typename T> 00044 struct get_wire_type_impl<T,1,2>{ enum wire_type { value = bit16 }; }; 00045 template<typename T> 00046 struct get_wire_type_impl<T,1,4>{ enum wire_type { value = bit32 }; }; 00047 template<typename T> 00048 struct get_wire_type_impl<T,1,8>{ enum wire_type { value = bit64 }; }; 00049 template<typename T> 00050 struct get_wire_type : get_wire_type_impl<T,boost::is_fundamental<T>::value,sizeof(T)>{}; 00051 00052 00053 template<typename T,typename T2> 00054 bool unpack_message_visitor( boost::rpc::datastream<T2>& is, T& val ); 00055 00056 template<typename DataStreamType> 00057 class unpack_field_visitor 00058 { 00059 boost::rpc::datastream<DataStreamType>& is; 00060 uint32_t m_field; 00061 uint32_t m_type; 00062 public: 00063 unpack_field_visitor( boost::rpc::datastream<DataStreamType>& _is, uint32_t f = -1, uint32_t t = -1 ) 00064 :is(_is),m_field(f),m_type(t),error(true){} 00065 bool error; 00066 template<typename Class> 00067 void start( Class, const char* anem ){} 00068 00069 template<typename Class> 00070 void end( Class, const char* anem ){} 00071 00072 /* 00073 * This method handles all fundamental types 00074 */ 00075 template<typename T, typename Flags> 00076 void unpack( T& value, const char* name, Flags key, boost::true_type _is_fundamental ) 00077 { 00078 if( key != m_field || m_type != get_wire_type<T>::value ) 00079 { 00080 BOOST_THROW_EXCEPTION( boost::rpc::protocol_buffer::key_type_mismatch(name) ); 00081 error = true; 00082 return; 00083 } 00084 is >> value; 00085 error = !is.valid(); 00086 } 00087 /* 00088 * This method handles all fundamental types 00089 */ 00090 template<typename T, typename Flags> 00091 void unpack( T& value, const char* name, Flags key ) 00092 { 00093 dlog( "key %1% m_field %2% m_type %3%", key, m_field, m_type ); 00094 unpack( value, name, key, typename boost::is_fundamental<T>::type() ); 00095 } 00096 /* 00097 * This method handles the general case where T is a nested type 00098 * (not string,varint,fundamental,container,optional, or required) 00099 */ 00100 template<typename T, typename Flags> 00101 void unpack( T& value, const char* name, Flags key, boost::false_type _is_not_fundamental ) 00102 { 00103 if( key != m_field || m_type != get_wire_type<T>::value ) 00104 { 00105 std::cerr << "Error unpacking field '"<<name<<"', key/type mismatch\n"; 00106 BOOST_THROW_EXCEPTION( boost::rpc::protocol_buffer::key_type_mismatch(name) ); 00107 error = true; 00108 return; 00109 } 00110 unsigned_int size; 00111 is >> size; 00112 00113 if( is.remaining() >= size.value ) 00114 { 00115 datastream<DataStreamType> is2( is.pos(), size.value ); 00116 if( !unpack_message_visitor( is2, value ) ) 00117 return; // error! 00118 } 00119 else 00120 { 00121 std::cerr << "Error unpacking field '"<<name<<"', size is larger than remaining datastream\n"; 00122 BOOST_THROW_EXCEPTION( boost::rpc::protocol_buffer::field_size_larger_than_buffer(name) ); 00123 error = true; 00124 } 00125 is.skip(size); 00126 error = !is.valid(); 00127 } 00128 template<typename Flags> 00129 void unpack( signed_int& value, const char* name, Flags key, boost::false_type _is_not_fundamental ) 00130 { 00131 if( key != m_field || m_type != varint ) 00132 { 00133 std::cerr << "Error unpacking field '"<<name<<"', key/type mismatch\n"; 00134 BOOST_THROW_EXCEPTION( boost::rpc::protocol_buffer::key_type_mismatch(name) ); 00135 error = true; 00136 return; 00137 } 00138 is >> value; 00139 error = false; 00140 } 00141 template<typename Flags> 00142 void unpack( unsigned_int& value, const char* name, Flags key, boost::false_type _is_not_fundamental ) 00143 { 00144 if( key != m_field || m_type != varint ) 00145 { 00146 std::cerr << "Error unpacking field '"<<name<<"', key/type mismatch\n"; 00147 BOOST_THROW_EXCEPTION( boost::rpc::protocol_buffer::key_type_mismatch(name) ); 00148 error = true; 00149 return; 00150 } 00151 is >> value; 00152 error = false; 00153 } 00154 00155 template<typename Flags> 00156 void unpack( std::string& str, const char* name, Flags key, boost::false_type _is_not_fundamental ) 00157 { 00158 if( key != m_field || m_type != length_delimited ) 00159 { 00160 std::cerr << "Error unpacking field '"<<name<<"', key/type mismatch\n"; 00161 BOOST_THROW_EXCEPTION( boost::rpc::protocol_buffer::key_type_mismatch(name) ); 00162 error = true; 00163 return; 00164 } 00165 unsigned_int size; 00166 is >> size; 00167 DataStreamType po = is.pos(); 00168 00169 if( is.remaining() >= size.value ) 00170 { 00171 str = std::string( po, size.value ); 00172 is.skip(size.value); 00173 error = false; 00174 return; 00175 } 00176 error = true; 00177 } 00178 00179 template<typename T, typename Flags> 00180 void unpack( boost::optional<T>& value, const char* name, Flags key, boost::false_type _is_not_fundamental ) 00181 { 00182 if( !value ) 00183 value = T(); 00184 wlog( "unapcking optional %1%", name ); 00185 unpack( *value, name, key,typename boost::is_fundamental<T>::type() ); 00186 } 00187 template<typename T, typename Flags> 00188 void unpack( boost::rpc::required<T>& value, const char* name, Flags key, boost::false_type _is_not_fundamental ) 00189 { 00190 if( !value ) 00191 value = T(); 00192 wlog( "unapcking required %1%", name ); 00193 unpack( *value, name, key, typename boost::is_fundamental<T>::type() ); 00194 } 00195 00196 /* 00197 * This is the method called by the visitor, it gets dispatched to the proper 00198 * unpack mehtod. 00199 */ 00200 template<typename Class, typename T, typename Flags> 00201 void accept_member( Class& c, T (Class::*p), const char* name, Flags key ) 00202 { 00203 unpack( c.*p, name, key, typename boost::is_fundamental<T>::type() ); 00204 } 00205 00206 template<typename Class, typename Field, typename Alloc, template<typename,typename> class Container, typename Flags> 00207 void accept_member( Class& c, Container<Field,Alloc> (Class::*p), const char* name, Flags key ) 00208 { 00209 if( key != m_field || m_type != length_delimited ) 00210 { 00211 std::cerr << "Error unpacking field '"<<name<<"', key/type mismatch\n"; 00212 BOOST_THROW_EXCEPTION( boost::rpc::protocol_buffer::key_type_mismatch(name) ); 00213 error = true; 00214 return; 00215 } 00216 00217 unsigned_int size; 00218 is >> size; 00219 00220 if( is.remaining() >= size.value ) 00221 { 00222 datastream<DataStreamType> is2( is.pos(), size.value ); 00223 (c.*p).resize( (c.*p).size()+1); 00224 if( !unpack_message_visitor( is2, (c.*p).back() ) ) 00225 { 00226 (c.*p).pop_back(); 00227 return; // error! 00228 } 00229 } 00230 else 00231 { 00232 std::cerr << "Error unpacking field '"<<name<<"', size is larger than remaining datastream\n"; 00233 BOOST_THROW_EXCEPTION( boost::rpc::protocol_buffer::field_size_larger_than_buffer(name) ); 00234 error = true; 00235 } 00236 is.skip(size); 00237 error = !is.valid(); 00238 } 00239 00240 template<typename Class, typename Alloc, template<typename,typename> class Container, typename Flags> 00241 void accept_member( Class& c, Container<std::string,Alloc> (Class::*p), const char* name, Flags key ) 00242 { 00243 if( key != m_field || m_type != length_delimited ) 00244 { 00245 std::cerr << "Error unpacking field '"<<name<<"', key/type mismatch\n"; 00246 BOOST_THROW_EXCEPTION( boost::rpc::protocol_buffer::key_type_mismatch(name) ); 00247 error = true; 00248 return; 00249 } 00250 00251 unsigned_int size; 00252 is >> size; 00253 00254 DataStreamType po = is.pos(); 00255 00256 if( is.remaining() >= size.value ) 00257 { 00258 (c.*p).push_back( std::string( po, size.value ) ); 00259 is.skip(size.value); 00260 error = false; 00261 return; 00262 } 00263 } 00264 00265 template<typename Class> 00266 void not_found( Class c, uint32_t field ) 00267 { 00268 BOOST_THROW_EXCEPTION( boost::rpc::protocol_buffer::field_not_found() ); 00269 } 00270 00271 }; 00272 00273 00274 template<typename T, typename T2, typename Flags> 00275 bool unpack_field( boost::rpc::datastream<T2>& is, T& val, Flags key, int type ) 00276 { 00277 unpack_field_visitor<T2> upfv(is, key, type); 00278 boost::reflect::reflector<T>::visit( val, upfv, key ); 00279 return !upfv.error; 00280 } 00281 template<typename T2, typename Flags> 00282 bool unpack_field( boost::rpc::datastream<T2>& is, std::string& val, Flags key, int type ) 00283 { 00284 unsigned_int size; 00285 is >> size; 00286 T2 p = is.pos(); 00287 is.skip(size.value); 00288 if( is.valid() ) 00289 { 00290 val = std::string( p, is.pos() ); 00291 } 00292 return !is.valid(); 00293 } 00294 00295 /* 00296 * By default, we can simply use the unpack_field() calls which use 00297 * reflect::reflect<>, but this class is specialized for fusion sequences. 00298 */ 00299 template<typename IsSequence> 00300 struct unpack_message_selector 00301 { 00302 template<typename T,typename T2> 00303 static inline bool unpack_message( boost::rpc::datastream<T2>& is, T& val ) 00304 { 00305 // unpack_message_selector<T>::unpack_message( is, val ); 00306 while( is.remaining() ) 00307 { 00308 // unpack key 00309 unsigned_int tkey; 00310 is >> tkey; 00311 if( !is.valid() ) 00312 return false; 00313 00314 int type = tkey.value & 0x07; 00315 uint32_t key = tkey.value >> 3; 00316 if( !unpack_field( is, val, key, type ) ) 00317 { 00318 std::cerr <<"error unpacking field "<<key<<std::endl; 00319 return false; 00320 } 00321 } 00322 return true; 00323 } 00324 }; 00325 /* 00326 * Specialization for fusion sequences. 00327 */ 00328 template<> 00329 struct unpack_message_selector<boost::integral_constant<bool, true> > 00330 { 00331 /* 00332 * Run-time access to boost::fusion::vector<> requires special support 00333 * to provide "random access" to the fields. 00334 * 00335 * @todo Convert the dynamic key lookup sequence into a binary search 00336 * instead of a linear search. Fortunately the number of fields in 00337 * the vector should be a relatively small number. 00338 */ 00339 template<typename Sequence, int32_t Index = 00340 boost::fusion::result_of::size<Sequence>::type::value> 00341 struct helper 00342 { 00343 template<typename StreamType> 00344 static inline bool unpack_field( boost::rpc::datastream<StreamType>& is, 00345 Sequence& seq, uint32_t key, uint32_t type ) 00346 { 00347 if( (Index -1)== key ) 00348 { 00349 unpack_field_visitor<StreamType> ufv( is, key, type ); 00350 ufv.unpack( boost::fusion::at_c<Index-1>(seq), 0, key ); 00351 return true; 00352 } 00353 else 00354 { 00355 helper<Sequence,(Index-1)>::unpack_field( is, seq, key, type ); 00356 } 00357 } 00358 }; 00359 00360 template<typename Sequence> 00361 struct helper<Sequence,0> 00362 { 00363 template<typename StreamType> 00364 static inline bool unpack_field( boost::rpc::datastream<StreamType>& is, 00365 Sequence& seq, uint32_t key, uint32_t type ) 00366 { 00367 return false; 00368 } 00369 }; 00370 00371 template<typename Sequence,typename T2> 00372 static inline bool unpack_message( boost::rpc::datastream<T2>& is, Sequence& val ) 00373 { 00374 while( is.remaining() ) 00375 { 00376 // unpack key 00377 unsigned_int tkey; 00378 is >> tkey; 00379 if( !is.valid() ) 00380 return false; 00381 00382 int type = tkey.value & 0x07; 00383 uint32_t key = tkey.value >> 3; 00384 if( !helper<Sequence>::unpack_field( is, val, key, type ) ) 00385 { 00386 std::cerr <<"error unpacking field "<<key<<std::endl; 00387 return false; 00388 } 00389 } 00390 return true; 00391 } 00392 }; 00393 00394 00395 /* 00396 * Iterates over the fields in the message and unpacks each 00397 * field as it is found. 00398 */ 00399 template<typename T,typename T2> 00400 bool unpack_message_visitor( boost::rpc::datastream<T2>& is, T& val ) 00401 { 00402 return unpack_message_selector<typename boost::fusion::traits::is_sequence<T>::type>::unpack_message(is,val); 00403 } 00404 00405 00406 template<typename DataStreamType> 00407 class pack_message_visitor 00408 { 00409 public: 00410 pack_message_visitor( boost::rpc::datastream<DataStreamType>& os ) 00411 :m_os(os){} 00412 00413 template<typename Class> 00414 void start( Class, const char* anem ){} 00415 00416 template<typename Class> 00417 void end( Class, const char* anem ){} 00418 00419 /* 00420 * This method handles all fundamental types 00421 */ 00422 template<typename T, typename Flags> 00423 void pack_field( const T& value, const char* name, Flags key, boost::true_type _is_fundamental ) 00424 { 00425 m_os << unsigned_int( uint32_t(key) << 3 | get_wire_type<T>::value ); 00426 m_os << value; 00427 } 00428 00429 /* 00430 * This method handles the general case where T is a nested type 00431 * (not string,varint,fundamental,container,optional, or required) 00432 */ 00433 template< typename T, typename Flags> 00434 void pack_field( const T& value, const char* name, Flags key, boost::false_type _is_not_fundamental ) 00435 { 00436 m_os <<unsigned_int( uint32_t(key) << 3 | length_delimited ); 00437 00438 unsigned_int s(boost::rpc::protocol_buffer::packsize(value)); 00439 m_os << s; 00440 pack( value ); 00441 } 00442 00443 template<typename DST> 00444 struct visit_sequence 00445 { 00446 visit_sequence( datastream<DST>& _ds ):id(0),pmv(_ds){} 00447 00448 mutable uint32_t id; 00449 mutable pack_message_visitor<DST> pmv; 00450 00451 template<typename T> 00452 void operator() ( const T& v )const 00453 { 00454 pmv.pack_field(v,0,id, typename boost::is_fundamental<T>::type()); 00455 ++id; 00456 } 00457 }; 00458 00459 template< typename T> 00460 void pack( const T& value, boost::false_type _is_not_fundamental, boost::mpl::true_ _is_fusion_sequence) 00461 { 00462 visit_sequence<DataStreamType> pack_vector(m_os); 00463 boost::fusion::for_each( value, pack_vector ); 00464 } 00465 template< typename T> 00466 void pack( const T& value, boost::false_type _is_not_fundamental, boost::mpl::false_ _is_not_fusion_sequence) 00467 { 00468 detail::pack_message_visitor<DataStreamType> pack_visitor( m_os ); 00469 boost::reflect::reflector<T>::visit( value, pack_visitor, -1 ); 00470 } 00471 00472 void pack( const std::string& value, boost::false_type _is_not_fundamental, boost::mpl::false_ _is_not_fusion_sequence) 00473 { 00474 uint32_t size = value.size(); 00475 m_os <<unsigned_int( size ); 00476 m_os.write( value.c_str(), size ); 00477 } 00478 00479 template< typename T > 00480 void pack( const T& value, boost::true_type _is_fundamental, boost::mpl::false_ _is_not_fusion_sequence) 00481 { 00482 m_os << value; 00483 } 00484 template< typename T > 00485 void pack( const T& value ) 00486 { 00487 pack( value, typename boost::is_fundamental<T>::type(), typename boost::fusion::traits::is_sequence<T>::type() ); 00488 } 00489 00490 template<typename Flags> 00491 void pack_field( const signed_int& value, const char* name, Flags key, boost::false_type _is_not_fundamental ) 00492 { 00493 m_os << unsigned_int( uint32_t(key) << 3 | varint ); 00494 m_os << value; 00495 } 00496 template<typename Flags> 00497 void pack_field( const unsigned_int& value, const char* name, Flags key, boost::false_type _is_not_fundamental ) 00498 { 00499 m_os << unsigned_int( uint32_t(key) << 3 | varint ); 00500 m_os << value; 00501 } 00502 template<typename Flags> 00503 void pack_field( const std::string& value, const char* name, Flags key, boost::false_type _is_not_fundamental ) 00504 { 00505 m_os <<unsigned_int( uint32_t(key) << 3 | length_delimited ); 00506 pack( value ); 00507 } 00508 template<typename T, typename Flags> 00509 void pack_field( const boost::optional<T>& value, const char* name, Flags key, boost::false_type _is_not_fundamental ) 00510 { 00511 if( !!value ) 00512 pack_field( *value, name, key, typename boost::is_fundamental<T>::type() ); 00513 } 00514 template<typename T, typename Flags> 00515 void pack_field( const typename boost::rpc::required<T>& value, const char* name, Flags key, boost::false_type _is_not_fundamental ) 00516 { 00517 if( !!value ) 00518 pack_field( *value, name, key, typename boost::is_fundamental<T>::type() ); 00519 else 00520 BOOST_THROW_EXCEPTION( boost::rpc::required_field_not_set() ); 00521 } 00522 00523 template<typename Class, typename T, typename Flags> 00524 void accept_member( const Class& c, T (Class::*p), const char* name, Flags key ) 00525 { 00526 pack_field( c.*p, name, key, typename boost::is_fundamental<T>::type() ); 00527 } 00528 00529 00530 00531 00532 template<typename Class, typename Field, typename Alloc, template<typename,typename> class Container, typename Flags> 00533 void accept_member( const Class& c, Container<Field,Alloc> (Class::*p), const char* name, Flags key ) 00534 { 00535 if( (c.*p).size() ) 00536 { 00537 typename Container<Field,Alloc >::const_iterator itr = (c.*p).begin(); 00538 typename Container<Field,Alloc >::const_iterator end = (c.*p).end(); 00539 while( itr != end ) 00540 { 00541 pack_field( *itr, name, key, typename boost::is_fundamental<Field>::type() ); 00542 ++itr; 00543 } 00544 } 00545 } 00546 template<typename Class> 00547 void not_found( Class c, uint32_t field ) 00548 { 00549 BOOST_THROW_EXCEPTION( boost::rpc::protocol_buffer::field_not_found() ); 00550 } 00551 00552 private: 00553 boost::rpc::datastream<DataStreamType>& m_os; 00554 }; 00555 00556 } // namespace detail 00557 00558 template<typename T> 00559 size_t packsize( const T& v ) 00560 { 00561 boost::rpc::datastream<size_t> ps; 00562 detail::pack_message_visitor<size_t> size_visitor( ps ); 00563 size_visitor.pack(v); 00564 // boost::reflect::reflector<T>::visit( const_cast<T&>(v), size_visitor, -1 ); 00565 return ps.tellp(); 00566 } 00567 template<typename T> 00568 void pack( char* loc, size_t loc_size, const T& v ) 00569 { 00570 boost::rpc::datastream<char*> ds(loc, loc_size); 00571 detail::pack_message_visitor<char*> pack_visitor( ds ); 00572 pack_visitor.pack(v); 00573 } 00574 template<typename T, typename DataStreamType> 00575 void pack( boost::rpc::datastream<DataStreamType>& ds, const T& v ) 00576 { 00577 detail::pack_message_visitor<DataStreamType> pack_visitor( ds ); 00578 pack_visitor.pack(v); 00579 } 00580 template<typename T> 00581 void pack( std::vector<char>& msg, const T& v ) 00582 { 00583 msg.resize(packsize(v)); 00584 pack( &msg.front(), msg.size(), v ); 00585 } 00586 template<typename T> 00587 void pack( std::string& msg, const T& v ) 00588 { 00589 msg.resize(packsize(v)); 00590 pack( msg.c_str(), msg.size(), v ); 00591 } 00592 00593 template<typename T> 00594 void unpack( const char* msg, size_t msg_size, T& v ) 00595 { 00596 elog( "unpack '%1%'", boost::reflect::get_typeinfo<T>::name() ); 00597 boost::rpc::datastream<const char*> ds(msg,msg_size); 00598 detail::unpack_message_visitor( ds, v ); 00599 // detail::unpack_field_visitor<const char*> visitor(ds,0,detail::get_wire_type<T>::value ); 00600 // visitor.unpack( v, 0, 0 ); 00601 00602 } 00603 00604 template<typename T> 00605 void unpack( const std::vector<char>& msg, T& v ) 00606 { 00607 if( msg.size() ) 00608 unpack( &msg.front(), msg.size(), v ); 00609 } 00610 00611 00612 } } }// boost::rpc::protocol_buffer 00613 00614 #endif // _BOOST_RPC_DETAIL_PROTOCOL_BUFFERS_HPP_ 00615