//
// Copyright 2015 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef GRPC_SRC_CORE_LIB_JSON_JSON_H
#define GRPC_SRC_CORE_LIB_JSON_JSON_H
#include <grpc/support/port_platform.h>
#include <map>
#include <util/generic/string.h>
#include <util/string/cast.h>
#include <utility>
#include <vector>
#include "y_absl/status/statusor.h"
#include "y_absl/strings/string_view.h"
namespace grpc_core {
// A JSON value, which can be any one of object, array, string,
// number, true, false, or null.
class Json {
public:
// TODO(roth): Currently, numbers are stored internally as strings,
// which makes the API a bit cumbersome to use. When we have time,
// consider whether there's a better alternative (e.g., maybe storing
// each numeric type as the native C++ type and automatically converting
// to string as needed).
enum class Type {
JSON_NULL,
JSON_TRUE,
JSON_FALSE,
NUMBER,
STRING,
OBJECT,
ARRAY
};
using Object = std::map<TString, Json>;
using Array = std::vector<Json>;
// Parses JSON string from json_str.
static y_absl::StatusOr<Json> Parse(y_absl::string_view json_str);
Json() = default;
// Copyable.
Json(const Json& other) { CopyFrom(other); }
Json& operator=(const Json& other) {
CopyFrom(other);
return *this;
}
// Moveable.
Json(Json&& other) noexcept { MoveFrom(std::move(other)); }
Json& operator=(Json&& other) noexcept {
MoveFrom(std::move(other));
return *this;
}
// Construct from copying a string.
// If is_number is true, the type will be NUMBER instead of STRING.
// NOLINTNEXTLINE(google-explicit-constructor)
Json(const TString& string, bool is_number = false)
: type_(is_number ? Type::NUMBER : Type::STRING), string_value_(string) {}
Json& operator=(const TString& string) {
type_ = Type::STRING;
string_value_ = string;
return *this;
}
// Same thing for C-style strings, both const and mutable.
// NOLINTNEXTLINE(google-explicit-constructor)
Json(const char* string, bool is_number = false)
: Json(TString(string), is_number) {}
Json& operator=(const char* string) {
*this = TString(string);
return *this;
}
// NOLINTNEXTLINE(google-explicit-constructor)
Json(char* string, bool is_number = false)
: Json(TString(string), is_number) {}
Json& operator=(char* string) {
*this = TString(string);
return *this;
}
// Construct by moving a string.
// NOLINTNEXTLINE(google-explicit-constructor)
Json(TString&& string)
: type_(Type::STRING), string_value_(std::move(string)) {}
Json& operator=(TString&& string) {
type_ = Type::STRING;
string_value_ = std::move(string);
return *this;
}
// Construct from bool.
// NOLINTNEXTLINE(google-explicit-constructor)
Json(bool b) : type_(b ? Type::JSON_TRUE : Type::JSON_FALSE) {}
Json& operator=(bool b) {
type_ = b ? Type::JSON_TRUE : Type::JSON_FALSE;
return *this;
}
// Construct from any numeric type.
template <typename NumericType>
// NOLINTNEXTLINE(google-explicit-constructor)
Json(NumericType number)
: type_(Type::NUMBER), string_value_(::ToString(number)) {}
template <typename NumericType>
Json& operator=(NumericType number) {
type_ = Type::NUMBER;
string_value_ = ::ToString(number);
return *this;
}
// Construct by copying object.
// NOLINTNEXTLINE(google-explicit-constructor)
Json(const Object& object) : type_(Type::OBJECT), object_value_(object) {}
Json& operator=(const Object& object) {
type_ = Type::OBJECT;
object_value_ = object;
return *this;
}
// Construct by moving object.
// NOLINTNEXTLINE(google-explicit-constructor)
Json(Object&& object)
: type_(Type::OBJECT), object_value_(std::move(object)) {}
Json& operator=(Object&& object) {
type_ = Type::OBJECT;
object_value_ = std::move(object);
return *this;
}
// Construct by copying array.
// NOLINTNEXTLINE(google-explicit-constructor)
Json(const Array& array) : type_(Type::ARRAY), array_value_(array) {}
Json& operator=(const Array& array) {
type_ = Type::ARRAY;
array_value_ = array;
return *this;
}
// Construct by moving array.
// NOLINTNEXTLINE(google-explicit-constructor)
Json(Array&& array) : type_(Type::ARRAY), array_value_(std::move(array)) {}
Json& operator=(Array&& array) {
type_ = Type::ARRAY;
array_value_ = std::move(array);
return *this;
}
// Dumps JSON from value to string form.
TString Dump(int indent = 0) const;
// Accessor methods.
Type type() const { return type_; }
const TString& string_value() const { return string_value_; }
TString* mutable_string_value() { return &string_value_; }
const Object& object_value() const { return object_value_; }
Object* mutable_object() { return &object_value_; }
const Array& array_value() const { return array_value_; }
Array* mutable_array() { return &array_value_; }
bool operator==(const Json& other) const {
if (type_ != other.type_) return false;
switch (type_) {
case Type::NUMBER:
case Type::STRING:
if (string_value_ != other.string_value_) return false;
break;
case Type::OBJECT:
if (object_value_ != other.object_value_) return false;
break;
case Type::ARRAY:
if (array_value_ != other.array_value_) return false;
break;
default:
break;
}
return true;
}
bool operator!=(const Json& other) const { return !(*this == other); }
private:
void CopyFrom(const Json& other) {
type_ = other.type_;
switch (type_) {
case Type::NUMBER:
case Type::STRING:
string_value_ = other.string_value_;
break;
case Type::OBJECT:
object_value_ = other.object_value_;
break;
case Type::ARRAY:
array_value_ = other.array_value_;
break;
default:
break;
}
}
void MoveFrom(Json&& other) {
type_ = other.type_;
other.type_ = Type::JSON_NULL;
switch (type_) {
case Type::NUMBER:
case Type::STRING:
string_value_ = std::move(other.string_value_);
break;
case Type::OBJECT:
object_value_ = std::move(other.object_value_);
break;
case Type::ARRAY:
array_value_ = std::move(other.array_value_);
break;
default:
break;
}
}
Type type_ = Type::JSON_NULL;
TString string_value_;
Object object_value_;
Array array_value_;
};
} // namespace grpc_core
#endif // GRPC_SRC_CORE_LIB_JSON_JSON_H