2023-08-16 20:40:36 +01:00
|
|
|
/*
|
|
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
|
|
*
|
|
|
|
* 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 <oi/exporters/Json.h>
|
|
|
|
|
2023-08-25 18:46:34 +01:00
|
|
|
#include <algorithm>
|
2023-08-16 20:40:36 +01:00
|
|
|
#include <stdexcept>
|
2023-09-22 14:18:57 +01:00
|
|
|
#include <variant>
|
2023-08-16 20:40:36 +01:00
|
|
|
|
|
|
|
template <class>
|
|
|
|
inline constexpr bool always_false_v = false;
|
|
|
|
|
|
|
|
namespace oi::exporters {
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
template <typename It>
|
|
|
|
void printStringList(std::ostream& out, It it, It end, bool pretty) {
|
|
|
|
out << '[';
|
|
|
|
for (; it != end; ++it) {
|
|
|
|
out << '"' << (*it) << '"';
|
|
|
|
if (it != end - 1)
|
|
|
|
out << (pretty ? ", " : ",");
|
|
|
|
}
|
|
|
|
out << ']';
|
|
|
|
}
|
|
|
|
|
2023-08-25 18:46:34 +01:00
|
|
|
std::string makeIndent(size_t depth) {
|
|
|
|
depth = std::max(depth, 1UL);
|
|
|
|
return std::string((depth - 1) * 4, ' ');
|
2023-08-16 20:40:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
Json::Json(std::ostream& out) : out_(out) {
|
|
|
|
}
|
|
|
|
|
|
|
|
void Json::print(const IntrospectionResult& r) {
|
|
|
|
auto begin = r.cbegin();
|
|
|
|
return print(begin, r.cend());
|
|
|
|
}
|
|
|
|
|
|
|
|
void Json::print(IntrospectionResult::const_iterator& it,
|
|
|
|
IntrospectionResult::const_iterator end) {
|
|
|
|
std::vector<std::string_view> firstTypePath = it->type_path;
|
|
|
|
|
2023-08-25 18:46:34 +01:00
|
|
|
const auto indent = pretty_ ? makeIndent(firstTypePath.size()) : "";
|
|
|
|
const auto lastIndent =
|
|
|
|
pretty_ ? makeIndent(std::max(firstTypePath.size(), 1UL) - 1) : "";
|
2023-08-16 20:40:36 +01:00
|
|
|
const auto* tab = pretty_ ? " " : "";
|
|
|
|
const auto* space = pretty_ ? " " : "";
|
|
|
|
const auto* endl = pretty_ ? "\n" : "";
|
|
|
|
|
2023-08-25 18:46:34 +01:00
|
|
|
out_ << '[' << endl << indent;
|
2023-08-16 20:40:36 +01:00
|
|
|
|
|
|
|
bool first = true;
|
|
|
|
while (it != end) {
|
|
|
|
if (it->type_path.size() < firstTypePath.size()) {
|
|
|
|
// no longer a sibling, must be a sibling of the type we're printing
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!first)
|
|
|
|
out_ << ',' << endl << indent;
|
|
|
|
first = false;
|
|
|
|
|
|
|
|
out_ << '{' << endl << indent;
|
|
|
|
|
|
|
|
out_ << tab << "\"name\"" << space << ':' << space << "\"" << it->name
|
|
|
|
<< "\"," << endl
|
|
|
|
<< indent;
|
|
|
|
|
|
|
|
out_ << tab << "\"typePath\"" << space << ':' << space << "";
|
|
|
|
printStringList(out_, it->type_path.begin(), it->type_path.end(), pretty_);
|
|
|
|
out_ << (pretty_ ? ",\n" : ",") << indent;
|
|
|
|
|
|
|
|
out_ << tab << "\"typeNames\"" << space << ':' << space;
|
|
|
|
printStringList(out_, it->type_names.begin(), it->type_names.end(),
|
|
|
|
pretty_);
|
|
|
|
out_ << ',' << endl << indent;
|
|
|
|
|
|
|
|
out_ << tab << "\"staticSize\":" << space << it->static_size << ',' << endl
|
|
|
|
<< indent;
|
|
|
|
out_ << tab << "\"exclusiveSize\":" << space << it->exclusive_size << ','
|
|
|
|
<< endl
|
|
|
|
<< indent;
|
|
|
|
|
|
|
|
if (it->pointer.has_value()) {
|
|
|
|
out_ << tab << "\"pointer\":" << space << *(it->pointer) << ',' << endl
|
|
|
|
<< indent;
|
|
|
|
}
|
2023-09-22 14:18:57 +01:00
|
|
|
|
|
|
|
if (auto* s = std::get_if<result::Element::Scalar>(&it->data)) {
|
|
|
|
out_ << tab << "\"data\":" << space << s->n << ',' << endl << indent;
|
|
|
|
} else if (auto* p = std::get_if<result::Element::Pointer>(&it->data)) {
|
|
|
|
out_ << tab << "\"data\":" << space << "\"0x" << std::hex << p->p
|
|
|
|
<< std::dec << "\"," << endl
|
|
|
|
<< indent;
|
|
|
|
} else if (auto* str = std::get_if<std::string>(&it->data)) {
|
|
|
|
out_ << tab << "\"data\":" << space << "\"" << *str << "\"," << endl
|
|
|
|
<< indent;
|
|
|
|
}
|
|
|
|
|
2023-08-16 20:40:36 +01:00
|
|
|
if (it->container_stats.has_value()) {
|
|
|
|
out_ << tab << "\"length\":" << space << it->container_stats->length
|
|
|
|
<< ',' << endl
|
|
|
|
<< indent;
|
|
|
|
out_ << tab << "\"capacity\":" << space << it->container_stats->capacity
|
|
|
|
<< ',' << endl
|
|
|
|
<< indent;
|
|
|
|
}
|
|
|
|
if (it->is_set_stats.has_value()) {
|
|
|
|
out_ << tab << "\"is_set\":" << space << it->is_set_stats->is_set << ','
|
|
|
|
<< endl
|
|
|
|
<< indent;
|
|
|
|
}
|
|
|
|
|
|
|
|
out_ << tab << "\"members\":" << space;
|
2023-09-11 17:37:19 +01:00
|
|
|
if (++it != end && it->type_path.size() > firstTypePath.size()) {
|
2023-08-16 20:40:36 +01:00
|
|
|
print(it, end);
|
|
|
|
} else {
|
2023-08-25 18:46:34 +01:00
|
|
|
out_ << "[]" << endl;
|
2023-08-16 20:40:36 +01:00
|
|
|
}
|
|
|
|
|
2023-08-25 18:46:34 +01:00
|
|
|
out_ << indent << "}";
|
|
|
|
}
|
|
|
|
if (firstTypePath.size() == 1) {
|
|
|
|
out_ << endl << ']' << endl;
|
|
|
|
} else {
|
|
|
|
out_ << endl << lastIndent << tab << ']' << endl;
|
2023-08-16 20:40:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace oi::exporters
|