/* * 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. */ #pragma once #include #include #include #include namespace facebook { namespace thrift { namespace detail { /** * Pretty print specialization for enumerations. * * @author: Marcelo Juchem */ template struct pretty_print_impl> { template static void print(OutputStream& out, T const& what) { out << apache::thrift::util::enumName(what, nullptr); } }; /** * Pretty print specialization for lists. * * @author: Marcelo Juchem */ template struct pretty_print_impl> { template static void print(OutputStream& out, T const& what) { out << "["; if (!what.empty()) { out.newline(); const auto size = what.size(); std::size_t index = 0; for (const auto& i : what) { auto scope = out.start_scope(); scope << index << ": "; pretty_print_impl::print(scope, i); if (++index < size) { scope << ','; } scope.newline(); } } out << ']'; } }; /** * Pretty print specialization for maps. * * @author: Marcelo Juchem */ template struct pretty_print_impl> { template static void print(OutputStream& out, T const& what) { out << "{"; if (!what.empty()) { out.newline(); const auto size = what.size(); std::size_t index = 0; for (const auto& [key, value] : what) { auto scope = out.start_scope(); pretty_print_impl::print(scope, key); scope << ": "; pretty_print_impl::print(scope, value); if (++index < size) { scope << ','; } scope.newline(); } } out << '}'; } }; /** * Pretty print specialization for sets. * * @author: Marcelo Juchem */ template struct pretty_print_impl> { template static void print(OutputStream& out, T const& what) { out << "{"; if (!what.empty()) { out.newline(); const auto size = what.size(); std::size_t index = 0; for (const auto& i : what) { auto scope = out.start_scope(); pretty_print_impl::print(scope, i); if (++index < size) { scope << ','; } scope.newline(); } } out << '}'; } }; /** * Thrift structures and unions may contain members that are wrapped in smart * pointers. This class helps decode those. */ struct pretty_print_structure_with_pointers { protected: template static void recurse_into(OutputStream& out, T const& member) { pretty_print_impl::print(out, member); } }; /** * Pretty print specialization for variants (Thrift unions). * * @author: Marcelo Juchem */ template struct pretty_print_impl> : pretty_print_structure_with_pointers { template static void print(OutputStream& out, T const& what) { out << "{"; apache::thrift::op::invoke_by_field_id( static_cast(what.getType()), [&](auto id) { using Id = decltype(id); using Tag = apache::thrift::op::get_type_tag; auto scope = out.start_scope(); scope.newline(); scope << apache::thrift::util::enumName(what.getType(), nullptr) << ": "; if (const auto* fieldPtr = apache::thrift::op::getValueOrNull( apache::thrift::op::get(what))) { recurse_into(scope, *fieldPtr); } scope.newline(); }, [] { // union is __EMPTY__ }); out << '}'; } }; /* * Pretty print specialization for structures. * * @author: Marcelo Juchem */ template struct pretty_print_impl> : pretty_print_structure_with_pointers { template static void print(OutputStream& out, T const& what) { out << "{"; out.newline(); apache::thrift::op::for_each_field_id([&](auto id) { using Id = decltype(id); using Tag = apache::thrift::op::get_type_tag; constexpr auto size = apache::thrift::op::size_v; constexpr auto index = folly::to_underlying(apache::thrift::op::get_ordinal_v); if (const auto* fieldPtr = apache::thrift::op::getValueOrNull( apache::thrift::op::get(what))) { auto scope = out.start_scope(); scope << apache::thrift::op::get_name_v << ": "; recurse_into(scope, *fieldPtr); if (index < size) { scope << ','; } scope.newline(); } }); out << '}'; } }; template struct pretty_print_impl> : pretty_print_impl> {}; /** * Pretty print specialization for strings. * * @author: Marcelo Juchem */ template <> struct pretty_print_impl { template static void print(OutputStream& out, T const& what) { out << '"' << folly::cEscape(what) << '"'; } }; template <> struct pretty_print_impl { template static void print(OutputStream& out, T const& what) { out << R"("0x)" << folly::hexlify(what) << R"(")"; } template static void print(OutputStream& out, folly::IOBuf const& what) { return print(out, what.to()); } template static void print( OutputStream& out, std::unique_ptr const& what) { if (what) { return print(out, what->to()); } } }; template struct pretty_print_impl> { template static void print(OutputStream& out, T const& what) { pretty_print_impl::print(out, what); } }; template struct pretty_print_impl> { template static void print(OutputStream& out, T const& what) { pretty_print_impl::print(out, Adapter::toThrift(what)); } }; /** * Pretty print fallback specialization. * * @author: Marcelo Juchem */ template struct pretty_print_impl { template static void print(OutputStream& out, T const& what) { out << what; } template static void print(OutputStream& out, const bool what) { out << (what ? "true" : "false"); } }; } // namespace detail } // namespace thrift } // namespace facebook