#ifndef ANDROID_PDX_RPC_SERIALIZABLE_H_ #define ANDROID_PDX_RPC_SERIALIZABLE_H_ #include #include #include #include #include #include "macros.h" #include "serialization.h" namespace android { namespace pdx { namespace rpc { // This file provides utilities to define serializable types for communication // between clients and services. Supporting efficient, typed communication // protocols is the primary goal, NOT providing a general-purpose solution for // all your C++ serialization needs. Features that are not aligned to the goals // are not supported, such as static/const member serialization and serializable // types with virtual methods (requiring a virtual destructor). // Captures the type and value of a pointer to member. Pointer to members are // essentially compile-time constant offsets that can be stored in the type // system without adding to the size of the structures they describe. This // library uses this property to implement a limited form of reflection for // serialization/deserialization functions. template struct MemberPointer; template struct MemberPointer { // Type of the member pointer this type represents. using PointerType = Type Class::*; // Resolves a pointer to member with the given instance, yielding a // reference to the member in that instance. static Type& Resolve(Class& instance) { return (instance.*Pointer); } static const Type& Resolve(const Class& instance) { return (instance.*Pointer); } }; // Describes a set of members to be serialized/deserialized by this library. The // parameter pack MemberPointers takes a list of MemberPointer types that // describe each member to participate in serialization/deserialization. template struct SerializableMembersType { using Type = T; // The number of member pointers described by this type. enum : std::size_t { MemberCount = sizeof...(MemberPointers) }; // The member pointers described by this type. using Members = std::tuple; // Accessor for individual member pointer types. template using At = typename std::tuple_element::type; }; // Classes must do the following to correctly define a serializable type: // 1. Define a type called "SerializableMembers" as a template instantiation // of SerializableMembersType, describing the members of the class to // participate in serialization (presumably all of them). Use the macro // PDX_SERIALIZABLE_MEMBERS(...) below to aid the correct type // definition. This type should be private to prevent leaking member // access information. // 2. Make SerializableTraits and HasSerilizableMembers types a friend of // the class. The macro PDX_SERIALIZABLE_MEMEBRS(...) takes care of // this automatically. // 3. Define a public default constructor, if necessary. Deserialization // requires instances to be default-constructible. // // Example usage: // class MySerializableType : public AnotherBaseType { // public: // MySerializableType(); // ... // private: // int a; // string b; // PDX_SERIALIZABLE_MEMBERS(MySerializableType, a, b); // }; // // Note that const and static member serialization is not supported. template class SerializableTraits { public: // Gets the serialized size of type T. static std::size_t GetSerializedSize(const T& value) { return GetEncodingSize(EncodeArrayType(SerializableMembers::MemberCount)) + GetMembersSize(value); } // Serializes type T. static void SerializeObject(const T& value, MessageWriter* writer, void*& buffer) { SerializeArrayEncoding(EncodeArrayType(SerializableMembers::MemberCount), SerializableMembers::MemberCount, buffer); SerializeMembers(value, writer, buffer); } // Deserializes type T. static ErrorType DeserializeObject(T* value, MessageReader* reader, const void*& start, const void* end) { EncodingType encoding; std::size_t size; if (const auto error = DeserializeArrayType(&encoding, &size, reader, start, end)) { return error; } else if (size != SerializableMembers::MemberCount) { return ErrorCode::UNEXPECTED_TYPE_SIZE; } else { return DeserializeMembers(value, reader, start, end); } } private: using SerializableMembers = typename T::SerializableMembers; }; // Utility macro to define a MemberPointer type for a member name. #define PDX_MEMBER_POINTER(type, member) \ ::android::pdx::rpc::MemberPointer // Defines a list of MemberPointer types given a list of member names. #define PDX_MEMBERS(type, ... /*members*/) \ PDX_FOR_EACH_BINARY_LIST(PDX_MEMBER_POINTER, type, __VA_ARGS__) // Defines the serializable members of a type given a list of member names and // befriends SerializableTraits and HasSerializableMembers for the class. This // macro handles requirements #1 and #2 above. #define PDX_SERIALIZABLE_MEMBERS(type, ... /*members*/) \ template \ friend class ::android::pdx::rpc::SerializableTraits; \ template \ friend struct ::android::pdx::rpc::HasSerializableMembers; \ using SerializableMembers = ::android::pdx::rpc::SerializableMembersType< \ type, PDX_MEMBERS(type, __VA_ARGS__)> } // namespace rpc } // namespace pdx } // namespace android #endif // ANDROID_PDX_RPC_SERIALIZABLE_H_