include/ylt/standalone/iguana/yaml_writer.hpp (180 lines of code) (raw):

#pragma once #include "detail/charconv.h" #include "yaml_util.hpp" namespace iguana { template <bool Is_writing_escape = false, typename Stream, typename T, std::enable_if_t<yaml_not_support_v<T>, int> = 0> IGUANA_INLINE void render_yaml_value(Stream &ss, T &&t, size_t min_spaces = 0) { throw std::bad_function_call(); } template <bool Is_writing_escape = false, typename Stream, typename T, std::enable_if_t<ylt_refletable_v<T>, int> = 0> IGUANA_INLINE void to_yaml(T &&t, Stream &s, size_t min_spaces = 0); template <bool Is_writing_escape, typename Stream, typename T, std::enable_if_t<ylt_refletable_v<T>, int> = 0> IGUANA_INLINE void render_yaml_value(Stream &ss, T &&t, size_t min_spaces) { ss.push_back('\n'); to_yaml<Is_writing_escape>(std::forward<T>(t), ss, min_spaces); } template <bool Is_writing_escape, bool appendLf = true, typename Stream, typename T, std::enable_if_t<string_container_v<T>, int> = 0> IGUANA_INLINE void render_yaml_value(Stream &ss, T &&t, size_t min_spaces) { if constexpr (Is_writing_escape) { ss.push_back('"'); write_string_with_escape(t.data(), t.size(), ss); ss.push_back('"'); } else { ss.append(t.data(), t.size()); } if constexpr (appendLf) ss.push_back('\n'); } template <bool Is_writing_escape, bool appendLf = true, typename Stream, typename T, std::enable_if_t<num_v<T>, int> = 0> IGUANA_INLINE void render_yaml_value(Stream &ss, T value, size_t min_spaces) { char temp[65]; auto p = detail::to_chars(temp, value); ss.append(temp, p - temp); if constexpr (appendLf) ss.push_back('\n'); } template <bool Is_writing_escape, bool appendLf = true, typename Stream, typename T, std::enable_if_t<is_pb_type_v<T>, int> = 0> IGUANA_INLINE void render_yaml_value(Stream &ss, T value, size_t min_spaces) { render_yaml_value<Is_writing_escape>(ss, value.val, min_spaces); } template <bool Is_writing_escape, bool appendLf = true, typename Stream> IGUANA_INLINE void render_yaml_value(Stream &ss, char value, size_t min_spaces) { ss.push_back(value); if constexpr (appendLf) ss.push_back('\n'); } template <bool Is_writing_escape, bool appendLf = true, typename Stream> IGUANA_INLINE void render_yaml_value(Stream &ss, bool value, size_t min_spaces) { ss.append(value ? "true" : "false"); if constexpr (appendLf) ss.push_back('\n'); } template <bool Is_writing_escape, bool appendLf = true, typename Stream, typename T, std::enable_if_t<enum_v<T>, int> = 0> IGUANA_INLINE void render_yaml_value(Stream &ss, T value, size_t min_spaces) { static constexpr auto enum_to_str = get_enum_map<false, std::decay_t<T>>(); if constexpr (bool_v<decltype(enum_to_str)>) { render_yaml_value<Is_writing_escape>( ss, static_cast<std::underlying_type_t<T>>(value), min_spaces); } else { auto it = enum_to_str.find(value); if (it != enum_to_str.end()) IGUANA_LIKELY { auto str = it->second; render_yaml_value<Is_writing_escape>( ss, std::string_view(str.data(), str.size()), min_spaces); } else { throw std::runtime_error( std::to_string(static_cast<std::underlying_type_t<T>>(value)) + " is a missing value in enum_value"); } } } template <bool Is_writing_escape, typename Stream, typename T, std::enable_if_t<optional_v<T>, int> = 0> IGUANA_INLINE void render_yaml_value(Stream &ss, const T &val, size_t min_spaces); template <bool Is_writing_escape, typename Stream, typename T, std::enable_if_t<smart_ptr_v<T>, int> = 0> IGUANA_INLINE void render_yaml_value(Stream &ss, const T &val, size_t min_spaces); template <bool Is_writing_escape, typename Stream, typename T, std::enable_if_t<sequence_container_v<T>, int> = 0> IGUANA_INLINE void render_yaml_value(Stream &ss, const T &t, size_t min_spaces) { ss.push_back('\n'); for (const auto &v : t) { ss.append(min_spaces, ' '); ss.append("- "); render_yaml_value<Is_writing_escape>(ss, v, min_spaces + 1); } } template <bool Is_writing_escape, typename Stream, typename T, std::enable_if_t<tuple_v<T>, int> = 0> IGUANA_INLINE void render_yaml_value(Stream &ss, T &&t, size_t min_spaces) { ss.push_back('\n'); for_each_tuple( [&ss, min_spaces](auto &v) IGUANA__INLINE_LAMBDA { ss.append(min_spaces, ' '); ss.append("- "); render_yaml_value<Is_writing_escape>(ss, v, min_spaces + 1); }, std::forward<T>(t)); } template <bool Is_writing_escape, typename Stream, typename T, std::enable_if_t<map_container_v<T>, int> = 0> IGUANA_INLINE void render_yaml_value(Stream &ss, const T &t, size_t min_spaces) { ss.push_back('\n'); for (const auto &[k, v] : t) { ss.append(min_spaces, ' '); render_yaml_value<false, false>(ss, k, 0); // key must be plaint type ss.append(": "); render_yaml_value<Is_writing_escape>(ss, v, min_spaces + 1); } } template <bool Is_writing_escape, typename Stream, typename T, std::enable_if_t<optional_v<T>, int>> IGUANA_INLINE void render_yaml_value(Stream &ss, const T &val, size_t min_spaces) { if (!val) { ss.append("null"); ss.push_back('\n'); } else { render_yaml_value<Is_writing_escape>(ss, *val, min_spaces); } } template <bool Is_writing_escape, typename Stream, typename T, std::enable_if_t<smart_ptr_v<T>, int>> IGUANA_INLINE void render_yaml_value(Stream &ss, const T &val, size_t min_spaces) { if (!val) { ss.push_back('\n'); } else { render_yaml_value<Is_writing_escape>(ss, *val, min_spaces); } } template <bool Is_writing_escape, typename Stream, typename T, std::enable_if_t<ylt_refletable_v<T>, int>> IGUANA_INLINE void to_yaml(T &&t, Stream &s, size_t min_spaces) { ylt::reflection::for_each(t, [&](auto &field, auto field_name, auto index) { s.append(min_spaces, ' '); s.append(field_name); s.append(": "); if constexpr (!ylt_refletable_v<std::decay_t<decltype(field)>>) { render_yaml_value<Is_writing_escape>(s, field, min_spaces + 1); } else { s.push_back('\n'); to_yaml<Is_writing_escape>(field, s, min_spaces + 1); } }); } template <bool Is_writing_escape = false, typename Stream, typename T, std::enable_if_t<non_ylt_refletable_v<T>, int> = 0> IGUANA_INLINE void to_yaml(T &&t, Stream &s) { if constexpr (tuple_v<T> || map_container_v<T> || sequence_container_v<T> || optional_v<T> || smart_ptr_v<T>) render_yaml_value<Is_writing_escape>(s, std::forward<T>(t), 0); else static_assert(!sizeof(T), "don't suppport this type"); } template <typename T> IGUANA_INLINE void to_yaml_adl(iguana_adl_t *p, const T &t, std::string &pb_str) { to_yaml(t, pb_str); } } // namespace iguana