// This file is generated by ValueConversions_cpp.template.

// Copyright 2020 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.

#include {{format_include(config.protocol.package, "Protocol")}}

#include <algorithm>
#include <climits>
#include <string>

//#include "ValueConversions.h"
//#include "Values.h"

{% for namespace in config.protocol.namespace %}
namespace {{namespace}} {
{% endfor %}

{% for namespace in config.protocol.namespace %}
}  // namespce
{% endfor %}


namespace {{config.crdtp.namespace}} {

namespace {

using {{"::".join(config.protocol.namespace)}}::Binary;
using {{"::".join(config.protocol.namespace)}}::Object;
using {{"::".join(config.protocol.namespace)}}::Value;
using {{"::".join(config.protocol.namespace)}}::String;
using {{"::".join(config.protocol.namespace)}}::DictionaryValue;
using {{"::".join(config.protocol.namespace)}}::FundamentalValue;
using {{"::".join(config.protocol.namespace)}}::StringValue;
using {{"::".join(config.protocol.namespace)}}::StringUtil;
//using {{"::".join(config.protocol.namespace)}}::EncodeString;

std::unique_ptr<Value> ReadValue(DeserializerState* state) {
  cbor::CBORTokenizer* tokenizer = state->tokenizer();
  switch (tokenizer->TokenTag()) {
    case cbor::CBORTokenTag::TRUE_VALUE:
      return FundamentalValue::create(true);
    case cbor::CBORTokenTag::FALSE_VALUE:
      return FundamentalValue::create(false);
    case cbor::CBORTokenTag::NULL_VALUE:
      return Value::null();
    case cbor::CBORTokenTag::INT32:
      return FundamentalValue::create(tokenizer->GetInt32());
    case cbor::CBORTokenTag::DOUBLE:
      return FundamentalValue::create(tokenizer->GetDouble());
    case cbor::CBORTokenTag::STRING8: {
      const auto str = tokenizer->GetString8();
      return StringValue::create(StringUtil::fromUTF8(str.data(), str.size()));
    }
    case cbor::CBORTokenTag::STRING16: {
      const auto str = tokenizer->GetString16WireRep();
      return StringValue::create(StringUtil::fromUTF16LE(reinterpret_cast<const uint16_t*>(str.data()), str.size() / 2));
    }
    case cbor::CBORTokenTag::ENVELOPE: {
      const auto env = tokenizer->GetEnvelope();
      return Value::parseBinary(env.data(), env.size());
    }
    // Intentionally not supported.
    case cbor::CBORTokenTag::BINARY:
    // Should not be encountered outside of envelope.
    case cbor::CBORTokenTag::MAP_START:
    case cbor::CBORTokenTag::ARRAY_START:
    default:
      state->RegisterError(Error::CBOR_UNSUPPORTED_VALUE);
      return nullptr;
  }
}

}  // namespace

// static
bool ProtocolTypeTraits<std::unique_ptr<Value>>::Deserialize(
    DeserializerState* state, std::unique_ptr<Value>* value) {
  auto result = ReadValue(state);
  if (!result)
    return false;
  *value = std::move(result);
  return true;
}

// static
void ProtocolTypeTraits<std::unique_ptr<Value>>::Serialize(
    const std::unique_ptr<Value>& value, std::vector<uint8_t>* bytes) {
  value->AppendSerialized(bytes);
}

// static
bool ProtocolTypeTraits<std::unique_ptr<DictionaryValue>>::Deserialize(
    DeserializerState* state, std::unique_ptr<DictionaryValue>* value) {
  std::unique_ptr<Value> res;
  if (!ProtocolTypeTraits<std::unique_ptr<Value>>::Deserialize(state, &res))
    return false;
  *value = DictionaryValue::cast(std::move(res));
  return true;
}

// static
void ProtocolTypeTraits<std::unique_ptr<DictionaryValue>>::Serialize(
    const std::unique_ptr<DictionaryValue>& value, std::vector<uint8_t>* bytes) {
  value->AppendSerialized(bytes);
}

// static
bool ProtocolTypeTraits<std::unique_ptr<Object>>::Deserialize(DeserializerState* state, std::unique_ptr<Object>* value) {
  auto res = DictionaryValue::create();
  if (ProtocolTypeTraits<std::unique_ptr<DictionaryValue>>::Deserialize(state, &res)) {
    *value = std::make_unique<Object>(std::move(res));
    return true;
  }
  return false;
}

void ProtocolTypeTraits<std::unique_ptr<Object>>::Serialize(const std::unique_ptr<Object>& value, std::vector<uint8_t>* bytes) {
  value->AppendSerialized(bytes);
}

}  // namespace {{config.crdtp.namespace}}