plugins/wasm-cpp/common/json_util.cc (169 lines of code) (raw):
/* Copyright 2020 Istio Authors. All Rights Reserved.
*
* 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.
*/
#include "json_util.h"
#include <string>
#include "absl/strings/numbers.h"
namespace Wasm {
namespace Common {
std::optional<JsonObject> JsonParse(std::string_view str) {
const auto result = JsonObject::parse(str, nullptr, false);
if (result.is_discarded() || !result.is_object()) {
return std::nullopt;
}
return result;
}
template <>
std::pair<std::optional<int64_t>, JsonParserResultDetail> JsonValueAs<int64_t>(
const JsonObject& j) {
if (j.is_number()) {
return std::make_pair(j.get<int64_t>(), JsonParserResultDetail::OK);
} else if (j.is_string()) {
int64_t result = 0;
if (absl::SimpleAtoi(j.get_ref<std::string const&>(), &result)) {
return std::make_pair(result, JsonParserResultDetail::OK);
} else {
return std::make_pair(std::nullopt,
JsonParserResultDetail::INVALID_VALUE);
}
}
return std::make_pair(std::nullopt, JsonParserResultDetail::TYPE_ERROR);
}
template <>
std::pair<std::optional<uint64_t>, JsonParserResultDetail>
JsonValueAs<uint64_t>(const JsonObject& j) {
if (j.is_number()) {
return std::make_pair(j.get<uint64_t>(), JsonParserResultDetail::OK);
} else if (j.is_string()) {
uint64_t result = 0;
if (absl::SimpleAtoi(j.get_ref<std::string const&>(), &result)) {
return std::make_pair(result, JsonParserResultDetail::OK);
} else {
return std::make_pair(std::nullopt,
JsonParserResultDetail::INVALID_VALUE);
}
}
return std::make_pair(std::nullopt, JsonParserResultDetail::TYPE_ERROR);
}
template <>
std::pair<std::optional<std::string_view>, JsonParserResultDetail>
JsonValueAs<std::string_view>(const JsonObject& j) {
if (j.is_string()) {
return std::make_pair(std::string_view(j.get_ref<std::string const&>()),
JsonParserResultDetail::OK);
}
return std::make_pair(std::nullopt, JsonParserResultDetail::TYPE_ERROR);
}
template <>
std::pair<std::optional<std::string>, JsonParserResultDetail>
JsonValueAs<std::string>(const JsonObject& j) {
if (j.is_string()) {
return std::make_pair(j.get_ref<std::string const&>(),
JsonParserResultDetail::OK);
}
if (j.is_number_unsigned()) {
return std::make_pair(
std::to_string((unsigned long long)(j.get<uint64_t>())),
JsonParserResultDetail::OK);
}
return std::make_pair(std::nullopt, JsonParserResultDetail::TYPE_ERROR);
}
template <>
std::pair<std::optional<bool>, JsonParserResultDetail> JsonValueAs<bool>(
const JsonObject& j) {
if (j.is_boolean()) {
return std::make_pair(j.get<bool>(), JsonParserResultDetail::OK);
}
if (j.is_string()) {
const std::string& v = j.get_ref<std::string const&>();
if (v == "true") {
return std::make_pair(true, JsonParserResultDetail::OK);
} else if (v == "false") {
return std::make_pair(false, JsonParserResultDetail::OK);
} else {
return std::make_pair(std::nullopt,
JsonParserResultDetail::INVALID_VALUE);
}
}
return std::make_pair(std::nullopt, JsonParserResultDetail::TYPE_ERROR);
}
template <>
std::pair<std::optional<std::vector<std::string_view>>, JsonParserResultDetail>
JsonValueAs<std::vector<std::string_view>>(const JsonObject& j) {
std::pair<std::optional<std::vector<std::string_view>>,
JsonParserResultDetail>
values = std::make_pair(std::nullopt, JsonParserResultDetail::OK);
if (j.is_array()) {
for (const auto& elt : j) {
if (!elt.is_string()) {
values.first = std::nullopt;
values.second = JsonParserResultDetail::TYPE_ERROR;
return values;
}
if (!values.first.has_value()) {
values.first = std::vector<std::string_view>();
}
values.first->emplace_back(elt.get_ref<std::string const&>());
}
return values;
}
values.second = JsonParserResultDetail::TYPE_ERROR;
return values;
}
template <>
std::pair<std::optional<JsonObject>, JsonParserResultDetail>
JsonValueAs<JsonObject>(const JsonObject& j) {
if (j.is_object()) {
return std::make_pair(j.get<JsonObject>(), JsonParserResultDetail::OK);
}
return std::make_pair(std::nullopt, JsonParserResultDetail::TYPE_ERROR);
}
bool JsonArrayIterate(
const JsonObject& j, std::string_view field,
const std::function<bool(const JsonObject& elt)>& visitor) {
auto it = j.find(field);
if (it == j.end()) {
return true;
}
if (!it.value().is_array()) {
return false;
}
for (const auto& elt : it.value().items()) {
if (!visitor(elt.value())) {
return false;
}
}
return true;
}
bool JsonObjectIterate(const JsonObject& j, std::string_view field,
const std::function<bool(std::string key)>& visitor) {
auto it = j.find(field);
if (it == j.end()) {
return true;
}
if (!it.value().is_object()) {
return false;
}
for (const auto& elt : it.value().items()) {
auto json_value = JsonValueAs<std::string>(elt.key());
if (json_value.second != JsonParserResultDetail::OK) {
return false;
}
if (!visitor(json_value.first.value())) {
return false;
}
}
return true;
}
bool JsonObjectIterate(const JsonObject& j,
const std::function<bool(std::string key)>& visitor) {
for (const auto& elt : j.items()) {
auto json_value = JsonValueAs<std::string>(elt.key());
if (json_value.second != JsonParserResultDetail::OK) {
return false;
}
if (!visitor(json_value.first.value())) {
return false;
}
}
return true;
}
} // namespace Common
} // namespace Wasm