Program Listing for File msgpack_to_string.hpp

Return to documentation for file (eshet/msgpack_to_string.hpp)

#pragma once
#include "msgpack.hpp"
#include <string>
#include <vector>

namespace eshet {
namespace detail {
// adapted from msgpack/v1/object.hpp, Boost Software License
struct object_stringize_visitor {
  explicit object_stringize_visitor(std::string &s) : s(s) {}
  bool visit_nil() {
    s += "null";
    return true;
  }
  bool visit_boolean(bool v) {
    if (v)
      s += "true";
    else
      s += "false";
    return true;
  }
  bool visit_positive_integer(uint64_t v) {
    s += std::to_string(v);
    return true;
  }
  bool visit_negative_integer(int64_t v) {
    s += std::to_string(v);
    return true;
  }
  bool visit_float32(float v) {
    s += std::to_string(v);
    return true;
  }
  bool visit_float64(double v) {
    s += std::to_string(v);
    return true;
  }
  bool visit_str(const char *v, uint32_t size) {
    s.push_back('"');
    for (uint32_t i = 0; i < size; ++i) {
      char c = v[i];
      switch (c) {
      case '\\':
        s += "\\\\";
        break;
      case '"':
        s += "\\\"";
        break;
      case '/':
        s += "\\/";
        break;
      case '\b':
        s += "\\b";
        break;
      case '\f':
        s += "\\f";
        break;
      case '\n':
        s += "\\n";
        break;
      case '\r':
        s += "\\r";
        break;
      case '\t':
        s += "\\t";
        break;
      default: {
        unsigned int code = static_cast<unsigned int>(c);
        if (code < 0x20 || code == 0x7f) {
          s += "\\u00";
          char codes[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
                            '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
          s.push_back(codes[(code >> 4) & 0xf]);
          s.push_back(codes[(code >> 0) & 0xf]);
        } else {
          s.push_back(c);
        }
      } break;
      }
    }
    s.push_back('"');
    return true;
  }
  bool visit_bin(const char *v, uint32_t size) {
    s.push_back('"');
    for (uint32_t i = 0; i < size; ++i)
      s.push_back(v[i]);
    s.push_back('"');
    return true;
  }
  bool visit_ext(const char * /*v*/, uint32_t /*size*/) {
    s += "EXT";
    return true;
  }
  bool start_array(uint32_t num_elements) {
    m_current_size.push_back(num_elements);
    s.push_back('[');
    return true;
  }
  bool start_array_item() { return true; }
  bool end_array_item() {
    --m_current_size.back();
    if (m_current_size.back() != 0) {
      s.push_back(',');
    }
    return true;
  }
  bool end_array() {
    m_current_size.pop_back();
    s.push_back(']');
    return true;
  }
  bool start_map(uint32_t num_kv_pairs) {
    m_current_size.push_back(num_kv_pairs);
    s.push_back('{');
    return true;
  }
  bool start_map_key() { return true; }
  bool end_map_key() {
    s.push_back(':');
    return true;
  }
  bool start_map_value() { return true; }
  bool end_map_value() {
    --m_current_size.back();
    if (m_current_size.back() != 0) {
      s.push_back(',');
    }
    return true;
  }
  bool end_map() {
    m_current_size.pop_back();
    s.push_back('}');
    return true;
  }

private:
  std::string &s;
  std::vector<uint32_t> m_current_size;
};
} // namespace detail

void append_msgpack(std::string &s, const msgpack::object &v) {
  detail::object_stringize_visitor vis(s);
  msgpack::object_parser(v).parse(vis);
}

std::string msgpack_to_string(const msgpack::object &v) {
  std::string s;
  append_msgpack(s, v);
  return s;
}
} // namespace eshet