Bytemaster's Boost Libraries
/Users/dlarimer/dev/libs/rpc/include/boost/rpc/protocol_buffer.hpp
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 
 All Classes Namespaces Files Functions Variables Typedefs Defines