| // 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_ |