// 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 #include #include #include "cbor.h" #include "glue.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* out); // Serialize(int32_t value, std::vector* out); // Serialize(double value, std::vector* 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::Serialize(bool value, std::vector* out); // SerializerTraits::Serialize(int32_t value, std::vector* out); // SerializerTraits::Serialize(double value, std::vector* out); template 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{}, int> = 0> static void Serialize(const LikeSerializable& value, std::vector* 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 { static void Serialize(const std::string& str, std::vector* out) { cbor::EncodeString8(SpanFrom(str), out); } }; template <> struct SerializerTraits { static void Serialize(bool value, std::vector* out) { out->push_back(value ? cbor::EncodeTrue() : cbor::EncodeFalse()); } }; template <> struct SerializerTraits { static void Serialize(int32_t value, std::vector* out) { cbor::EncodeInt32(value, out); } }; template <> struct SerializerTraits { static void Serialize(double value, std::vector* out) { cbor::EncodeDouble(value, out); } }; template struct SerializerTraits> { static void Serialize(const std::vector& value, std::vector* out) { out->push_back(cbor::EncodeIndefiniteLengthArrayStart()); for (const T& element : value) SerializerTraits::Serialize(element, out); out->push_back(cbor::EncodeStop()); } }; template struct SerializerTraits> { static void Serialize(const std::unique_ptr& value, std::vector* out) { SerializerTraits::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 struct FieldSerializerTraits { static void Serialize(span field_name, const T& field_value, std::vector* out) { cbor::EncodeString8(field_name, out); SerializerTraits::Serialize(field_value, out); } }; template struct FieldSerializerTraits> { static void Serialize(span field_name, const glue::detail::PtrMaybe& field_value, std::vector* out) { if (!field_value.isJust()) return; cbor::EncodeString8(field_name, out); SerializerTraits::Serialize(*field_value.fromJust(), out); } }; template struct FieldSerializerTraits> { static void Serialize(span field_name, const glue::detail::ValueMaybe& field_value, std::vector* out) { if (!field_value.isJust()) return; cbor::EncodeString8(field_name, out); SerializerTraits::Serialize(field_value.fromJust(), out); } }; template void SerializeField(span field_name, const T& field_value, std::vector* out) { FieldSerializerTraits::Serialize(field_name, field_value, out); } } // namespace v8_crdtp #endif // V8_CRDTP_SERIALIZER_TRAITS_H_