blob: 4b3b725d4c6e909239d8f687591fac4fde47be28 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_FML_MESSAGE_H_
#define FLUTTER_FML_MESSAGE_H_
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <memory>
#include <type_traits>
#include <utility>
#include "flutter/fml/compiler_specific.h"
#include "flutter/fml/macros.h"
namespace fml {
#define FML_SERIALIZE(message, value) \
if (!message.Encode(value)) { \
return false; \
}
#define FML_SERIALIZE_TRAITS(message, value, traits) \
if (!message.Encode<traits>(value)) { \
return false; \
}
#define FML_DESERIALIZE(message, value) \
if (!message.Decode(value)) { \
return false; \
}
#define FML_DESERIALIZE_TRAITS(message, value, traits) \
if (!message.Decode<traits>(value)) { \
return false; \
}
class Message;
class MessageSerializable {
public:
virtual ~MessageSerializable() = default;
virtual bool Serialize(Message& message) const = 0;
virtual bool Deserialize(Message& message) = 0;
virtual size_t GetSerializableTag() const;
};
// The traits passed to the encode/decode calls that accept traits should be
// something like the following.
//
// class MessageSerializableTraits {
// static size_t GetSerializableTag(const T&);
// static std::unique_ptr<T> CreateForSerializableTag(size_t tag);
// };
template <class T>
struct Serializable : public std::integral_constant<
bool,
std::is_trivially_copyable<T>::value ||
std::is_base_of<MessageSerializable, T>::value> {
};
// Utility class to encode and decode |Serializable| types to and from a buffer.
// Elements have to be read back into the same order they were written.
class Message {
public:
Message();
~Message();
const uint8_t* GetBuffer() const;
size_t GetBufferSize() const;
size_t GetDataLength() const;
size_t GetSizeRead() const;
void ResetRead();
// Encoders.
template <typename T,
typename = std::enable_if_t<std::is_trivially_copyable<T>::value>>
[[nodiscard]] bool Encode(const T& value) {
if (auto* buffer = PrepareEncode(sizeof(T))) {
::memcpy(buffer, &value, sizeof(T));
return true;
}
return false;
}
[[nodiscard]] bool Encode(const MessageSerializable& value) {
return value.Serialize(*this);
}
template <typename Traits,
typename T,
typename = std::enable_if_t<
std::is_base_of<MessageSerializable, T>::value>>
[[nodiscard]] bool Encode(const std::unique_ptr<T>& value) {
// Encode if null.
if (!Encode(static_cast<bool>(value))) {
return false;
}
if (!value) {
return true;
}
// Encode the type.
if (!Encode(Traits::GetSerializableTag(*value.get()))) {
return false;
}
// Encode the value.
if (!Encode(*value.get())) {
return false;
}
return true;
}
// Decoders.
template <typename T,
typename = std::enable_if_t<std::is_trivially_copyable<T>::value>>
[[nodiscard]] bool Decode(T& value) {
if (auto* buffer = PrepareDecode(sizeof(T))) {
::memcpy(&value, buffer, sizeof(T));
return true;
}
return false;
}
[[nodiscard]] bool Decode(MessageSerializable& value) {
return value.Deserialize(*this);
}
template <typename Traits,
typename T,
typename = std::enable_if_t<
std::is_base_of<MessageSerializable, T>::value>>
[[nodiscard]] bool Decode(std::unique_ptr<T>& value) {
// Decode if null.
bool is_null = false;
if (!Decode(is_null)) {
return false;
}
if (is_null) {
return true;
}
// Decode type.
size_t tag = 0;
if (!Decode(tag)) {
return false;
}
std::unique_ptr<T> new_value = Traits::CreateForSerializableTag(tag);
if (!new_value) {
return false;
}
// Decode value.
if (!Decode(*new_value.get())) {
return false;
}
std::swap(value, new_value);
return true;
}
private:
uint8_t* buffer_ = nullptr;
size_t buffer_length_ = 0;
size_t data_length_ = 0;
size_t size_read_ = 0;
[[nodiscard]] bool Reserve(size_t size);
[[nodiscard]] bool Resize(size_t size);
[[nodiscard]] uint8_t* PrepareEncode(size_t size);
[[nodiscard]] uint8_t* PrepareDecode(size_t size);
FML_DISALLOW_COPY_AND_ASSIGN(Message);
};
} // namespace fml
#endif // FLUTTER_FML_MESSAGE_H_