DevTools protocol roll

... to revision c40253f87c475880d1bdad4a90cf21c38dadf4ac

Also, preseve binary protocol when restoring session.

Bug: chromium:929862
Change-Id: Icb1cb04b42ca7238b46e2978337b36e32398665f
Reviewed-on: https://chromium-review.googlesource.com/c/1474556
Commit-Queue: Andrey Kosyakov <caseq@chromium.org>
Commit-Queue: Pavel Feldman <pfeldman@chromium.org>
Reviewed-by: Pavel Feldman <pfeldman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59614}
This commit is contained in:
Andrey Kosyakov 2019-02-14 14:38:51 -08:00 committed by Commit Bot
parent f781f522af
commit 6703647b93
12 changed files with 305 additions and 109 deletions

View File

@ -76,6 +76,8 @@ V8InspectorSessionImpl::V8InspectorSessionImpl(V8InspectorImpl* inspector,
m_state = protocol::DictionaryValue::create();
}
m_state->getBoolean("use_binary_protocol", &use_binary_protocol_);
m_runtimeAgent.reset(new V8RuntimeAgentImpl(
this, this, agentState(protocol::Runtime::Metainfo::domainName)));
protocol::Runtime::Dispatcher::wire(&m_dispatcher, m_runtimeAgent.get());
@ -330,7 +332,11 @@ void V8InspectorSessionImpl::dispatchProtocolMessage(
const StringView& message) {
bool binary_protocol =
message.is8Bit() && message.length() && message.characters8()[0] == 0xD8;
if (binary_protocol) use_binary_protocol_ = true;
if (binary_protocol) {
use_binary_protocol_ = true;
m_state->setBoolean("use_binary_protocol", true);
}
int callId;
std::unique_ptr<protocol::Value> parsed_message;
if (binary_protocol) {

View File

@ -2,7 +2,7 @@ Name: inspector protocol
Short Name: inspector_protocol
URL: https://chromium.googlesource.com/deps/inspector_protocol/
Version: 0
Revision: ec358ccfd63a2a657c147329c7793d217e278a58
Revision: c40253f87c475880d1bdad4a90cf21c38dadf4ac
License: BSD
License File: LICENSE
Security Critical: no

View File

@ -15,34 +15,9 @@ namespace {{namespace}} {
// ===== encoding/cbor.cc =====
using namespace cbor;
namespace {
using cbor_internals::MajorType;
// Indicates the number of bits the "initial byte" needs to be shifted to the
// right after applying |kMajorTypeMask| to produce the major type in the
// lowermost bits.
static constexpr uint8_t kMajorTypeBitShift = 5u;
// Mask selecting the low-order 5 bits of the "initial byte", which is where
// the additional information is encoded.
static constexpr uint8_t kAdditionalInformationMask = 0x1f;
// Mask selecting the high-order 3 bits of the "initial byte", which indicates
// the major type of the encoded value.
static constexpr uint8_t kMajorTypeMask = 0xe0;
// Indicates the integer is in the following byte.
static constexpr uint8_t kAdditionalInformation1Byte = 24u;
// Indicates the integer is in the next 2 bytes.
static constexpr uint8_t kAdditionalInformation2Bytes = 25u;
// Indicates the integer is in the next 4 bytes.
static constexpr uint8_t kAdditionalInformation4Bytes = 26u;
// Indicates the integer is in the next 8 bytes.
static constexpr uint8_t kAdditionalInformation8Bytes = 27u;
// Encodes the initial byte, consisting of the |type| in the first 3 bits
// followed by 5 bits of |additional_info|.
constexpr uint8_t EncodeInitialByte(MajorType type, uint8_t additional_info) {
return (uint8_t(type) << kMajorTypeBitShift) |
(additional_info & kAdditionalInformationMask);
}
// See RFC 7049 Section 2.3, Table 2.
static constexpr uint8_t kEncodedTrue =
@ -53,38 +28,13 @@ static constexpr uint8_t kEncodedNull =
EncodeInitialByte(MajorType::SIMPLE_VALUE, 22);
static constexpr uint8_t kInitialByteForDouble =
EncodeInitialByte(MajorType::SIMPLE_VALUE, 27);
} // namespace
uint8_t EncodeTrue() { return kEncodedTrue; }
uint8_t EncodeFalse() { return kEncodedFalse; }
uint8_t EncodeNull() { return kEncodedNull; }
namespace {
// TAG 24 indicates that what follows is a byte string which is
// encoded in CBOR format. We use this as a wrapper for
// maps and arrays, allowing us to skip them, because the
// byte string carries its size (byte length).
// https://tools.ietf.org/html/rfc7049#section-2.4.4.1
static constexpr uint8_t kInitialByteForEnvelope =
EncodeInitialByte(MajorType::TAG, 24);
// The initial byte for a byte string with at most 2^32 bytes
// of payload. This is used for envelope encoding, even if
// the byte string is shorter.
static constexpr uint8_t kInitialByteFor32BitLengthByteString =
EncodeInitialByte(MajorType::BYTE_STRING, 26);
// See RFC 7049 Section 2.2.1, indefinite length arrays / maps have additional
// info = 31.
static constexpr uint8_t kInitialByteIndefiniteLengthArray =
EncodeInitialByte(MajorType::ARRAY, 31);
static constexpr uint8_t kInitialByteIndefiniteLengthMap =
EncodeInitialByte(MajorType::MAP, 31);
// See RFC 7049 Section 2.3, Table 1; this is used for finishing indefinite
// length maps / arrays.
static constexpr uint8_t kStopByte =
EncodeInitialByte(MajorType::SIMPLE_VALUE, 31);
} // namespace
uint8_t EncodeIndefiniteLengthArrayStart() {
return kInitialByteIndefiniteLengthArray;
}
@ -122,7 +72,7 @@ void WriteTokenStart(MajorType type, uint64_t value,
if (value < 24) {
// Values 0-23 are encoded directly into the additional info of the
// initial byte.
encoded->push_back(EncodeInitialByte(type, /*additiona_info=*/value));
encoded->push_back(EncodeInitialByte(type, /*additional_info=*/value));
return;
}
if (value <= std::numeric_limits<uint8_t>::max()) {
@ -156,9 +106,9 @@ namespace {
// See also: https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
template <typename T>
T ReadBytesMostSignificantByteFirst(span<uint8_t> in) {
assert(size_t(in.size()) >= sizeof(T));
assert(static_cast<std::size_t>(in.size()) >= sizeof(T));
T result = 0;
for (size_t shift_bytes = 0; shift_bytes < sizeof(T); ++shift_bytes)
for (std::size_t shift_bytes = 0; shift_bytes < sizeof(T); ++shift_bytes)
result |= T(in[sizeof(T) - 1 - shift_bytes]) << (shift_bytes * 8);
return result;
}
@ -185,19 +135,22 @@ int8_t ReadTokenStart(span<uint8_t> bytes, MajorType* type, uint64_t* value) {
}
if (additional_information == kAdditionalInformation2Bytes) {
// Values 256-65535: 1 initial byte + 2 bytes payload.
if (static_cast<size_t>(bytes.size()) < 1 + sizeof(uint16_t)) return -1;
if (static_cast<std::size_t>(bytes.size()) < 1 + sizeof(uint16_t))
return -1;
*value = ReadBytesMostSignificantByteFirst<uint16_t>(bytes.subspan(1));
return 3;
}
if (additional_information == kAdditionalInformation4Bytes) {
// 32 bit uint: 1 initial byte + 4 bytes payload.
if (static_cast<size_t>(bytes.size()) < 1 + sizeof(uint32_t)) return -1;
if (static_cast<std::size_t>(bytes.size()) < 1 + sizeof(uint32_t))
return -1;
*value = ReadBytesMostSignificantByteFirst<uint32_t>(bytes.subspan(1));
return 5;
}
if (additional_information == kAdditionalInformation8Bytes) {
// 64 bit uint: 1 initial byte + 8 bytes payload.
if (static_cast<size_t>(bytes.size()) < 1 + sizeof(uint64_t)) return -1;
if (static_cast<std::size_t>(bytes.size()) < 1 + sizeof(uint64_t))
return -1;
*value = ReadBytesMostSignificantByteFirst<uint64_t>(bytes.subspan(1));
return 9;
}
@ -205,7 +158,6 @@ int8_t ReadTokenStart(span<uint8_t> bytes, MajorType* type, uint64_t* value) {
}
} // namespace cbor_internals
using cbor_internals::MajorType;
using cbor_internals::WriteTokenStart;
using cbor_internals::ReadTokenStart;
@ -669,7 +621,8 @@ void CBORTokenizer::ReadNextToken(bool enter_envelope) {
SetError(Error::CBOR_INVALID_BINARY);
return;
}
SetToken(CBORTokenTag::BINARY, std::ptrdiff_t(token_byte_length));
SetToken(CBORTokenTag::BINARY,
static_cast<std::ptrdiff_t>(token_byte_length));
return;
}
case kInitialByteForDouble: { // DOUBLE
@ -696,7 +649,7 @@ void CBORTokenizer::ReadNextToken(bool enter_envelope) {
// Make sure the payload is contained within the message.
if (token_start_internal_value_ + kEncodedEnvelopeHeaderSize +
status_.pos >
size_t(bytes_.size())) {
static_cast<std::size_t>(bytes_.size())) {
SetError(Error::CBOR_INVALID_ENVELOPE);
return;
}
@ -731,8 +684,8 @@ void CBORTokenizer::ReadNextToken(bool enter_envelope) {
SetToken(CBORTokenTag::INT32, token_start_length);
return;
case MajorType::STRING: { // STRING8.
if (!success ||
remainder.size() < int64_t(token_start_internal_value_)) {
if (!success || remainder.size() < static_cast<int64_t>(
token_start_internal_value_)) {
SetError(Error::CBOR_INVALID_STRING8);
return;
}
@ -742,7 +695,8 @@ void CBORTokenizer::ReadNextToken(bool enter_envelope) {
}
case MajorType::BYTE_STRING: { // STRING16.
if (!success ||
remainder.size() < int64_t(token_start_internal_value_) ||
remainder.size() <
static_cast<int64_t>(token_start_internal_value_) ||
// Must be divisible by 2 since UTF16 is 2 bytes per character.
token_start_internal_value_ & 1) {
SetError(Error::CBOR_INVALID_STRING16);
@ -774,6 +728,75 @@ void CBORTokenizer::SetError(Error error) {
status_.error = error;
}
#if 0
void DumpCBOR(span<uint8_t> cbor) {
std::string indent;
CBORTokenizer tokenizer(cbor);
while (true) {
fprintf(stderr, "%s", indent.c_str());
switch (tokenizer.TokenTag()) {
case CBORTokenTag::ERROR_VALUE:
fprintf(stderr, "ERROR {status.error=%d, status.pos=%ld}\n",
tokenizer.Status().error, tokenizer.Status().pos);
return;
case CBORTokenTag::DONE:
fprintf(stderr, "DONE\n");
return;
case CBORTokenTag::TRUE_VALUE:
fprintf(stderr, "TRUE_VALUE\n");
break;
case CBORTokenTag::FALSE_VALUE:
fprintf(stderr, "FALSE_VALUE\n");
break;
case CBORTokenTag::NULL_VALUE:
fprintf(stderr, "NULL_VALUE\n");
break;
case CBORTokenTag::INT32:
fprintf(stderr, "INT32 [%d]\n", tokenizer.GetInt32());
break;
case CBORTokenTag::DOUBLE:
fprintf(stderr, "DOUBLE [%lf]\n", tokenizer.GetDouble());
break;
case CBORTokenTag::STRING8: {
span<uint8_t> v = tokenizer.GetString8();
std::string t(v.begin(), v.end());
fprintf(stderr, "STRING8 [%s]\n", t.c_str());
break;
}
case CBORTokenTag::STRING16: {
span<uint8_t> v = tokenizer.GetString16WireRep();
std::string t(v.begin(), v.end());
fprintf(stderr, "STRING16 [%s]\n", t.c_str());
break;
}
case CBORTokenTag::BINARY: {
span<uint8_t> v = tokenizer.GetBinary();
std::string t(v.begin(), v.end());
fprintf(stderr, "BINARY [%s]\n", t.c_str());
break;
}
case CBORTokenTag::MAP_START:
fprintf(stderr, "MAP_START\n");
indent += " ";
break;
case CBORTokenTag::ARRAY_START:
fprintf(stderr, "ARRAY_START\n");
indent += " ";
break;
case CBORTokenTag::STOP:
fprintf(stderr, "STOP\n");
indent.erase(0, 2);
break;
case CBORTokenTag::ENVELOPE:
fprintf(stderr, "ENVELOPE\n");
tokenizer.EnterEnvelope();
continue;
}
tokenizer.Next();
}
}
#endif
{% for namespace in config.protocol.namespace %}
} // namespace {{namespace}}

View File

@ -135,7 +135,31 @@ class JSONParserHandler {
// ===== encoding/cbor_internals.h =====
namespace cbor {
enum class MajorType;
}
namespace cbor_internals {
// Reads the start of a token with definitive size from |bytes|.
// |type| is the major type as specified in RFC 7049 Section 2.1.
// |value| is the payload (e.g. for MajorType::UNSIGNED) or is the size
// (e.g. for BYTE_STRING).
// If successful, returns the number of bytes read. Otherwise returns -1.
int8_t ReadTokenStart(span<uint8_t> bytes, cbor::MajorType* type,
uint64_t* value);
// Writes the start of a token with |type|. The |value| may indicate the size,
// or it may be the payload if the value is an unsigned integer.
void WriteTokenStart(cbor::MajorType type, uint64_t value,
std::vector<uint8_t>* encoded);
} // namespace cbor_internals
// ===== encoding/cbor.h =====
namespace cbor {
// The major types from RFC 7049 Section 2.1.
enum class MajorType {
UNSIGNED = 0,
@ -148,20 +172,57 @@ enum class MajorType {
SIMPLE_VALUE = 7
};
// Reads the start of a token with definitive size from |bytes|.
// |type| is the major type as specified in RFC 7049 Section 2.1.
// |value| is the payload (e.g. for MajorType::UNSIGNED) or is the size
// (e.g. for BYTE_STRING).
// If successful, returns the number of bytes read. Otherwise returns -1.
int8_t ReadTokenStart(span<uint8_t> bytes, MajorType* type, uint64_t* value);
// Indicates the number of bits the "initial byte" needs to be shifted to the
// right after applying |kMajorTypeMask| to produce the major type in the
// lowermost bits.
static constexpr uint8_t kMajorTypeBitShift = 5u;
// Mask selecting the low-order 5 bits of the "initial byte", which is where
// the additional information is encoded.
static constexpr uint8_t kAdditionalInformationMask = 0x1f;
// Mask selecting the high-order 3 bits of the "initial byte", which indicates
// the major type of the encoded value.
static constexpr uint8_t kMajorTypeMask = 0xe0;
// Indicates the integer is in the following byte.
static constexpr uint8_t kAdditionalInformation1Byte = 24u;
// Indicates the integer is in the next 2 bytes.
static constexpr uint8_t kAdditionalInformation2Bytes = 25u;
// Indicates the integer is in the next 4 bytes.
static constexpr uint8_t kAdditionalInformation4Bytes = 26u;
// Indicates the integer is in the next 8 bytes.
static constexpr uint8_t kAdditionalInformation8Bytes = 27u;
// Writes the start of a token with |type|. The |value| may indicate the size,
// or it may be the payload if the value is an unsigned integer.
void WriteTokenStart(MajorType type, uint64_t value,
std::vector<uint8_t>* encoded);
} // namespace cbor_internals
// Encodes the initial byte, consisting of the |type| in the first 3 bits
// followed by 5 bits of |additional_info|.
constexpr uint8_t EncodeInitialByte(MajorType type, uint8_t additional_info) {
return (static_cast<uint8_t>(type) << kMajorTypeBitShift) |
(additional_info & kAdditionalInformationMask);
}
// ===== encoding/cbor.h =====
// TAG 24 indicates that what follows is a byte string which is
// encoded in CBOR format. We use this as a wrapper for
// maps and arrays, allowing us to skip them, because the
// byte string carries its size (byte length).
// https://tools.ietf.org/html/rfc7049#section-2.4.4.1
static constexpr uint8_t kInitialByteForEnvelope =
EncodeInitialByte(MajorType::TAG, 24);
// The initial byte for a byte string with at most 2^32 bytes
// of payload. This is used for envelope encoding, even if
// the byte string is shorter.
static constexpr uint8_t kInitialByteFor32BitLengthByteString =
EncodeInitialByte(MajorType::BYTE_STRING, 26);
// See RFC 7049 Section 2.2.1, indefinite length arrays / maps have additional
// info = 31.
static constexpr uint8_t kInitialByteIndefiniteLengthArray =
EncodeInitialByte(MajorType::ARRAY, 31);
static constexpr uint8_t kInitialByteIndefiniteLengthMap =
EncodeInitialByte(MajorType::MAP, 31);
// See RFC 7049 Section 2.3, Table 1; this is used for finishing indefinite
// length maps / arrays.
static constexpr uint8_t kStopByte =
EncodeInitialByte(MajorType::SIMPLE_VALUE, 31);
} // namespace cbor
// The binary encoding for the inspector protocol follows the CBOR specification
// (RFC 7049). Additional constraints:
@ -231,7 +292,7 @@ class EnvelopeEncoder {
bool EncodeStop(std::vector<uint8_t>* out);
private:
std::vector<uint8_t>::size_type byte_size_pos_ = 0;
std::size_t byte_size_pos_ = 0;
};
// This can be used to convert from JSON to CBOR, by passing the
@ -342,10 +403,13 @@ class CBORTokenizer {
CBORTokenTag token_tag_;
struct Status status_;
std::ptrdiff_t token_byte_length_;
cbor_internals::MajorType token_start_type_;
cbor::MajorType token_start_type_;
uint64_t token_start_internal_value_;
};
void DumpCBOR(span<uint8_t> cbor);
{% for namespace in config.protocol.namespace %}
} // namespace {{namespace}}
{% endfor %}

View File

@ -168,6 +168,7 @@ std::unique_ptr<DictionaryValue> parseMap(
String key;
if (tokenizer->TokenTag() == CBORTokenTag::STRING8) {
span<uint8_t> key_span = tokenizer->GetString8();
tokenizer->Next();
key = StringUtil::fromUTF8(key_span.data(), key_span.size());
} else if (tokenizer->TokenTag() == CBORTokenTag::STRING16) {
return nullptr; // STRING16 not supported yet.
@ -178,6 +179,7 @@ std::unique_ptr<DictionaryValue> parseMap(
// Parse value.
auto value = parseValue(stack_depth, tokenizer);
if (!value) return nullptr;
dict->setValue(key, std::move(value));
}
tokenizer->Next();
return dict;

View File

@ -39,7 +39,8 @@ public:
TypeBinary,
TypeObject,
TypeArray,
TypeSerialized
TypeSerialized,
TypeImported
};
ValueType type() const { return m_type; }

View File

@ -12,6 +12,7 @@
#include "base/json/json_reader.h"
#include "base/memory/ptr_util.h"
#include "base/strings/string16.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
@ -229,6 +230,75 @@ Binary Binary::fromSpan(const uint8_t* data, size_t size) {
new base::RefCountedBytes(data, size)));
}
namespace {
int32_t ReadEnvelopeSize(const uint8_t* in) {
return (in[0] << 24) + (in[1] << 16) + (in[2] << 8) + in[3];
}
void WriteEnvelopeSize(uint32_t value, uint8_t* out) {
*(out++) = (value >> 24) & 0xFF;
*(out++) = (value >> 16) & 0xFF;
*(out++) = (value >> 8) & 0xFF;
*(out++) = (value) & 0xFF;
}
}
bool AppendStringValueToMapBinary(base::StringPiece in,
base::StringPiece key, base::StringPiece value, std::string* out) {
if (in.size() < 1 + 1 + 4 + 1 + 1)
return false;
const uint8_t* envelope = reinterpret_cast<const uint8_t*>(in.data());
if (cbor::kInitialByteForEnvelope != envelope[0])
return false;
if (cbor::kInitialByteFor32BitLengthByteString != envelope[1])
return false;
if (cbor::kInitialByteIndefiniteLengthMap != envelope[6])
return false;
uint32_t envelope_size = ReadEnvelopeSize(envelope + 2);
if (envelope_size + 2 + 4 != in.size())
return false;
if (cbor::kStopByte != static_cast<uint8_t>(*in.rbegin()))
return false;
std::vector<uint8_t> encoded_entry;
encoded_entry.reserve(1 + 4 + key.size() + 1 + 4 + value.size());
span<uint8_t> key_span(
reinterpret_cast<const uint8_t*>(key.data()), key.size());
EncodeString8(key_span, &encoded_entry);
span<uint8_t> value_span(
reinterpret_cast<const uint8_t*>(value.data()), value.size());
EncodeString8(value_span, &encoded_entry);
out->clear();
out->reserve(in.size() + encoded_entry.size());
out->append(in.begin(), in.end() - 1);
out->append(reinterpret_cast<const char*>(encoded_entry.data()),
encoded_entry.size());
out->append(1, static_cast<char>(cbor::kStopByte));
std::size_t new_size = envelope_size + out->size() - in.size();
if (new_size > static_cast<std::size_t>(
std::numeric_limits<uint32_t>::max())) {
return false;
}
WriteEnvelopeSize(new_size, reinterpret_cast<uint8_t*>(&*out->begin() + 2));
return true;
}
bool AppendStringValueToMapJSON(base::StringPiece in,
base::StringPiece key, base::StringPiece value, std::string* out) {
if (!in.length() || *in.rbegin() != '}')
return false;
std::string suffix =
base::StringPrintf(", \"%s\": \"%s\"}", key.begin(), value.begin());
out->clear();
out->reserve(in.length() + suffix.length() - 1);
out->append(in.data(), in.length() - 1);
out->append(suffix);
return true;
}
{% for namespace in config.protocol.namespace %}
} // namespace {{namespace}}
{% endfor %}

View File

@ -134,6 +134,11 @@ class {{config.lib.export_macro}} Binary {
std::unique_ptr<Value> toProtocolValue(const base::Value* value, int depth);
std::unique_ptr<base::Value> toBaseValue(Value* value, int depth);
bool AppendStringValueToMapBinary(base::StringPiece in,
base::StringPiece key, base::StringPiece value, std::string* out);
bool AppendStringValueToMapJSON(base::StringPiece in,
base::StringPiece key, base::StringPiece value, std::string* out);
{% for namespace in config.protocol.namespace %}
} // namespace {{namespace}}
{% endfor %}

View File

@ -15,6 +15,17 @@
{% for namespace in config.protocol.namespace %}
namespace {{namespace}} {
{% endfor %}
#ifndef {{"_".join(config.protocol.namespace)}}_exported_api_h
#define {{"_".join(config.protocol.namespace)}}_exported_api_h
class {{config.exported.export_macro}} Exported {
public:
virtual {{config.exported.string_out}} toJSONString() const = 0;
virtual void writeBinary(std::vector<uint8_t>* out) const = 0;
virtual ~Exported() { }
};
#endif // !defined({{"_".join(config.protocol.namespace)}}_exported_api_h)
namespace {{domain.domain}} {
namespace API {
@ -48,11 +59,8 @@ namespace {{param.name | to_title_case}}Enum {
{% for type in domain.types %}
{% if not (type.type == "object") or not ("properties" in type) or not protocol.is_exported(domain.domain, type.id) %}{% continue %}{% endif %}
class {{config.exported.export_macro}} {{type.id}} {
class {{config.exported.export_macro}} {{type.id}} : public Exported {
public:
virtual {{config.exported.string_out}} toJSONString() const = 0;
virtual std::vector<uint8_t> toBinary() const = 0;
virtual ~{{type.id}}() { }
static std::unique_ptr<protocol::{{domain.domain}}::API::{{type.id}}> fromJSONString(const {{config.exported.string_in}}& json);
static std::unique_ptr<protocol::{{domain.domain}}::API::{{type.id}}> fromBinary(const uint8_t* data, size_t length);
};

View File

@ -17,6 +17,37 @@
{% for namespace in config.protocol.namespace %}
namespace {{namespace}} {
{% endfor %}
using Exported = {{"::".join(config.imported.namespace)}}::Exported;
#ifndef {{"_".join(config.protocol.namespace)}}_imported_imported_h
#define {{"_".join(config.protocol.namespace)}}_imported_imported_h
class {{config.lib.export_macro}} ImportedValue : public Value {
public:
static std::unique_ptr<ImportedValue> fromExported(const Exported* value) {
return std::unique_ptr<ImportedValue>(new ImportedValue(value));
}
void writeJSON(StringBuilder* output) const override {
auto json = m_exported->toJSONString();
String local_json = ({{config.imported.from_imported_string % "std::move(json)"}});
StringUtil::builderAppend(*output, local_json);
}
void writeBinary(std::vector<uint8_t>* output) const override {
m_exported->writeBinary(output);
}
std::unique_ptr<Value> clone() const override {
return std::unique_ptr<Value>(new ImportedValue(m_exported));
}
private:
explicit ImportedValue(const Exported* exported) : Value(TypeImported), m_exported(exported) { }
const Exported* m_exported;
};
#endif // !defined({{"_".join(config.protocol.namespace)}}_imported_imported_h)
{% for type in domain.types %}
{% if not (type.type == "object") or not ("properties" in type) or not protocol.is_imported(domain.domain, type.id) %}{% continue %}{% endif %}
@ -29,32 +60,17 @@ struct ValueConversions<{{"::".join(config.imported.namespace)}}::{{domain.domai
return nullptr;
}
// TODO(pfeldman): toggle to true and delete the json branch when binary is ready.
bool binary_protocol = false;
std::unique_ptr<{{"::".join(config.imported.namespace)}}::{{domain.domain}}::API::{{type.id}}> result;
if (binary_protocol) {
std::vector<uint8_t> binary = value->serializeToBinary();
result = {{"::".join(config.imported.namespace)}}::{{domain.domain}}::API::{{type.id}}::fromBinary(binary.data(), binary.size());
} else {
String json = value->serializeToJSON();
result = {{"::".join(config.imported.namespace)}}::{{domain.domain}}::API::{{type.id}}::fromJSONString({{config.imported.to_imported_string % "json"}});
}
std::vector<uint8_t> binary;
value->writeBinary(&binary);
auto result = {{"::".join(config.imported.namespace)}}::{{domain.domain}}::API::{{type.id}}::fromBinary(binary.data(), binary.size());
if (!result)
errors->addError("cannot parse");
return result;
}
static std::unique_ptr<protocol::Value> toValue(const {{"::".join(config.imported.namespace)}}::{{domain.domain}}::API::{{type.id}}* value)
static std::unique_ptr<protocol::Value> toValue(const {{"::".join(config.imported.namespace)}}::{{domain.domain}}::API::{{type.id}}* exported)
{
// TODO(pfeldman): toggle to true and delete the json branch when binary is ready.
bool binary_protocol = false;
if (binary_protocol) {
return SerializedValue::fromBinary(value->toBinary());
} else {
auto json = value->toJSONString();
String local_json = ({{config.imported.from_imported_string % "std::move(json)"}});
return SerializedValue::fromJSON(local_json);
}
return ImportedValue::fromExported(exported);
}
static std::unique_ptr<protocol::Value> toValue(const std::unique_ptr<{{"::".join(config.imported.namespace)}}::{{domain.domain}}::API::{{type.id}}>& value)
@ -62,6 +78,7 @@ struct ValueConversions<{{"::".join(config.imported.namespace)}}::{{domain.domai
return toValue(value.get());
}
};
{% endfor %}
{% for namespace in config.protocol.namespace %}

View File

@ -105,9 +105,9 @@ std::unique_ptr<{{type.id}}> {{type.id}}::clone() const
return {{config.exported.to_string_out % "json"}};
}
std::vector<uint8_t> {{type.id}}::toBinary() const
void {{type.id}}::writeBinary(std::vector<uint8_t>* out) const
{
return toValue()->serializeToBinary();
toValue()->writeBinary(out);
}
// static

View File

@ -106,7 +106,7 @@ public:
std::unique_ptr<{{type.id}}> clone() const;
{% if protocol.is_exported(domain.domain, type.id) %}
{{config.exported.string_out}} toJSONString() const override;
std::vector<uint8_t> toBinary() const override;
void writeBinary(std::vector<uint8_t>* out) const override;
{% endif %}
template<int STATE>