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 14namespace android { 15namespace pdx { 16namespace 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. 30template <typename T, T> 31struct MemberPointer; 32 33template <typename Type, typename Class, Type Class::*Pointer> 34struct 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. 49template <typename T, typename... MemberPointers> 50struct 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 90template <typename T> 91class 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