blob: 230ece96e2b2e69aa0fc158c0ecd7af97b570c3d [file] [log] [blame]
// 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>
auto operator|(T& val)
-> std::enable_if_t<std::is_void_v<decltype(val.Serialize(*this, 0))>, Serializer&> {
val.Serialize(*this, GetVersion());
return *this;
}
template <typename Integer>
auto operator|(Integer& val) -> std::enable_if_t<std::is_integral_v<Integer>, Serializer&> {
SerializeBytes(&val, sizeof(val));
return *this;
}
template <typename Enum>
auto operator|(Enum& val) -> std::enable_if_t<std::is_enum_v<Enum>, Serializer&> {
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;
};
} // namespace debug
namespace debug_ipc {
using Serializer = debug::Serializer; // for convenience.
} // namespace debug_ipc
#endif // SRC_DEVELOPER_DEBUG_SHARED_SERIALIZATION_H_