1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef FLUTTER_FML_MESSAGE_H_
6#define FLUTTER_FML_MESSAGE_H_
7
8#include <algorithm>
9#include <cstdint>
10#include <cstring>
11#include <memory>
12#include <type_traits>
13#include <utility>
14
15#include "flutter/fml/compiler_specific.h"
16#include "flutter/fml/macros.h"
17
18namespace fml {
19
20#define FML_SERIALIZE(message, value) \
21 if (!message.Encode(value)) { \
22 return false; \
23 }
24
25#define FML_SERIALIZE_TRAITS(message, value, traits) \
26 if (!message.Encode<traits>(value)) { \
27 return false; \
28 }
29
30#define FML_DESERIALIZE(message, value) \
31 if (!message.Decode(value)) { \
32 return false; \
33 }
34
35#define FML_DESERIALIZE_TRAITS(message, value, traits) \
36 if (!message.Decode<traits>(value)) { \
37 return false; \
38 }
39
40class Message;
41
42class MessageSerializable {
43 public:
44 virtual ~MessageSerializable() = default;
45
46 virtual bool Serialize(Message& message) const = 0;
47
48 virtual bool Deserialize(Message& message) = 0;
49
50 virtual size_t GetSerializableTag() const;
51};
52
53// The traits passed to the encode/decode calls that accept traits should be
54// something like the following.
55//
56// class MessageSerializableTraits {
57// static size_t GetSerializableTag(const T&);
58// static std::unique_ptr<T> CreateForSerializableTag(size_t tag);
59// };
60
61template <class T>
62struct Serializable : public std::integral_constant<
63 bool,
64 std::is_trivially_copyable<T>::value ||
65 std::is_base_of<MessageSerializable, T>::value> {
66};
67
68// Utility class to encode and decode |Serializable| types to and from a buffer.
69// Elements have to be read back into the same order they were written.
70class Message {
71 public:
72 Message();
73
74 ~Message();
75
76 const uint8_t* GetBuffer() const;
77
78 size_t GetBufferSize() const;
79
80 size_t GetDataLength() const;
81
82 size_t GetSizeRead() const;
83
84 void ResetRead();
85
86 // Encoders.
87
88 template <typename T,
89 typename = std::enable_if_t<std::is_trivially_copyable<T>::value>>
90 [[nodiscard]] bool Encode(const T& value) {
91 if (auto* buffer = PrepareEncode(sizeof(T))) {
92 ::memcpy(buffer, &value, sizeof(T));
93 return true;
94 }
95 return false;
96 }
97
98 [[nodiscard]] bool Encode(const MessageSerializable& value) {
99 return value.Serialize(*this);
100 }
101
102 template <typename Traits,
103 typename T,
104 typename = std::enable_if_t<
105 std::is_base_of<MessageSerializable, T>::value>>
106 [[nodiscard]] bool Encode(const std::unique_ptr<T>& value) {
107 // Encode if null.
108 if (!Encode(static_cast<bool>(value))) {
109 return false;
110 }
111
112 if (!value) {
113 return true;
114 }
115
116 // Encode the type.
117 if (!Encode(Traits::GetSerializableTag(*value.get()))) {
118 return false;
119 }
120
121 // Encode the value.
122 if (!Encode(*value.get())) {
123 return false;
124 }
125
126 return true;
127 }
128
129 // Decoders.
130
131 template <typename T,
132 typename = std::enable_if_t<std::is_trivially_copyable<T>::value>>
133 [[nodiscard]] bool Decode(T& value) {
134 if (auto* buffer = PrepareDecode(sizeof(T))) {
135 ::memcpy(&value, buffer, sizeof(T));
136 return true;
137 }
138 return false;
139 }
140
141 [[nodiscard]] bool Decode(MessageSerializable& value) {
142 return value.Deserialize(*this);
143 }
144
145 template <typename Traits,
146 typename T,
147 typename = std::enable_if_t<
148 std::is_base_of<MessageSerializable, T>::value>>
149 [[nodiscard]] bool Decode(std::unique_ptr<T>& value) {
150 // Decode if null.
151 bool is_null = false;
152 if (!Decode(is_null)) {
153 return false;
154 }
155
156 if (is_null) {
157 return true;
158 }
159
160 // Decode type.
161 size_t tag = 0;
162 if (!Decode(tag)) {
163 return false;
164 }
165
166 std::unique_ptr<T> new_value = Traits::CreateForSerializableTag(tag);
167 if (!new_value) {
168 return false;
169 }
170
171 // Decode value.
172 if (!Decode(*new_value.get())) {
173 return false;
174 }
175
176 std::swap(value, new_value);
177
178 return true;
179 }
180
181 private:
182 uint8_t* buffer_ = nullptr;
183 size_t buffer_length_ = 0;
184 size_t data_length_ = 0;
185 size_t size_read_ = 0;
186
187 [[nodiscard]] bool Reserve(size_t size);
188
189 [[nodiscard]] bool Resize(size_t size);
190
191 [[nodiscard]] uint8_t* PrepareEncode(size_t size);
192
193 [[nodiscard]] uint8_t* PrepareDecode(size_t size);
194
195 FML_DISALLOW_COPY_AND_ASSIGN(Message);
196};
197
198} // namespace fml
199
200#endif // FLUTTER_FML_MESSAGE_H_
201