scimpl_json_write.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. #include "scimpl.h"
  2. #include "scimpl_private.h"
  3. #include <library/cpp/json/json_prettifier.h>
  4. #include <library/cpp/string_utils/relaxed_escaper/relaxed_escaper.h>
  5. #include <util/charset/utf8.h>
  6. #include <util/generic/algorithm.h>
  7. #include <util/generic/ymath.h>
  8. #include <util/system/tls.h>
  9. namespace NSc {
  10. bool TJsonOpts::StringPolicySafe(TStringBuf& s) {
  11. return IsUtf(s);
  12. }
  13. bool TJsonOpts::NumberPolicySafe(double& d) {
  14. return IsFinite(d);
  15. }
  16. static inline void WriteString(IOutputStream& out, TStringBuf s) {
  17. NEscJ::EscapeJ<true, true>(s, out);
  18. }
  19. static inline const NSc::TValue& GetValue(size_t, TStringBuf key, const TDict& dict) {
  20. return dict.find(key)->second;
  21. }
  22. static inline const NSc::TValue& GetValue(TDict::const_iterator it, TStringBuf, const TDict&) {
  23. return it->second;
  24. }
  25. static inline TStringBuf GetKey(size_t it, const NImpl::TKeySortContext::TGuard& keys) {
  26. return keys.GetVector()[it];
  27. }
  28. static inline TStringBuf GetKey(TDict::const_iterator it, const TDict&) {
  29. return it->first;
  30. }
  31. template <typename TDictKeys>
  32. static inline void WriteDict(IOutputStream& out, const TDictKeys& keys, const TDict& dict,
  33. const TJsonOpts& jopts, NImpl::TKeySortContext& sortCtx, NImpl::TSelfLoopContext& loopCtx) {
  34. using const_iterator = typename TDictKeys::const_iterator;
  35. const_iterator begin = keys.begin();
  36. const_iterator end = keys.end();
  37. for (const_iterator it = begin; it != end; ++it) {
  38. TStringBuf key = GetKey(it, keys);
  39. if (jopts.StringPolicy && !jopts.StringPolicy(key)) {
  40. ++begin;
  41. continue;
  42. }
  43. if (it != begin) {
  44. out << ',';
  45. }
  46. NEscJ::EscapeJ<true, true>(key, out);
  47. out << ':';
  48. GetValue(it, key, dict).DoWriteJsonImpl(out, jopts, sortCtx, loopCtx);
  49. }
  50. }
  51. void TValue::DoWriteJsonImpl(IOutputStream& out, const TJsonOpts& jopts,
  52. NImpl::TKeySortContext& sortCtx, NImpl::TSelfLoopContext& loopCtx) const {
  53. const TScCore& core = Core();
  54. NImpl::TSelfLoopContext::TGuard loopCheck(loopCtx, core);
  55. if (!loopCheck.Ok) {
  56. out << TStringBuf("null"); // a loop encountered (and asserted), skip the back reference
  57. return;
  58. }
  59. switch (core.ValueType) {
  60. default: {
  61. Y_ASSERT(false);
  62. [[fallthrough]]; /* no break */
  63. }
  64. case EType::Null: {
  65. out << TStringBuf("null");
  66. break;
  67. }
  68. case EType::Bool: {
  69. out << (core.IntNumber ? TStringBuf("true") : TStringBuf("false"));
  70. break;
  71. }
  72. case EType::IntNumber: {
  73. out << core.IntNumber;
  74. break;
  75. }
  76. case EType::FloatNumber: {
  77. double d = core.FloatNumber;
  78. if (!jopts.NumberPolicy || jopts.NumberPolicy(d)) {
  79. out << d;
  80. } else {
  81. out << TStringBuf("null");
  82. }
  83. break;
  84. }
  85. case EType::String: {
  86. TStringBuf s = core.String;
  87. if (!jopts.StringPolicy || jopts.StringPolicy(s)) {
  88. WriteString(out, s);
  89. } else {
  90. out << TStringBuf("null");
  91. }
  92. break;
  93. }
  94. case EType::Array: {
  95. out << '[';
  96. const TArray& a = core.GetArray();
  97. for (TArray::const_iterator it = a.begin(); it != a.end(); ++it) {
  98. if (it != a.begin()) {
  99. out << ',';
  100. }
  101. it->DoWriteJsonImpl(out, jopts, sortCtx, loopCtx);
  102. }
  103. out << ']';
  104. break;
  105. }
  106. case EType::Dict: {
  107. out << '{';
  108. const TDict& dict = core.GetDict();
  109. if (jopts.SortKeys) {
  110. NImpl::TKeySortContext::TGuard keys(sortCtx, dict);
  111. WriteDict(out, keys, dict, jopts, sortCtx, loopCtx);
  112. } else {
  113. WriteDict(out, dict, dict, jopts, sortCtx, loopCtx);
  114. }
  115. out << '}';
  116. break;
  117. }
  118. }
  119. }
  120. const TValue& TValue::ToJson(IOutputStream& out, const TJsonOpts& jopts) const {
  121. using namespace NImpl;
  122. if (jopts.FormatJson) {
  123. TStringStream str;
  124. DoWriteJsonImpl(str, jopts, GetTlsInstance<TKeySortContext>(), GetTlsInstance<TSelfLoopContext>());
  125. NJson::PrettifyJson(str.Str(), out);
  126. } else {
  127. DoWriteJsonImpl(out, jopts, GetTlsInstance<TKeySortContext>(), GetTlsInstance<TSelfLoopContext>());
  128. }
  129. return *this;
  130. }
  131. TString TValue::ToJson(const TJsonOpts& jopts) const {
  132. TString s;
  133. {
  134. TStringOutput out(s);
  135. ToJson(out, jopts);
  136. }
  137. return s;
  138. }
  139. TJsonOpts TValue::MakeOptsSafeForSerializer(TJsonOpts opts) {
  140. opts.SortKeys = true;
  141. opts.StringPolicy = TJsonOpts::StringPolicySafe;
  142. opts.NumberPolicy = TJsonOpts::NumberPolicySafe;
  143. return opts;
  144. }
  145. TJsonOpts TValue::MakeOptsPrettyForSerializer(TJsonOpts opts) {
  146. opts.FormatJson = true;
  147. return MakeOptsSafeForSerializer(opts);
  148. }
  149. TString TValue::ToJsonSafe(const TJsonOpts& jopts) const {
  150. return ToJson(MakeOptsSafeForSerializer(jopts));
  151. }
  152. const TValue& TValue::ToJsonSafe(IOutputStream& out, const TJsonOpts& jopts) const {
  153. return ToJson(out, MakeOptsSafeForSerializer(jopts));
  154. }
  155. TString TValue::ToJsonPretty(const TJsonOpts& jopts) const {
  156. return ToJson(MakeOptsPrettyForSerializer(jopts));
  157. }
  158. const TValue& TValue::ToJsonPretty(IOutputStream& out, const TJsonOpts& jopts) const {
  159. return ToJson(out, MakeOptsPrettyForSerializer(jopts));
  160. }
  161. }