// 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 #include #include #include #include #include #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(value)) { \ return false; \ } #define FML_DESERIALIZE(message, value) \ if (!message.Decode(value)) { \ return false; \ } #define FML_DESERIALIZE_TRAITS(message, value, traits) \ if (!message.Decode(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 CreateForSerializableTag(size_t tag); // }; template struct Serializable : public std::integral_constant< bool, std::is_trivially_copyable::value || std::is_base_of::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 ::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 ::value>> [[nodiscard]] bool Encode(const std::unique_ptr& value) { // Encode if null. if (!Encode(static_cast(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 ::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 ::value>> [[nodiscard]] bool Decode(std::unique_ptr& 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 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_