mirror of
				https://github.com/ton-blockchain/ton
				synced 2025-03-09 15:40:10 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			880 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			880 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
    This file is part of TON Blockchain Library.
 | 
						|
 | 
						|
    TON Blockchain Library is free software: you can redistribute it and/or modify
 | 
						|
    it under the terms of the GNU Lesser General Public License as published by
 | 
						|
    the Free Software Foundation, either version 2 of the License, or
 | 
						|
    (at your option) any later version.
 | 
						|
 | 
						|
    TON Blockchain Library is distributed in the hope that it will be useful,
 | 
						|
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
    GNU Lesser General Public License for more details.
 | 
						|
 | 
						|
    You should have received a copy of the GNU Lesser General Public License
 | 
						|
    along with TON Blockchain Library.  If not, see <http://www.gnu.org/licenses/>.
 | 
						|
 | 
						|
    Copyright 2017-2020 Telegram Systems LLP
 | 
						|
*/
 | 
						|
#pragma once
 | 
						|
 | 
						|
#include "td/utils/common.h"
 | 
						|
#include "td/utils/logging.h"
 | 
						|
#include "td/utils/Parser.h"
 | 
						|
#include "td/utils/Slice.h"
 | 
						|
#include "td/utils/StackAllocator.h"
 | 
						|
#include "td/utils/Status.h"
 | 
						|
#include "td/utils/StringBuilder.h"
 | 
						|
 | 
						|
#include <new>
 | 
						|
#include <type_traits>
 | 
						|
#include <utility>
 | 
						|
 | 
						|
namespace td {
 | 
						|
 | 
						|
class JsonTrue {
 | 
						|
 public:
 | 
						|
  friend StringBuilder &operator<<(StringBuilder &sb, const JsonTrue &val) {
 | 
						|
    return sb << "true";
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
class JsonFalse {
 | 
						|
 public:
 | 
						|
  friend StringBuilder &operator<<(StringBuilder &sb, const JsonFalse &val) {
 | 
						|
    return sb << "false";
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
class JsonNull {
 | 
						|
 public:
 | 
						|
  friend StringBuilder &operator<<(StringBuilder &sb, JsonNull val) {
 | 
						|
    return sb << "null";
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
class JsonBool {
 | 
						|
 public:
 | 
						|
  explicit JsonBool(bool value) : value_(value) {
 | 
						|
  }
 | 
						|
  friend StringBuilder &operator<<(StringBuilder &sb, const JsonBool &val) {
 | 
						|
    if (val.value_) {
 | 
						|
      return sb << JsonTrue();
 | 
						|
    } else {
 | 
						|
      return sb << JsonFalse();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  bool value_;
 | 
						|
};
 | 
						|
 | 
						|
class JsonInt {
 | 
						|
 public:
 | 
						|
  explicit JsonInt(int32 value) : value_(value) {
 | 
						|
  }
 | 
						|
  friend StringBuilder &operator<<(StringBuilder &sb, const JsonInt &val) {
 | 
						|
    return sb << val.value_;
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  int32 value_;
 | 
						|
};
 | 
						|
 | 
						|
class JsonLong {
 | 
						|
 public:
 | 
						|
  explicit JsonLong(int64 value) : value_(value) {
 | 
						|
  }
 | 
						|
  friend StringBuilder &operator<<(StringBuilder &sb, const JsonLong &val) {
 | 
						|
    return sb << val.value_;
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  int64 value_;
 | 
						|
};
 | 
						|
 | 
						|
class JsonFloat {
 | 
						|
 public:
 | 
						|
  explicit JsonFloat(double value) : value_(value) {
 | 
						|
  }
 | 
						|
  friend StringBuilder &operator<<(StringBuilder &sb, const JsonFloat &val) {
 | 
						|
    return sb << val.value_;
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  double value_;
 | 
						|
};
 | 
						|
 | 
						|
class JsonOneChar {
 | 
						|
 public:
 | 
						|
  explicit JsonOneChar(unsigned int c) : c_(c) {
 | 
						|
  }
 | 
						|
 | 
						|
  friend StringBuilder &operator<<(StringBuilder &sb, const JsonOneChar &val) {
 | 
						|
    auto c = val.c_;
 | 
						|
    return sb << '\\' << 'u' << "0123456789abcdef"[c >> 12] << "0123456789abcdef"[(c >> 8) & 15]
 | 
						|
              << "0123456789abcdef"[(c >> 4) & 15] << "0123456789abcdef"[c & 15];
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  unsigned int c_;
 | 
						|
};
 | 
						|
 | 
						|
class JsonChar {
 | 
						|
 public:
 | 
						|
  explicit JsonChar(unsigned int c) : c_(c) {
 | 
						|
  }
 | 
						|
  friend StringBuilder &operator<<(StringBuilder &sb, const JsonChar &val) {
 | 
						|
    auto c = val.c_;
 | 
						|
    if (c < 0x10000) {
 | 
						|
      if (0xD7FF < c && c < 0xE000) {
 | 
						|
        // UTF-8 correctness has already been checked
 | 
						|
        UNREACHABLE();
 | 
						|
      }
 | 
						|
      return sb << JsonOneChar(c);
 | 
						|
    } else if (c <= 0x10ffff) {
 | 
						|
      return sb << JsonOneChar(0xD7C0 + (c >> 10)) << JsonOneChar(0xDC00 + (c & 0x3FF));
 | 
						|
    } else {
 | 
						|
      // UTF-8 correctness has already been checked
 | 
						|
      UNREACHABLE();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  unsigned int c_;
 | 
						|
};
 | 
						|
 | 
						|
class JsonRaw {
 | 
						|
 public:
 | 
						|
  explicit JsonRaw(Slice value) : value_(value) {
 | 
						|
  }
 | 
						|
  friend StringBuilder &operator<<(StringBuilder &sb, const JsonRaw &val) {
 | 
						|
    return sb << val.value_;
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  Slice value_;
 | 
						|
};
 | 
						|
 | 
						|
class JsonRawString {
 | 
						|
 public:
 | 
						|
  explicit JsonRawString(Slice value) : value_(value) {
 | 
						|
  }
 | 
						|
  friend StringBuilder &operator<<(StringBuilder &sb, const JsonRawString &val);
 | 
						|
 | 
						|
 private:
 | 
						|
  Slice value_;
 | 
						|
};
 | 
						|
 | 
						|
class JsonString {
 | 
						|
 public:
 | 
						|
  explicit JsonString(Slice str) : str_(str) {
 | 
						|
  }
 | 
						|
 | 
						|
  friend StringBuilder &operator<<(StringBuilder &sb, const JsonString &val);
 | 
						|
 | 
						|
 private:
 | 
						|
  Slice str_;
 | 
						|
};
 | 
						|
 | 
						|
class JsonScope;
 | 
						|
class JsonValueScope;
 | 
						|
class JsonArrayScope;
 | 
						|
class JsonObjectScope;
 | 
						|
 | 
						|
class JsonBuilder {
 | 
						|
 public:
 | 
						|
  explicit JsonBuilder(StringBuilder &&sb = {}, int32 offset = -1) : sb_(std::move(sb)), offset_(offset) {
 | 
						|
  }
 | 
						|
  StringBuilder &string_builder() {
 | 
						|
    return sb_;
 | 
						|
  }
 | 
						|
  friend class JsonScope;
 | 
						|
  JsonValueScope enter_value() TD_WARN_UNUSED_RESULT;
 | 
						|
  JsonArrayScope enter_array() TD_WARN_UNUSED_RESULT;
 | 
						|
  JsonObjectScope enter_object() TD_WARN_UNUSED_RESULT;
 | 
						|
 | 
						|
  int32 offset() const {
 | 
						|
    return offset_;
 | 
						|
  }
 | 
						|
  bool is_pretty() const {
 | 
						|
    return offset_ >= 0;
 | 
						|
  }
 | 
						|
  void print_offset() {
 | 
						|
    if (offset_ >= 0) {
 | 
						|
      sb_ << '\n';
 | 
						|
      for (int x = 0; x < offset_; x++) {
 | 
						|
        sb_ << "   ";
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  void dec_offset() {
 | 
						|
    if (offset_ >= 0) {
 | 
						|
      CHECK(offset_ > 0);
 | 
						|
      offset_--;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  void inc_offset() {
 | 
						|
    if (offset_ >= 0) {
 | 
						|
      offset_++;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  StringBuilder sb_;
 | 
						|
  JsonScope *scope_ = nullptr;
 | 
						|
  int32 offset_;
 | 
						|
};
 | 
						|
 | 
						|
class Jsonable {};
 | 
						|
 | 
						|
class JsonScope {
 | 
						|
 public:
 | 
						|
  explicit JsonScope(JsonBuilder *jb) : sb_(&jb->sb_), jb_(jb), save_scope_(jb->scope_) {
 | 
						|
    jb_->scope_ = this;
 | 
						|
    CHECK(is_active());
 | 
						|
  }
 | 
						|
  JsonScope(const JsonScope &other) = delete;
 | 
						|
  JsonScope(JsonScope &&other) : sb_(other.sb_), jb_(other.jb_), save_scope_(other.save_scope_) {
 | 
						|
    other.jb_ = nullptr;
 | 
						|
  }
 | 
						|
  JsonScope &operator=(const JsonScope &) = delete;
 | 
						|
  JsonScope &operator=(JsonScope &&) = delete;
 | 
						|
  ~JsonScope() {
 | 
						|
    if (jb_) {
 | 
						|
      leave();
 | 
						|
    }
 | 
						|
  }
 | 
						|
  void leave() {
 | 
						|
    CHECK(is_active());
 | 
						|
    jb_->scope_ = save_scope_;
 | 
						|
  }
 | 
						|
 | 
						|
 protected:
 | 
						|
  StringBuilder *sb_;
 | 
						|
 | 
						|
  // For CHECK
 | 
						|
  JsonBuilder *jb_;
 | 
						|
  JsonScope *save_scope_;
 | 
						|
 | 
						|
  bool is_active() const {
 | 
						|
    return jb_ && jb_->scope_ == this;
 | 
						|
  }
 | 
						|
 | 
						|
  JsonScope &operator<<(JsonTrue x) {
 | 
						|
    *sb_ << x;
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
  JsonScope &operator<<(JsonFalse x) {
 | 
						|
    *sb_ << x;
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
  JsonScope &operator<<(JsonNull x) {
 | 
						|
    *sb_ << x;
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
  JsonScope &operator<<(const JsonBool &x) {
 | 
						|
    *sb_ << x;
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
  JsonScope &operator<<(const JsonInt &x) {
 | 
						|
    *sb_ << x;
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
  JsonScope &operator<<(const JsonLong &x) {
 | 
						|
    *sb_ << x;
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
  JsonScope &operator<<(const JsonFloat &x) {
 | 
						|
    *sb_ << x;
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
  JsonScope &operator<<(const JsonString &x) {
 | 
						|
    *sb_ << x;
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
  JsonScope &operator<<(const JsonRawString &x) {
 | 
						|
    *sb_ << x;
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
  JsonScope &operator<<(const JsonRaw &x) {
 | 
						|
    *sb_ << x;
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
  JsonScope &operator<<(bool x) = delete;
 | 
						|
  JsonScope &operator<<(int32 x) {
 | 
						|
    return *this << JsonInt(x);
 | 
						|
  }
 | 
						|
  JsonScope &operator<<(int64 x) {
 | 
						|
    return *this << JsonLong(x);
 | 
						|
  }
 | 
						|
  JsonScope &operator<<(double x) {
 | 
						|
    return *this << JsonFloat(x);
 | 
						|
  }
 | 
						|
  template <size_t N>
 | 
						|
  JsonScope &operator<<(const char (&x)[N]) {
 | 
						|
    return *this << JsonString(Slice(x));
 | 
						|
  }
 | 
						|
  JsonScope &operator<<(const char *x) {
 | 
						|
    return *this << JsonString(Slice(x));
 | 
						|
  }
 | 
						|
  JsonScope &operator<<(Slice x) {
 | 
						|
    return *this << JsonString(x);
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
class JsonValueScope : public JsonScope {
 | 
						|
 public:
 | 
						|
  using JsonScope::JsonScope;
 | 
						|
  template <class T>
 | 
						|
  std::enable_if_t<std::is_base_of<Jsonable, typename std::decay<T>::type>::value, JsonValueScope &> operator<<(
 | 
						|
      const T &x) {
 | 
						|
    x.store(this);
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
  template <class T>
 | 
						|
  std::enable_if_t<!std::is_base_of<Jsonable, typename std::decay<T>::type>::value, JsonValueScope &> operator<<(
 | 
						|
      const T &x) {
 | 
						|
    CHECK(!was_);
 | 
						|
    was_ = true;
 | 
						|
    JsonScope::operator<<(x);
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
 | 
						|
  JsonArrayScope enter_array() TD_WARN_UNUSED_RESULT;
 | 
						|
  JsonObjectScope enter_object() TD_WARN_UNUSED_RESULT;
 | 
						|
 | 
						|
 private:
 | 
						|
  bool was_ = false;
 | 
						|
};
 | 
						|
 | 
						|
class JsonArrayScope : public JsonScope {
 | 
						|
 public:
 | 
						|
  explicit JsonArrayScope(JsonBuilder *jb) : JsonScope(jb) {
 | 
						|
    jb->inc_offset();
 | 
						|
    *sb_ << "[";
 | 
						|
  }
 | 
						|
  JsonArrayScope(JsonArrayScope &&other) = default;
 | 
						|
  ~JsonArrayScope() {
 | 
						|
    if (jb_) {
 | 
						|
      leave();
 | 
						|
    }
 | 
						|
  }
 | 
						|
  void leave() {
 | 
						|
    jb_->dec_offset();
 | 
						|
    if (jb_->is_pretty()) {
 | 
						|
      jb_->print_offset();
 | 
						|
    }
 | 
						|
    *sb_ << "]";
 | 
						|
  }
 | 
						|
  template <class T>
 | 
						|
  JsonArrayScope &operator<<(const T &x) {
 | 
						|
    return (*this)(x);
 | 
						|
  }
 | 
						|
  template <class T>
 | 
						|
  JsonArrayScope &operator()(const T &x) {
 | 
						|
    enter_value() << x;
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
  JsonValueScope enter_value() {
 | 
						|
    CHECK(is_active());
 | 
						|
    if (is_first_) {
 | 
						|
      *sb_ << ",";
 | 
						|
    } else {
 | 
						|
      is_first_ = true;
 | 
						|
    }
 | 
						|
    if (jb_->is_pretty()) {
 | 
						|
      jb_->print_offset();
 | 
						|
    }
 | 
						|
    return jb_->enter_value();
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  bool is_first_ = false;
 | 
						|
};
 | 
						|
 | 
						|
class JsonObjectScope : public JsonScope {
 | 
						|
 public:
 | 
						|
  explicit JsonObjectScope(JsonBuilder *jb) : JsonScope(jb) {
 | 
						|
    jb->inc_offset();
 | 
						|
    *sb_ << "{";
 | 
						|
  }
 | 
						|
  JsonObjectScope(JsonObjectScope &&other) = default;
 | 
						|
  ~JsonObjectScope() {
 | 
						|
    if (jb_) {
 | 
						|
      leave();
 | 
						|
    }
 | 
						|
  }
 | 
						|
  void leave() {
 | 
						|
    jb_->dec_offset();
 | 
						|
    if (jb_->is_pretty()) {
 | 
						|
      jb_->print_offset();
 | 
						|
    }
 | 
						|
    *sb_ << "}";
 | 
						|
  }
 | 
						|
  template <class T>
 | 
						|
  JsonObjectScope &operator()(Slice key, T &&value) {
 | 
						|
    CHECK(is_active());
 | 
						|
    if (is_first_) {
 | 
						|
      *sb_ << ",";
 | 
						|
    } else {
 | 
						|
      is_first_ = true;
 | 
						|
    }
 | 
						|
    if (jb_->is_pretty()) {
 | 
						|
      jb_->print_offset();
 | 
						|
    }
 | 
						|
    jb_->enter_value() << key;
 | 
						|
    if (jb_->is_pretty()) {
 | 
						|
      *sb_ << " : ";
 | 
						|
    } else {
 | 
						|
      *sb_ << ":";
 | 
						|
    }
 | 
						|
    jb_->enter_value() << value;
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
  JsonObjectScope &operator<<(const JsonRaw &key_value) {
 | 
						|
    CHECK(is_active());
 | 
						|
    is_first_ = true;
 | 
						|
    jb_->enter_value() << key_value;
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  bool is_first_ = false;
 | 
						|
};
 | 
						|
 | 
						|
inline JsonArrayScope JsonValueScope::enter_array() {
 | 
						|
  CHECK(!was_);
 | 
						|
  was_ = true;
 | 
						|
  return JsonArrayScope(jb_);
 | 
						|
}
 | 
						|
inline JsonObjectScope JsonValueScope::enter_object() {
 | 
						|
  CHECK(!was_);
 | 
						|
  was_ = true;
 | 
						|
  return JsonObjectScope(jb_);
 | 
						|
}
 | 
						|
inline JsonValueScope JsonBuilder::enter_value() {
 | 
						|
  return JsonValueScope(this);
 | 
						|
}
 | 
						|
inline JsonObjectScope JsonBuilder::enter_object() {
 | 
						|
  return JsonObjectScope(this);
 | 
						|
}
 | 
						|
inline JsonArrayScope JsonBuilder::enter_array() {
 | 
						|
  return JsonArrayScope(this);
 | 
						|
}
 | 
						|
 | 
						|
class JsonValue;
 | 
						|
 | 
						|
using JsonObject = vector<std::pair<MutableSlice, JsonValue>>;
 | 
						|
using JsonArray = vector<JsonValue>;
 | 
						|
 | 
						|
class JsonValue : public Jsonable {
 | 
						|
 public:
 | 
						|
  enum class Type { Null, Number, Boolean, String, Array, Object };
 | 
						|
 | 
						|
  static Slice get_type_name(Type type);
 | 
						|
 | 
						|
  JsonValue() {
 | 
						|
  }
 | 
						|
  ~JsonValue() {
 | 
						|
    destroy();
 | 
						|
  }
 | 
						|
  JsonValue(JsonValue &&other) : JsonValue() {
 | 
						|
    init(std::move(other));
 | 
						|
  }
 | 
						|
  JsonValue &operator=(JsonValue &&other) {
 | 
						|
    if (&other == this) {
 | 
						|
      return *this;
 | 
						|
    }
 | 
						|
    destroy();
 | 
						|
    init(std::move(other));
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
  JsonValue(const JsonValue &other) = delete;
 | 
						|
  JsonValue &operator=(const JsonValue &other) = delete;
 | 
						|
 | 
						|
  Type type() const {
 | 
						|
    return type_;
 | 
						|
  }
 | 
						|
 | 
						|
  MutableSlice &get_string() {
 | 
						|
    CHECK(type_ == Type::String);
 | 
						|
    return string_;
 | 
						|
  }
 | 
						|
  const MutableSlice &get_string() const {
 | 
						|
    CHECK(type_ == Type::String);
 | 
						|
    return string_;
 | 
						|
  }
 | 
						|
  bool &get_boolean() {
 | 
						|
    CHECK(type_ == Type::Boolean);
 | 
						|
    return boolean_;
 | 
						|
  }
 | 
						|
  const bool &get_boolean() const {
 | 
						|
    CHECK(type_ == Type::Boolean);
 | 
						|
    return boolean_;
 | 
						|
  }
 | 
						|
 | 
						|
  MutableSlice &get_number() {
 | 
						|
    CHECK(type_ == Type::Number);
 | 
						|
    return number_;
 | 
						|
  }
 | 
						|
  const MutableSlice &get_number() const {
 | 
						|
    CHECK(type_ == Type::Number);
 | 
						|
    return number_;
 | 
						|
  }
 | 
						|
 | 
						|
  JsonArray &get_array() {
 | 
						|
    CHECK(type_ == Type::Array);
 | 
						|
    return array_;
 | 
						|
  }
 | 
						|
  const JsonArray &get_array() const {
 | 
						|
    CHECK(type_ == Type::Array);
 | 
						|
    return array_;
 | 
						|
  }
 | 
						|
 | 
						|
  JsonObject &get_object() {
 | 
						|
    CHECK(type_ == Type::Object);
 | 
						|
    return object_;
 | 
						|
  }
 | 
						|
  const JsonObject &get_object() const {
 | 
						|
    CHECK(type_ == Type::Object);
 | 
						|
    return object_;
 | 
						|
  }
 | 
						|
 | 
						|
  static JsonValue create_boolean(bool val) {
 | 
						|
    JsonValue res;
 | 
						|
    res.init_boolean(val);
 | 
						|
    return res;
 | 
						|
  }
 | 
						|
 | 
						|
  static JsonValue create_number(MutableSlice number) {
 | 
						|
    JsonValue res;
 | 
						|
    res.init_number(number);
 | 
						|
    return res;
 | 
						|
  }
 | 
						|
 | 
						|
  static JsonValue create_string(MutableSlice str) {
 | 
						|
    JsonValue res;
 | 
						|
    res.init_string(str);
 | 
						|
    return res;
 | 
						|
  }
 | 
						|
 | 
						|
  static JsonValue create_array(JsonArray v) {
 | 
						|
    JsonValue res;
 | 
						|
    res.init_array(std::move(v));
 | 
						|
    return res;
 | 
						|
  }
 | 
						|
 | 
						|
  static JsonValue make_object(JsonObject c) {
 | 
						|
    JsonValue res;
 | 
						|
    res.init_object(std::move(c));
 | 
						|
    return res;
 | 
						|
  }
 | 
						|
 | 
						|
  void store(JsonValueScope *scope) const {
 | 
						|
    switch (type_) {
 | 
						|
      case Type::Null:
 | 
						|
        *scope << JsonRaw("null");
 | 
						|
        break;
 | 
						|
      case Type::Boolean:
 | 
						|
        if (get_boolean()) {
 | 
						|
          *scope << JsonRaw("true");
 | 
						|
        } else {
 | 
						|
          *scope << JsonRaw("false");
 | 
						|
        }
 | 
						|
        break;
 | 
						|
      case Type::Number:
 | 
						|
        *scope << JsonRaw(get_number());
 | 
						|
        break;
 | 
						|
      case Type::String:
 | 
						|
        *scope << JsonString(get_string());
 | 
						|
        break;
 | 
						|
      case Type::Array: {
 | 
						|
        auto arr = scope->enter_array();
 | 
						|
        for (auto &val : get_array()) {
 | 
						|
          arr << val;
 | 
						|
        }
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      case Type::Object: {
 | 
						|
        auto object = scope->enter_object();
 | 
						|
        for (auto &key_value : get_object()) {
 | 
						|
          object(key_value.first, key_value.second);
 | 
						|
        }
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  };
 | 
						|
 | 
						|
 private:
 | 
						|
  Type type_{Type::Null};
 | 
						|
  union {
 | 
						|
    MutableSlice number_;
 | 
						|
    bool boolean_;
 | 
						|
    MutableSlice string_;
 | 
						|
    JsonArray array_;
 | 
						|
    JsonObject object_;
 | 
						|
  };
 | 
						|
 | 
						|
  void init_null() {
 | 
						|
    type_ = Type::Null;
 | 
						|
  }
 | 
						|
  void init_number(MutableSlice number) {
 | 
						|
    type_ = Type::Number;
 | 
						|
    new (&number_) MutableSlice(number);
 | 
						|
  }
 | 
						|
  void init_boolean(bool boolean) {
 | 
						|
    type_ = Type::Boolean;
 | 
						|
    boolean_ = boolean;
 | 
						|
  }
 | 
						|
  void init_string(MutableSlice slice) {
 | 
						|
    type_ = Type::String;
 | 
						|
    new (&string_) MutableSlice(slice);
 | 
						|
  }
 | 
						|
  void init_array(JsonArray array) {
 | 
						|
    type_ = Type::Array;
 | 
						|
    new (&array_) JsonArray(std::move(array));
 | 
						|
  }
 | 
						|
  void init_object(JsonObject object) {
 | 
						|
    type_ = Type::Object;
 | 
						|
    new (&object_) JsonObject(std::move(object));
 | 
						|
  }
 | 
						|
 | 
						|
  void init(JsonValue &&other) {
 | 
						|
    switch (other.type_) {
 | 
						|
      case Type::Null:
 | 
						|
        break;
 | 
						|
      case Type::Number:
 | 
						|
        init_number(other.number_);
 | 
						|
        break;
 | 
						|
      case Type::Boolean:
 | 
						|
        init_boolean(other.boolean_);
 | 
						|
        break;
 | 
						|
      case Type::String:
 | 
						|
        init_string(other.string_);
 | 
						|
        break;
 | 
						|
      case Type::Array:
 | 
						|
        init_array(std::move(other.array_));
 | 
						|
        break;
 | 
						|
      case Type::Object:
 | 
						|
        init_object(std::move(other.object_));
 | 
						|
        break;
 | 
						|
    }
 | 
						|
    other.destroy();
 | 
						|
  }
 | 
						|
 | 
						|
  void destroy() {
 | 
						|
    switch (type_) {
 | 
						|
      case Type::Null:
 | 
						|
      case Type::Boolean:
 | 
						|
        break;
 | 
						|
      case Type::Number:
 | 
						|
        number_.~MutableSlice();
 | 
						|
        break;
 | 
						|
      case Type::String:
 | 
						|
        string_.~MutableSlice();
 | 
						|
        break;
 | 
						|
      case Type::Array:
 | 
						|
        array_.~vector<JsonValue>();
 | 
						|
        break;
 | 
						|
      case Type::Object:
 | 
						|
        object_.~vector<std::pair<MutableSlice, JsonValue>>();
 | 
						|
        break;
 | 
						|
    }
 | 
						|
    type_ = Type::Null;
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
inline StringBuilder &operator<<(StringBuilder &sb, JsonValue::Type type) {
 | 
						|
  switch (type) {
 | 
						|
    case JsonValue::Type::Null:
 | 
						|
      return sb << "Null";
 | 
						|
    case JsonValue::Type::Number:
 | 
						|
      return sb << "Number";
 | 
						|
    case JsonValue::Type::Boolean:
 | 
						|
      return sb << "Boolean";
 | 
						|
    case JsonValue::Type::String:
 | 
						|
      return sb << "String";
 | 
						|
    case JsonValue::Type::Array:
 | 
						|
      return sb << "Array";
 | 
						|
    case JsonValue::Type::Object:
 | 
						|
      return sb << "Object";
 | 
						|
    default:
 | 
						|
      UNREACHABLE();
 | 
						|
      return sb;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
class VirtuallyJsonable : public Jsonable {
 | 
						|
 public:
 | 
						|
  virtual void store(JsonValueScope *scope) const = 0;
 | 
						|
  VirtuallyJsonable() = default;
 | 
						|
  VirtuallyJsonable(const VirtuallyJsonable &) = delete;
 | 
						|
  VirtuallyJsonable &operator=(const VirtuallyJsonable &) = delete;
 | 
						|
  VirtuallyJsonable(VirtuallyJsonable &&) = default;
 | 
						|
  VirtuallyJsonable &operator=(VirtuallyJsonable &&) = default;
 | 
						|
  virtual ~VirtuallyJsonable() = default;
 | 
						|
};
 | 
						|
 | 
						|
class VirtuallyJsonableInt : public VirtuallyJsonable {
 | 
						|
 public:
 | 
						|
  explicit VirtuallyJsonableInt(int32 value) : value_(value) {
 | 
						|
  }
 | 
						|
  void store(JsonValueScope *scope) const override {
 | 
						|
    *scope << JsonInt(value_);
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  int32 value_;
 | 
						|
};
 | 
						|
 | 
						|
class VirtuallyJsonableLong : public VirtuallyJsonable {
 | 
						|
 public:
 | 
						|
  explicit VirtuallyJsonableLong(int64 value) : value_(value) {
 | 
						|
  }
 | 
						|
  void store(JsonValueScope *scope) const override {
 | 
						|
    *scope << JsonLong(value_);
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  int64 value_;
 | 
						|
};
 | 
						|
 | 
						|
class VirtuallyJsonableString : public VirtuallyJsonable {
 | 
						|
 public:
 | 
						|
  explicit VirtuallyJsonableString(Slice value) : value_(value) {
 | 
						|
  }
 | 
						|
  void store(JsonValueScope *scope) const override {
 | 
						|
    *scope << JsonString(value_);
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  Slice value_;
 | 
						|
};
 | 
						|
 | 
						|
Result<MutableSlice> json_string_decode(Parser &parser) TD_WARN_UNUSED_RESULT;
 | 
						|
Status json_string_skip(Parser &parser) TD_WARN_UNUSED_RESULT;
 | 
						|
 | 
						|
Result<JsonValue> do_json_decode(Parser &parser, int32 max_depth) TD_WARN_UNUSED_RESULT;
 | 
						|
Status do_json_skip(Parser &parser, int32 max_depth) TD_WARN_UNUSED_RESULT;
 | 
						|
 | 
						|
inline Result<JsonValue> json_decode(MutableSlice json) {
 | 
						|
  Parser parser(json);
 | 
						|
  const int32 DEFAULT_MAX_DEPTH = 100;
 | 
						|
  auto result = do_json_decode(parser, DEFAULT_MAX_DEPTH);
 | 
						|
  if (result.is_ok()) {
 | 
						|
    parser.skip_whitespaces();
 | 
						|
    if (!parser.empty()) {
 | 
						|
      return Status::Error("Expected string end");
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
template <class StrT, class ValT>
 | 
						|
StrT json_encode(const ValT &val, bool pretty = false) {
 | 
						|
  auto buf_len = 1 << 18;
 | 
						|
  auto buf = StackAllocator::alloc(buf_len);
 | 
						|
  JsonBuilder jb(StringBuilder(buf.as_slice(), true), pretty ? 0 : -1);
 | 
						|
  jb.enter_value() << val;
 | 
						|
  if (pretty) {
 | 
						|
    jb.string_builder() << "\n";
 | 
						|
  }
 | 
						|
  LOG_IF(ERROR, jb.string_builder().is_error()) << "JSON buffer overflow";
 | 
						|
  auto slice = jb.string_builder().as_cslice();
 | 
						|
  return StrT(slice.begin(), slice.size());
 | 
						|
}
 | 
						|
 | 
						|
template <class T>
 | 
						|
class ToJsonImpl : public Jsonable {
 | 
						|
 public:
 | 
						|
  explicit ToJsonImpl(const T &value) : value_(value) {
 | 
						|
  }
 | 
						|
  void store(JsonValueScope *scope) const {
 | 
						|
    to_json(*scope, value_);
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  const T &value_;
 | 
						|
};
 | 
						|
 | 
						|
template <class T>
 | 
						|
auto ToJson(const T &value) {
 | 
						|
  return ToJsonImpl<T>(value);
 | 
						|
}
 | 
						|
 | 
						|
template <class T>
 | 
						|
void to_json(JsonValueScope &jv, const T &value) {
 | 
						|
  jv << value;
 | 
						|
}
 | 
						|
 | 
						|
template <class F>
 | 
						|
class JsonObjectImpl : Jsonable {
 | 
						|
 public:
 | 
						|
  explicit JsonObjectImpl(F &&f) : f_(std::forward<F>(f)) {
 | 
						|
  }
 | 
						|
  void store(JsonValueScope *scope) const {
 | 
						|
    auto object = scope->enter_object();
 | 
						|
    f_(object);
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  F f_;
 | 
						|
};
 | 
						|
 | 
						|
template <class F>
 | 
						|
auto json_object(F &&f) {
 | 
						|
  return JsonObjectImpl<F>(std::forward<F>(f));
 | 
						|
}
 | 
						|
 | 
						|
template <class F>
 | 
						|
class JsonArrayImpl : Jsonable {
 | 
						|
 public:
 | 
						|
  explicit JsonArrayImpl(F &&f) : f_(std::forward<F>(f)) {
 | 
						|
  }
 | 
						|
  void store(JsonValueScope *scope) const {
 | 
						|
    auto array = scope->enter_array();
 | 
						|
    f_(array);
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  F f_;
 | 
						|
};
 | 
						|
 | 
						|
template <class F>
 | 
						|
auto json_array(F &&f) {
 | 
						|
  return JsonArrayImpl<F>(std::forward<F>(f));
 | 
						|
}
 | 
						|
 | 
						|
template <class A, class F>
 | 
						|
auto json_array(const A &a, F &&f) {
 | 
						|
  return json_array([&a, &f](auto &arr) {
 | 
						|
    for (auto &x : a) {
 | 
						|
      arr(f(x));
 | 
						|
    }
 | 
						|
  });
 | 
						|
}
 | 
						|
 | 
						|
bool has_json_object_field(const JsonObject &object, Slice name);
 | 
						|
 | 
						|
JsonValue get_json_object_field_force(JsonObject &object, Slice name) TD_WARN_UNUSED_RESULT;
 | 
						|
 | 
						|
Result<JsonValue> get_json_object_field(JsonObject &object, Slice name, JsonValue::Type type,
 | 
						|
                                        bool is_optional = true) TD_WARN_UNUSED_RESULT;
 | 
						|
 | 
						|
Result<bool> get_json_object_bool_field(JsonObject &object, Slice name, bool is_optional = true,
 | 
						|
                                        bool default_value = false) TD_WARN_UNUSED_RESULT;
 | 
						|
 | 
						|
Result<int32> get_json_object_int_field(JsonObject &object, Slice name, bool is_optional = true,
 | 
						|
                                        int32 default_value = 0) TD_WARN_UNUSED_RESULT;
 | 
						|
 | 
						|
Result<int64> get_json_object_long_field(JsonObject &object, Slice name, bool is_optional = true,
 | 
						|
                                         int64 default_value = 0) TD_WARN_UNUSED_RESULT;
 | 
						|
 | 
						|
Result<double> get_json_object_double_field(JsonObject &object, Slice name, bool is_optional = true,
 | 
						|
                                            double default_value = 0.0) TD_WARN_UNUSED_RESULT;
 | 
						|
 | 
						|
Result<string> get_json_object_string_field(JsonObject &object, Slice name, bool is_optional = true,
 | 
						|
                                            string default_value = "") TD_WARN_UNUSED_RESULT;
 | 
						|
 | 
						|
}  // namespace td
 |