chromium/third_party/grpc/src/src/core/lib/json/json_object_loader.h

// Copyright 2020 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_OBJECT_LOADER_H
#define GRPC_SRC_CORE_LIB_JSON_JSON_OBJECT_LOADER_H

#include <grpc/support/port_platform.h>

#include <cstdint>
#include <cstring>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "absl/meta/type_traits.h"
#include "absl/status/statusor.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"

#include "src/core/lib/gprpp/no_destruct.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/gprpp/time.h"
#include "src/core/lib/gprpp/validation_errors.h"
#include "src/core/lib/json/json.h"
#include "src/core/lib/json/json_args.h"

// Provides a means to load JSON objects into C++ objects, with the aim of
// minimizing object code size.
//
// Usage:
// Given struct Foo:
//   struct Foo {
//     int a;
//     int b;
//   };
// We add a static JsonLoader() method to Foo to declare how to load the
// object from JSON, and an optional JsonPostLoad() method to do any
// necessary post-processing:
//   struct Foo {
//     int a;
//     int b;
//     static const JsonLoaderInterface* JsonLoader(const JsonArgs& args) {
//       // Note: Field names must be string constants; they are not copied.
//       static const auto* loader = JsonObjectLoader<Foo>()
//           .Field("a", &Foo::a)
//           .Field("b", &Foo::b)
//           .Finish();
//       return loader;
//     }
//     // Optional; omit if no post-processing needed.
//     void JsonPostLoad(const Json& source, const JsonArgs& args,
//                       ValidationErrors* errors) {
//       ++a;
//     }
//   };
// Now we can load Foo objects from JSON:
//   absl::StatusOr<Foo> foo = LoadFromJson<Foo>(json);
namespace grpc_core {

namespace json_detail {

// An un-typed JSON loader.
class LoaderInterface {};

// Loads a scalar (string or number).
class LoadScalar : public LoaderInterface {};

// Load a string.
class LoadString : public LoadScalar {};

// Load a Duration.
class LoadDuration : public LoadScalar {};

// Load a number.
class LoadNumber : public LoadScalar {};

// Load a signed number of type T.
template <typename T>
class TypedLoadSignedNumber : public LoadNumber {};

// Load an unsigned number of type T.
template <typename T>
class TypedLoadUnsignedNumber : public LoadNumber {};

// Load a float.
class LoadFloat : public LoadNumber {};

// Load a double.
class LoadDouble : public LoadNumber {};

// Load a bool.
class LoadBool : public LoaderInterface {};

// Loads an unprocessed JSON object value.
class LoadUnprocessedJsonObject : public LoaderInterface {};

// Loads an unprocessed JSON array value.
class LoadUnprocessedJsonArray : public LoaderInterface {};

// Load a vector of some type.
class LoadVector : public LoaderInterface {};

// Load a map of string->some type.
class LoadMap : public LoaderInterface {};

// Load an optional of some type.
class LoadOptional : public LoaderInterface {};

// Fetch a LoaderInterface for some type.
template <typename T>
const LoaderInterface* LoaderForType();

// AutoLoader implements LoaderInterface for a type.
// The default asks the type for its LoaderInterface and then uses that.
// Classes that load from objects should provide a:
// static const JsonLoaderInterface* JsonLoader();
template <typename T>
class AutoLoader final : public LoaderInterface {};

// Specializations of AutoLoader for basic types.
template <>
class AutoLoader<std::string> final : public LoadString {};
template <>
class AutoLoader<Duration> final : public LoadDuration {};
template <>
class AutoLoader<int32_t> final : public TypedLoadSignedNumber<int32_t> {};
template <>
class AutoLoader<int64_t> final : public TypedLoadSignedNumber<int64_t> {};
template <>
class AutoLoader<uint32_t> final : public TypedLoadUnsignedNumber<uint32_t> {};
template <>
class AutoLoader<uint64_t> final : public TypedLoadUnsignedNumber<uint64_t> {};
template <>
class AutoLoader<float> final : public LoadFloat {};
template <>
class AutoLoader<double> final : public LoadDouble {};
template <>
class AutoLoader<bool> final : public LoadBool {};
template <>
class AutoLoader<Json::Object> final : public LoadUnprocessedJsonObject {};
template <>
class AutoLoader<Json::Array> final : public LoadUnprocessedJsonArray {};

// Specializations of AutoLoader for vectors.
AutoLoader<std::vector<T>>;

// Specialization of AutoLoader for vector<bool> - we need a different
// implementation because, as vector<bool> packs bits in its implementation, the
// technique of returning a void* from Emplace() for the generic vector loader
// doesn't work.
template <>
class AutoLoader<std::vector<bool>> final : public LoaderInterface {};

// Specializations of AutoLoader for maps.
AutoLoader<std::map<std::string, T>>;

// Specializations of AutoLoader for absl::optional<>.
AutoLoader<absl::optional<T>>;

// Specializations of AutoLoader for std::unique_ptr<>.
AutoLoader<std::unique_ptr<T>>;

// Implementation of aforementioned LoaderForType.
// Simply keeps a static AutoLoader<T> and returns a pointer to that.
template <typename T>
const LoaderInterface* LoaderForType() {}

// Element describes one typed field to be loaded from a JSON object.
struct Element {};

// Vec<T, kSize> provides a constant array type that can be appended to by
// copying. It's setup so that most compilers can optimize away all of its
// operations.
template <typename T, size_t kSize>
class Vec {};

Vec<T, 0>;

// Given a list of elements, and a destination object, load the elements into
// the object from some parsed JSON.
// Returns false if the JSON object was not of type Json::Type::OBJECT.
bool LoadObject(const Json& json, const JsonArgs& args, const Element* elements,
                size_t num_elements, void* dst, ValidationErrors* errors);

// Adaptor type - takes a compile time computed list of elements and
// implements LoaderInterface by calling LoadObject.
template <typename T, size_t kElemCount, typename Hidden = void>
class FinishedJsonObjectLoader final : public LoaderInterface {};

// Specialization for when the object has a JsonPostLoad function exposed.
FinishedJsonObjectLoader<T, kElemCount, absl::void_t<decltype(&T::JsonPostLoad)>>;

// Builder type for JSON object loaders.
// Concatenate fields with Field, OptionalField, and then call Finish to
// obtain an object that implements LoaderInterface.
template <typename T, size_t kElemCount = 0>
class JsonObjectLoader final {};

const Json* GetJsonObjectField(const Json::Object& json,
                               absl::string_view field,
                               ValidationErrors* errors, bool required);

}  // namespace json_detail

JsonObjectLoader;

JsonLoaderInterface;

template <typename T>
absl::StatusOr<T> LoadFromJson(
    const Json& json, const JsonArgs& args = JsonArgs(),
    absl::string_view error_prefix = "errors validating JSON") {}

template <typename T>
absl::StatusOr<RefCountedPtr<T>> LoadRefCountedFromJson(
    const Json& json, const JsonArgs& args = JsonArgs(),
    absl::string_view error_prefix = "errors validating JSON") {}

template <typename T>
T LoadFromJson(const Json& json, const JsonArgs& args,
               ValidationErrors* errors) {}

template <typename T>
absl::optional<T> LoadJsonObjectField(const Json::Object& json,
                                      const JsonArgs& args,
                                      absl::string_view field,
                                      ValidationErrors* errors,
                                      bool required = true) {}

}  // namespace grpc_core

#endif  // GRPC_SRC_CORE_LIB_JSON_JSON_OBJECT_LOADER_H