Home | History | Annotate | Download | only in rpc
      1 #ifndef ANDROID_PDX_RPC_SERIALIZABLE_H_
      2 #define ANDROID_PDX_RPC_SERIALIZABLE_H_
      3 
      4 #include <cstddef>
      5 #include <string>
      6 #include <tuple>
      7 
      8 #include <pdx/message_reader.h>
      9 #include <pdx/message_writer.h>
     10 
     11 #include "macros.h"
     12 #include "serialization.h"
     13 
     14 namespace android {
     15 namespace pdx {
     16 namespace rpc {
     17 
     18 // This file provides utilities to define serializable types for communication
     19 // between clients and services. Supporting efficient, typed communication
     20 // protocols is the primary goal, NOT providing a general-purpose solution for
     21 // all your C++ serialization needs. Features that are not aligned to the goals
     22 // are not supported, such as static/const member serialization and serializable
     23 // types with virtual methods (requiring a virtual destructor).
     24 
     25 // Captures the type and value of a pointer to member. Pointer to members are
     26 // essentially compile-time constant offsets that can be stored in the type
     27 // system without adding to the size of the structures they describe. This
     28 // library uses this property to implement a limited form of reflection for
     29 // serialization/deserialization functions.
     30 template <typename T, T>
     31 struct MemberPointer;
     32 
     33 template <typename Type, typename Class, Type Class::*Pointer>
     34 struct MemberPointer<Type Class::*, Pointer> {
     35   // Type of the member pointer this type represents.
     36   using PointerType = Type Class::*;
     37 
     38   // Resolves a pointer to member with the given instance, yielding a
     39   // reference to the member in that instance.
     40   static Type& Resolve(Class& instance) { return (instance.*Pointer); }
     41   static const Type& Resolve(const Class& instance) {
     42     return (instance.*Pointer);
     43   }
     44 };
     45 
     46 // Describes a set of members to be serialized/deserialized by this library. The
     47 // parameter pack MemberPointers takes a list of MemberPointer types that
     48 // describe each member to participate in serialization/deserialization.
     49 template <typename T, typename... MemberPointers>
     50 struct SerializableMembersType {
     51   using Type = T;
     52 
     53   // The number of member pointers described by this type.
     54   enum : std::size_t { MemberCount = sizeof...(MemberPointers) };
     55 
     56   // The member pointers described by this type.
     57   using Members = std::tuple<MemberPointers...>;
     58 
     59   // Accessor for individual member pointer types.
     60   template <std::size_t Index>
     61   using At = typename std::tuple_element<Index, Members>::type;
     62 };
     63 
     64 // Classes must do the following to correctly define a serializable type:
     65 //     1. Define a type called "SerializableMembers" as a template instantiation
     66 //        of SerializableMembersType, describing the members of the class to
     67 //        participate in serialization (presumably all of them). Use the macro
     68 //        PDX_SERIALIZABLE_MEMBERS(...) below to aid the correct type
     69 //        definition. This type should be private to prevent leaking member
     70 //        access information.
     71 //     2. Make SerializableTraits and HasSerilizableMembers types a friend of
     72 //        the class. The macro PDX_SERIALIZABLE_MEMEBRS(...) takes care of
     73 //        this automatically.
     74 //     3. Define a public default constructor, if necessary. Deserialization
     75 //        requires instances to be default-constructible.
     76 //
     77 // Example usage:
     78 //     class MySerializableType : public AnotherBaseType {
     79 //      public:
     80 //       MySerializableType();
     81 //       ...
     82 //      private:
     83 //       int a;
     84 //       string b;
     85 //       PDX_SERIALIZABLE_MEMBERS(MySerializableType, a, b);
     86 //     };
     87 //
     88 // Note that const and static member serialization is not supported.
     89 
     90 template <typename T>
     91 class SerializableTraits {
     92  public:
     93   // Gets the serialized size of type T.
     94   static std::size_t GetSerializedSize(const T& value) {
     95     return GetEncodingSize(EncodeArrayType(SerializableMembers::MemberCount)) +
     96            GetMembersSize<SerializableMembers>(value);
     97   }
     98 
     99   // Serializes type T.
    100   static void SerializeObject(const T& value, MessageWriter* writer,
    101                               void*& buffer) {
    102     SerializeArrayEncoding(EncodeArrayType(SerializableMembers::MemberCount),
    103                            SerializableMembers::MemberCount, buffer);
    104     SerializeMembers<SerializableMembers>(value, writer, buffer);
    105   }
    106 
    107   // Deserializes type T.
    108   static ErrorType DeserializeObject(T* value, MessageReader* reader,
    109                                      const void*& start, const void* end) {
    110     EncodingType encoding;
    111     std::size_t size;
    112 
    113     if (const auto error =
    114             DeserializeArrayType(&encoding, &size, reader, start, end)) {
    115       return error;
    116     } else if (size != SerializableMembers::MemberCount) {
    117       return ErrorCode::UNEXPECTED_TYPE_SIZE;
    118     } else {
    119       return DeserializeMembers<SerializableMembers>(value, reader, start, end);
    120     }
    121   }
    122 
    123  private:
    124   using SerializableMembers = typename T::SerializableMembers;
    125 };
    126 
    127 // Utility macro to define a MemberPointer type for a member name.
    128 #define PDX_MEMBER_POINTER(type, member) \
    129   ::android::pdx::rpc::MemberPointer<decltype(&type::member), &type::member>
    130 
    131 // Defines a list of MemberPointer types given a list of member names.
    132 #define PDX_MEMBERS(type, ... /*members*/) \
    133   PDX_FOR_EACH_BINARY_LIST(PDX_MEMBER_POINTER, type, __VA_ARGS__)
    134 
    135 // Defines the serializable members of a type given a list of member names and
    136 // befriends SerializableTraits and HasSerializableMembers for the class. This
    137 // macro handles requirements #1 and #2 above.
    138 #define PDX_SERIALIZABLE_MEMBERS(type, ... /*members*/)                     \
    139   template <typename T>                                                     \
    140   friend class ::android::pdx::rpc::SerializableTraits;                     \
    141   template <typename, typename>                                             \
    142   friend struct ::android::pdx::rpc::HasSerializableMembers;                \
    143   using SerializableMembers = ::android::pdx::rpc::SerializableMembersType< \
    144       type, PDX_MEMBERS(type, __VA_ARGS__)>
    145 
    146 }  // namespace rpc
    147 }  // namespace pdx
    148 }  // namespace android
    149 
    150 #endif  // ANDROID_PDX_RPC_SERIALIZABLE_H_
    151