| // Copyright 2022 The Fuchsia 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 SRC_DEVELOPER_DEBUG_SHARED_SERIALIZATION_H_ | |
| #define SRC_DEVELOPER_DEBUG_SHARED_SERIALIZATION_H_ | |
| #include <optional> | |
| #include <string> | |
| #include <type_traits> | |
| #include <vector> | |
| // This is a simple "serialization" solution for the debug_ipc. | |
| // | |
| // It utilizes template and function overloading to avoid writing serialization and deserialization | |
| // functions twice. | |
| // | |
| // To add serialization support for a type, either | |
| // | |
| // - For classes owned by us, provide a function `void Serialize(Serializer& ser, uint32_t ver)` | |
| // in the class. | |
| // - For classes not owned by us / non-class types, provide a function | |
| // `Serializer& Serializer::operator|(Type& object)`. | |
| // | |
| // These functions will be used by both serialization and deserialization, although the names only | |
| // contain "serialize". In another word, these functions could also write to the object. | |
| namespace debug { | |
| // To implement a Serializer/Deserializer, inherit this interface. | |
| class Serializer { | |
| public: | |
| template <typename T> | |
| Serializer& operator|(T& val) | |
| requires std::is_void_v<decltype(val.Serialize(*this, 0))> | |
| { | |
| val.Serialize(*this, GetVersion()); | |
| return *this; | |
| } | |
| template <typename Integer> | |
| Serializer& operator|(Integer& val) | |
| requires std::is_integral_v<Integer> | |
| { | |
| SerializeBytes(&val, sizeof(val)); | |
| return *this; | |
| } | |
| template <typename Enum> | |
| Serializer& operator|(Enum& val) | |
| requires std::is_enum_v<Enum> | |
| { | |
| uint32_t v = static_cast<uint32_t>(val); | |
| *this | v; | |
| val = static_cast<Enum>(v); | |
| return *this; | |
| } | |
| template <typename T> | |
| Serializer& operator|(std::optional<T>& val) { | |
| uint32_t has_value = val.has_value(); | |
| *this | has_value; | |
| if (has_value) { | |
| if (!val.has_value()) { | |
| val.emplace(); | |
| } | |
| *this | val.value(); | |
| } else if (val.has_value()) { | |
| val.reset(); | |
| } | |
| return *this; | |
| } | |
| template <typename T> | |
| Serializer& operator|(std::vector<T>& val) { | |
| uint32_t size = static_cast<uint32_t>(val.size()); | |
| *this | size; | |
| val.resize(size); | |
| for (uint32_t i = 0; i < size; i++) { | |
| *this | val[i]; | |
| } | |
| return *this; | |
| } | |
| Serializer& operator|(std::string& val); | |
| // Returns the desired version for serialization. | |
| virtual uint32_t GetVersion() const = 0; | |
| // Reads or writes bytes. | |
| virtual void SerializeBytes(void* data, uint32_t size) = 0; | |
| virtual ~Serializer(); | |
| }; | |
| } // namespace debug | |
| namespace debug_ipc { | |
| using Serializer = debug::Serializer; // for convenience. | |
| } // namespace debug_ipc | |
| #endif // SRC_DEVELOPER_DEBUG_SHARED_SERIALIZATION_H_ |