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