blob: 0bb4d90adab5bd00201263452bce70d30df1f475 [file] [log] [blame]
// Copyright 2019 The Chromium 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 V8_CRDTP_SERIALIZER_TRAITS_H_
#define V8_CRDTP_SERIALIZER_TRAITS_H_
#include <memory>
#include <string>
#include <vector>
#include "cbor.h"
#include "maybe.h"
#include "span.h"
namespace v8_crdtp {
// =============================================================================
// SerializerTraits - Encodes field values of protocol objects in CBOR.
// =============================================================================
//
// A family of serialization functions which are used by FieldSerializerTraits
// (below) to encode field values in CBOR. Conceptually, it's this:
//
// Serialize(bool value, std::vector<uint8_t>* out);
// Serialize(int32_t value, std::vector<uint8_t>* out);
// Serialize(double value, std::vector<uint8_t>* out);
// ...
//
// However, if this was to use straight-forward overloading, implicit
// type conversions would lead to ambiguity - e.g., a bool could be
// represented as an int32_t, but it should really be encoded as a bool.
// The template parameterized / specialized structs accomplish this.
//
// SerializerTraits<bool>::Serialize(bool value, std::vector<uint8_t>* out);
// SerializerTraits<int32>::Serialize(int32_t value, std::vector<uint8_t>* out);
// SerializerTraits<double>::Serialize(double value, std::vector<uint8_t>* out);
template <typename T>
struct SerializerTraits {
// |Serializable| (defined in serializable.h) already knows how to serialize
// to CBOR, so we can just delegate. This covers domain specific types,
// protocol::Binary, etc.
// However, we use duck-typing here, because Exported, which is part of the V8
// headers also comes with AppendSerialized, and logically it's the same type,
// but it lives in a different namespace (v8_inspector::protocol::Exported).
template <
typename LikeSerializable,
typename std::enable_if_t<std::is_member_pointer<decltype(
&LikeSerializable::AppendSerialized)>{},
int> = 0>
static void Serialize(const LikeSerializable& value,
std::vector<uint8_t>* out) {
value.AppendSerialized(out);
}
};
// This covers std::string, which is assumed to be UTF-8.
// The two other string implementations that are used in the protocol bindings:
// - WTF::String, for which the SerializerTraits specialization is located
// in third_party/blink/renderer/core/inspector/v8-inspector-string.h.
// - v8_inspector::String16, implemented in v8/src/inspector/string-16.h
// along with its SerializerTraits specialization.
template <>
struct SerializerTraits<std::string> {
static void Serialize(const std::string& str, std::vector<uint8_t>* out) {
cbor::EncodeString8(SpanFrom(str), out);
}
};
template <>
struct SerializerTraits<bool> {
static void Serialize(bool value, std::vector<uint8_t>* out) {
out->push_back(value ? cbor::EncodeTrue() : cbor::EncodeFalse());
}
};
template <>
struct SerializerTraits<int32_t> {
static void Serialize(int32_t value, std::vector<uint8_t>* out) {
cbor::EncodeInt32(value, out);
}
};
template <>
struct SerializerTraits<double> {
static void Serialize(double value, std::vector<uint8_t>* out) {
cbor::EncodeDouble(value, out);
}
};
template <typename T>
struct SerializerTraits<std::vector<T>> {
static void Serialize(const std::vector<T>& value,
std::vector<uint8_t>* out) {
out->push_back(cbor::EncodeIndefiniteLengthArrayStart());
for (const T& element : value)
SerializerTraits<T>::Serialize(element, out);
out->push_back(cbor::EncodeStop());
}
};
template <typename T>
struct SerializerTraits<std::unique_ptr<T>> {
static void Serialize(const std::unique_ptr<T>& value,
std::vector<uint8_t>* out) {
SerializerTraits<T>::Serialize(*value, out);
}
};
// =============================================================================
// FieldSerializerTraits - Encodes fields of protocol objects in CBOR
// =============================================================================
//
// The generated code (see TypeBuilder_cpp.template) invokes SerializeField,
// which then instantiates the FieldSerializerTraits to emit the appropriate
// existence checks / dereference for the field value. This avoids emitting
// the field name if the value for an optional field isn't set.
template <typename T>
struct FieldSerializerTraits {
static void Serialize(span<uint8_t> field_name,
const T& field_value,
std::vector<uint8_t>* out) {
cbor::EncodeString8(field_name, out);
SerializerTraits<T>::Serialize(field_value, out);
}
};
template <typename T>
struct FieldSerializerTraits<detail::PtrMaybe<T>> {
static void Serialize(span<uint8_t> field_name,
const detail::PtrMaybe<T>& field_value,
std::vector<uint8_t>* out) {
if (!field_value.isJust())
return;
cbor::EncodeString8(field_name, out);
SerializerTraits<T>::Serialize(*field_value.fromJust(), out);
}
};
template <typename T>
struct FieldSerializerTraits<detail::ValueMaybe<T>> {
static void Serialize(span<uint8_t> field_name,
const detail::ValueMaybe<T>& field_value,
std::vector<uint8_t>* out) {
if (!field_value.isJust())
return;
cbor::EncodeString8(field_name, out);
SerializerTraits<T>::Serialize(field_value.fromJust(), out);
}
};
template <typename T>
void SerializeField(span<uint8_t> field_name,
const T& field_value,
std::vector<uint8_t>* out) {
FieldSerializerTraits<T>::Serialize(field_name, field_value, out);
}
} // namespace v8_crdtp
#endif // V8_CRDTP_SERIALIZER_TRAITS_H_