#pragma once #include "toml_formatter.h" TOML_START { template std::basic_ostream& operator << (std::basic_ostream&, json_formatter&) TOML_MAY_THROW; template std::basic_ostream& operator << (std::basic_ostream&, json_formatter&&) TOML_MAY_THROW; /// \brief A wrapper for printing TOML objects out to a stream as formatted JSON. /// /// \detail \cpp /// auto some_toml = toml::parse(R"( /// [fruit] /// apple.color = "red" /// apple.taste.sweet = true /// /// [fruit.apple.texture] /// smooth = true /// )"sv); /// std::cout << toml::json_formatter{ some_toml } << std::endl; /// /// \ecpp /// /// \out /// { /// "fruit" : { /// "apple" : { /// "color" : "red", /// "taste" : { /// "sweet" : true /// }, /// "texture" : { /// "smooth" : true /// } /// } /// } /// } /// \eout /// /// \tparam CHAR The underlying character type of the output stream. Must be 1 byte in size. template class json_formatter final : impl::formatter { private: using base = impl::formatter; inline void print(const toml::table& tbl) TOML_MAY_THROW; void print(const array& arr) TOML_MAY_THROW { if (arr.empty()) impl::print_to_stream("[]"sv, base::stream()); else { impl::print_to_stream('[', base::stream()); base::increase_indent(); for (size_t i = 0; i < arr.size(); i++) { if (i > 0_sz) impl::print_to_stream(',', base::stream()); base::print_newline(true); base::print_indent(); auto& v = arr[i]; const auto type = v.type(); switch (type) { case node_type::table: print(*reinterpret_cast(&v)); break; case node_type::array: print(*reinterpret_cast(&v)); break; default: base::print(v, type); } } base::decrease_indent(); base::print_newline(true); base::print_indent(); impl::print_to_stream(']', base::stream()); } base::clear_naked_newline(); } void print() TOML_MAY_THROW { switch (auto source_type = base::source().type()) { case node_type::table: print(*reinterpret_cast(&base::source())); break; case node_type::array: print(*reinterpret_cast(&base::source())); break; default: base::print(base::source(), source_type); } } public: /// \brief Constructs a JSON formatter and binds it to a TOML object. /// /// \param source The source TOML object. /// \param flags Format option flags. TOML_NODISCARD_CTOR explicit json_formatter( const toml::node& source, format_flags flags = format_flags::quote_dates_and_times) noexcept : base{ source, flags } {} template friend std::basic_ostream& operator << (std::basic_ostream&, json_formatter&) TOML_MAY_THROW; template friend std::basic_ostream& operator << (std::basic_ostream&, json_formatter&&) TOML_MAY_THROW; }; template inline void json_formatter::print(const toml::table& tbl) TOML_MAY_THROW { if (tbl.empty()) impl::print_to_stream("{}"sv, base::stream()); else { impl::print_to_stream('{', base::stream()); base::increase_indent(); bool first = false; for (auto [k, v] : tbl) { if (first) impl::print_to_stream(", "sv, base::stream()); first = true; base::print_newline(true); base::print_indent(); base::print_quoted_string(k); impl::print_to_stream(" : "sv, base::stream()); const auto type = v.type(); switch (type) { case node_type::table: print(*reinterpret_cast(&v)); break; case node_type::array: print(*reinterpret_cast(&v)); break; default: base::print(v, type); } } base::decrease_indent(); base::print_newline(true); base::print_indent(); impl::print_to_stream('}', base::stream()); } base::clear_naked_newline(); } /// \brief Prints the bound TOML object out to the stream as JSON. template inline std::basic_ostream& operator << (std::basic_ostream& lhs, json_formatter& rhs) TOML_MAY_THROW { rhs.attach(lhs); rhs.print(); rhs.detach(); return lhs; } /// \brief Prints the bound TOML object out to the stream as JSON (rvalue overload). template inline std::basic_ostream& operator << (std::basic_ostream& lhs, json_formatter&& rhs) TOML_MAY_THROW { return lhs << rhs; //as lvalue } } TOML_END