proto2json_printer.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  1. #include "proto2json_printer.h"
  2. #include "config.h"
  3. #include "util.h"
  4. #include <google/protobuf/any.pb.h>
  5. #include <google/protobuf/dynamic_message.h>
  6. #include <google/protobuf/util/time_util.h>
  7. #include <library/cpp/protobuf/json/proto/enum_options.pb.h>
  8. #include <util/generic/map.h>
  9. #include <util/generic/yexception.h>
  10. #include <util/string/ascii.h>
  11. #include <util/string/cast.h>
  12. #include <util/system/win_undef.h>
  13. namespace NProtobufJson {
  14. using namespace NProtoBuf;
  15. class TJsonKeyBuilder {
  16. public:
  17. TJsonKeyBuilder(const FieldDescriptor& field, const TProto2JsonConfig& config, TString& tmpBuf)
  18. : NewKeyStr(tmpBuf)
  19. {
  20. if (config.NameGenerator) {
  21. NewKeyStr = config.NameGenerator(field);
  22. NewKeyBuf = NewKeyStr;
  23. return;
  24. }
  25. if (config.UseJsonName) {
  26. Y_ASSERT(!field.json_name().empty());
  27. NewKeyStr = field.json_name();
  28. if (!field.has_json_name() && !NewKeyStr.empty()) {
  29. // FIXME: https://st.yandex-team.ru/CONTRIB-139
  30. NewKeyStr[0] = AsciiToLower(NewKeyStr[0]);
  31. }
  32. NewKeyBuf = NewKeyStr;
  33. return;
  34. }
  35. switch (config.FieldNameMode) {
  36. case TProto2JsonConfig::FieldNameOriginalCase: {
  37. NewKeyBuf = field.name();
  38. break;
  39. }
  40. case TProto2JsonConfig::FieldNameLowerCase: {
  41. NewKeyStr = field.name();
  42. NewKeyStr.to_lower();
  43. NewKeyBuf = NewKeyStr;
  44. break;
  45. }
  46. case TProto2JsonConfig::FieldNameUpperCase: {
  47. NewKeyStr = field.name();
  48. NewKeyStr.to_upper();
  49. NewKeyBuf = NewKeyStr;
  50. break;
  51. }
  52. case TProto2JsonConfig::FieldNameCamelCase: {
  53. NewKeyStr = field.name();
  54. if (!NewKeyStr.empty()) {
  55. NewKeyStr[0] = AsciiToLower(NewKeyStr[0]);
  56. }
  57. NewKeyBuf = NewKeyStr;
  58. break;
  59. }
  60. case TProto2JsonConfig::FieldNameSnakeCase: {
  61. NewKeyStr = field.name();
  62. ToSnakeCase(&NewKeyStr);
  63. NewKeyBuf = NewKeyStr;
  64. break;
  65. }
  66. case TProto2JsonConfig::FieldNameSnakeCaseDense: {
  67. NewKeyStr = field.name();
  68. ToSnakeCaseDense(&NewKeyStr);
  69. NewKeyBuf = NewKeyStr;
  70. break;
  71. }
  72. default:
  73. Y_DEBUG_ABORT_UNLESS(false, "Unknown FieldNameMode.");
  74. }
  75. }
  76. const TStringBuf& GetKey() const {
  77. return NewKeyBuf;
  78. }
  79. private:
  80. TStringBuf NewKeyBuf;
  81. TString& NewKeyStr;
  82. };
  83. TProto2JsonPrinter::TProto2JsonPrinter(const TProto2JsonConfig& cfg)
  84. : Config(cfg)
  85. {
  86. }
  87. TProto2JsonPrinter::~TProto2JsonPrinter() {
  88. }
  89. TStringBuf TProto2JsonPrinter::MakeKey(const FieldDescriptor& field) {
  90. return TJsonKeyBuilder(field, GetConfig(), TmpBuf).GetKey();
  91. }
  92. template <bool InMapContext, typename T>
  93. std::enable_if_t<InMapContext, void> WriteWithMaybeEmptyKey(IJsonOutput& json, const TStringBuf& key, const T& value) {
  94. json.WriteKey(key).Write(value);
  95. }
  96. template <bool InMapContext, typename T>
  97. std::enable_if_t<!InMapContext, void> WriteWithMaybeEmptyKey(IJsonOutput& array, const TStringBuf& key, const T& value) {
  98. Y_ASSERT(!key);
  99. array.Write(value);
  100. }
  101. template <bool InMapContext>
  102. Y_NO_INLINE void TProto2JsonPrinter::PrintStringValue(const FieldDescriptor& field,
  103. const TStringBuf& key, const TString& value,
  104. IJsonOutput& json) {
  105. if (!GetConfig().StringTransforms.empty()) {
  106. TString tmpBuf = value;
  107. for (const TStringTransformPtr& stringTransform : GetConfig().StringTransforms) {
  108. Y_ASSERT(stringTransform);
  109. if (stringTransform) {
  110. if (field.type() == FieldDescriptor::TYPE_BYTES)
  111. stringTransform->TransformBytes(tmpBuf);
  112. else
  113. stringTransform->Transform(tmpBuf);
  114. }
  115. }
  116. WriteWithMaybeEmptyKey<InMapContext>(json, key, tmpBuf);
  117. } else {
  118. WriteWithMaybeEmptyKey<InMapContext>(json, key, value);
  119. }
  120. }
  121. template <bool InMapContext>
  122. void TProto2JsonPrinter::PrintEnumValue(const TStringBuf& key,
  123. const EnumValueDescriptor* value,
  124. IJsonOutput& json) {
  125. if (Config.EnumValueGenerator) {
  126. WriteWithMaybeEmptyKey<InMapContext>(json, key, Config.EnumValueGenerator(*value));
  127. return;
  128. }
  129. if (Config.UseJsonEnumValue) {
  130. auto jsonEnumValue = value->options().GetExtension(json_enum_value);
  131. if (!jsonEnumValue) {
  132. ythrow yexception() << "Trying to using json enum value for field " << value->name() << " which is not set.";
  133. }
  134. WriteWithMaybeEmptyKey<InMapContext>(json, key, jsonEnumValue);
  135. return;
  136. }
  137. switch (GetConfig().EnumMode) {
  138. case TProto2JsonConfig::EnumNumber: {
  139. WriteWithMaybeEmptyKey<InMapContext>(json, key, value->number());
  140. break;
  141. }
  142. case TProto2JsonConfig::EnumName: {
  143. WriteWithMaybeEmptyKey<InMapContext>(json, key, value->name());
  144. break;
  145. }
  146. case TProto2JsonConfig::EnumFullName: {
  147. WriteWithMaybeEmptyKey<InMapContext>(json, key, value->full_name());
  148. break;
  149. }
  150. case TProto2JsonConfig::EnumNameLowerCase: {
  151. TString newName = value->name();
  152. newName.to_lower();
  153. WriteWithMaybeEmptyKey<InMapContext>(json, key, newName);
  154. break;
  155. }
  156. case TProto2JsonConfig::EnumFullNameLowerCase: {
  157. TString newName = value->full_name();
  158. newName.to_lower();
  159. WriteWithMaybeEmptyKey<InMapContext>(json, key, newName);
  160. break;
  161. }
  162. default:
  163. Y_DEBUG_ABORT_UNLESS(false, "Unknown EnumMode.");
  164. }
  165. }
  166. bool HandleTimeConversion(const Message& proto, IJsonOutput& json) {
  167. using namespace google::protobuf;
  168. auto type = proto.GetDescriptor()->well_known_type();
  169. // XXX static_cast will cause UB if used with dynamic messages
  170. // (can be created by a DynamicMessageFactory with SetDelegateToGeneratedFactory(false). Unlikely, but still possible).
  171. // See workaround with CopyFrom in JsonString2Duration, JsonString2Timestamp (json2proto.cpp)
  172. if (type == Descriptor::WellKnownType::WELLKNOWNTYPE_DURATION) {
  173. const auto& duration = static_cast<const Duration&>(proto);
  174. json.Write(util::TimeUtil::ToString(duration));
  175. return true;
  176. } else if (type == Descriptor::WellKnownType::WELLKNOWNTYPE_TIMESTAMP) {
  177. const auto& timestamp = static_cast<const Timestamp&>(proto);
  178. json.Write(util::TimeUtil::ToString(timestamp));
  179. return true;
  180. }
  181. return false;
  182. }
  183. bool TProto2JsonPrinter::TryPrintAny(const Message& proto, IJsonOutput& json) {
  184. using namespace google::protobuf;
  185. const FieldDescriptor* typeUrlField;
  186. const FieldDescriptor* valueField;
  187. if (!Any::GetAnyFieldDescriptors(proto, &typeUrlField, &valueField)) {
  188. return false;
  189. }
  190. const Reflection* const reflection = proto.GetReflection();
  191. const TString& typeUrl = reflection->GetString(proto, typeUrlField);
  192. TString fullTypeName;
  193. if (!Any::ParseAnyTypeUrl(typeUrl, &fullTypeName)) {
  194. return false;
  195. }
  196. const Descriptor* const valueDesc = proto.GetDescriptor()->file()->pool()->FindMessageTypeByName(fullTypeName);
  197. if (!valueDesc) {
  198. return false;
  199. }
  200. DynamicMessageFactory factory;
  201. const THolder<Message> valueMessage{factory.GetPrototype(valueDesc)->New()};
  202. const TString& serializedValue = reflection->GetString(proto, valueField);
  203. if (!valueMessage->ParseFromString(serializedValue)) {
  204. return false;
  205. }
  206. json.BeginObject();
  207. json.WriteKey("@type").Write(typeUrl);
  208. PrintFields(*valueMessage, json);
  209. json.EndObject();
  210. return true;
  211. }
  212. void TProto2JsonPrinter::PrintSingleField(const Message& proto,
  213. const FieldDescriptor& field,
  214. IJsonOutput& json,
  215. TStringBuf key,
  216. bool inProtoMap) {
  217. Y_ABORT_UNLESS(!field.is_repeated(), "field is repeated.");
  218. if (!key) {
  219. key = MakeKey(field);
  220. }
  221. #define FIELD_TO_JSON(EProtoCppType, ProtoGet) \
  222. case FieldDescriptor::EProtoCppType: { \
  223. json.WriteKey(key).Write(reflection->ProtoGet(proto, &field)); \
  224. break; \
  225. }
  226. #define INT_FIELD_TO_JSON(EProtoCppType, ProtoGet) \
  227. case FieldDescriptor::EProtoCppType: { \
  228. const auto value = reflection->ProtoGet(proto, &field); \
  229. if (NeedStringifyNumber(value)) { \
  230. json.WriteKey(key).Write(ToString(value)); \
  231. } else { \
  232. json.WriteKey(key).Write(value); \
  233. } \
  234. break; \
  235. }
  236. const Reflection* reflection = proto.GetReflection();
  237. bool shouldPrintField = inProtoMap || reflection->HasField(proto, &field);
  238. if (!shouldPrintField && GetConfig().MissingSingleKeyMode == TProto2JsonConfig::MissingKeyExplicitDefaultThrowRequired) {
  239. if (field.has_default_value()) {
  240. shouldPrintField = true;
  241. } else if (field.is_required()) {
  242. ythrow yexception() << "Empty required protobuf field: "
  243. << field.full_name() << ".";
  244. }
  245. }
  246. shouldPrintField = shouldPrintField ||
  247. (GetConfig().MissingSingleKeyMode == TProto2JsonConfig::MissingKeyDefault && !field.containing_oneof());
  248. if (shouldPrintField) {
  249. switch (field.cpp_type()) {
  250. INT_FIELD_TO_JSON(CPPTYPE_INT32, GetInt32);
  251. INT_FIELD_TO_JSON(CPPTYPE_INT64, GetInt64);
  252. INT_FIELD_TO_JSON(CPPTYPE_UINT32, GetUInt32);
  253. INT_FIELD_TO_JSON(CPPTYPE_UINT64, GetUInt64);
  254. FIELD_TO_JSON(CPPTYPE_DOUBLE, GetDouble);
  255. FIELD_TO_JSON(CPPTYPE_FLOAT, GetFloat);
  256. FIELD_TO_JSON(CPPTYPE_BOOL, GetBool);
  257. case FieldDescriptor::CPPTYPE_MESSAGE: {
  258. json.WriteKey(key);
  259. if (Config.ConvertTimeAsString && HandleTimeConversion(reflection->GetMessage(proto, &field), json)) {
  260. break;
  261. }
  262. const Message& msg = reflection->GetMessage(proto, &field);
  263. if (Config.ConvertAny && TryPrintAny(msg, json)) {
  264. break;
  265. }
  266. Print(msg, json);
  267. break;
  268. }
  269. case FieldDescriptor::CPPTYPE_ENUM: {
  270. PrintEnumValue<true>(key, reflection->GetEnum(proto, &field), json);
  271. break;
  272. }
  273. case FieldDescriptor::CPPTYPE_STRING: {
  274. TString scratch;
  275. const TString& value = reflection->GetStringReference(proto, &field, &scratch);
  276. PrintStringValue<true>(field, key, value, json);
  277. break;
  278. }
  279. default:
  280. ythrow yexception() << "Unknown protobuf field type: "
  281. << static_cast<int>(field.cpp_type()) << ".";
  282. }
  283. } else {
  284. switch (GetConfig().MissingSingleKeyMode) {
  285. case TProto2JsonConfig::MissingKeyNull: {
  286. json.WriteKey(key).WriteNull();
  287. break;
  288. }
  289. case TProto2JsonConfig::MissingKeySkip:
  290. case TProto2JsonConfig::MissingKeyExplicitDefaultThrowRequired:
  291. default:
  292. break;
  293. }
  294. }
  295. #undef FIELD_TO_JSON
  296. }
  297. void TProto2JsonPrinter::PrintRepeatedField(const Message& proto,
  298. const FieldDescriptor& field,
  299. IJsonOutput& json,
  300. TStringBuf key) {
  301. Y_ABORT_UNLESS(field.is_repeated(), "field isn't repeated.");
  302. const bool isMap = field.is_map() && GetConfig().MapAsObject;
  303. if (!key) {
  304. key = MakeKey(field);
  305. }
  306. #define REPEATED_FIELD_TO_JSON(EProtoCppType, ProtoGet) \
  307. case FieldDescriptor::EProtoCppType: { \
  308. for (size_t i = 0, endI = reflection->FieldSize(proto, &field); i < endI; ++i) \
  309. json.Write(reflection->ProtoGet(proto, &field, i)); \
  310. break; \
  311. }
  312. #define REPEATED_INT_FIELD_TO_JSON(EProtoCppType, ProtoGet) \
  313. case FieldDescriptor::EProtoCppType: { \
  314. for (size_t i = 0, endI = reflection->FieldSize(proto, &field); i < endI; ++i) { \
  315. const auto value = reflection->ProtoGet(proto, &field, i); \
  316. if (NeedStringifyRepeatedNumber(value)) { \
  317. json.Write(ToString(value)); \
  318. } else { \
  319. json.Write(value); \
  320. } \
  321. } \
  322. break; \
  323. }
  324. const Reflection* reflection = proto.GetReflection();
  325. if (reflection->FieldSize(proto, &field) > 0) {
  326. json.WriteKey(key);
  327. if (isMap) {
  328. json.BeginObject();
  329. } else {
  330. json.BeginList();
  331. }
  332. switch (field.cpp_type()) {
  333. REPEATED_INT_FIELD_TO_JSON(CPPTYPE_INT32, GetRepeatedInt32);
  334. REPEATED_INT_FIELD_TO_JSON(CPPTYPE_INT64, GetRepeatedInt64);
  335. REPEATED_INT_FIELD_TO_JSON(CPPTYPE_UINT32, GetRepeatedUInt32);
  336. REPEATED_INT_FIELD_TO_JSON(CPPTYPE_UINT64, GetRepeatedUInt64);
  337. REPEATED_FIELD_TO_JSON(CPPTYPE_DOUBLE, GetRepeatedDouble);
  338. REPEATED_FIELD_TO_JSON(CPPTYPE_FLOAT, GetRepeatedFloat);
  339. REPEATED_FIELD_TO_JSON(CPPTYPE_BOOL, GetRepeatedBool);
  340. case FieldDescriptor::CPPTYPE_MESSAGE: {
  341. if (isMap) {
  342. if (GetConfig().SortMapKeys) {
  343. TMap<TString, size_t> keyToIndex;
  344. for (size_t i = 0, endI = reflection->FieldSize(proto, &field); i < endI; ++i) {
  345. const Message& fieldMessage = reflection->GetRepeatedMessage(proto, &field, i);
  346. const FieldDescriptor* keyField = fieldMessage.GetDescriptor()->map_key();
  347. Y_ABORT_UNLESS(keyField, "Map entry key field not found.");
  348. TString key = MakeKey(fieldMessage, *keyField);
  349. keyToIndex[key] = i;
  350. }
  351. for (const auto& [_, i] : keyToIndex) {
  352. PrintKeyValue(reflection->GetRepeatedMessage(proto, &field, i), json);
  353. }
  354. } else {
  355. for (size_t i = 0, endI = reflection->FieldSize(proto, &field); i < endI; ++i) {
  356. PrintKeyValue(reflection->GetRepeatedMessage(proto, &field, i), json);
  357. }
  358. }
  359. } else {
  360. for (size_t i = 0, endI = reflection->FieldSize(proto, &field); i < endI; ++i) {
  361. Print(reflection->GetRepeatedMessage(proto, &field, i), json);
  362. }
  363. }
  364. break;
  365. }
  366. case FieldDescriptor::CPPTYPE_ENUM: {
  367. for (int i = 0, endI = reflection->FieldSize(proto, &field); i < endI; ++i)
  368. PrintEnumValue<false>(TStringBuf(), reflection->GetRepeatedEnum(proto, &field, i), json);
  369. break;
  370. }
  371. case FieldDescriptor::CPPTYPE_STRING: {
  372. TString scratch;
  373. for (int i = 0, endI = reflection->FieldSize(proto, &field); i < endI; ++i) {
  374. const TString& value =
  375. reflection->GetRepeatedStringReference(proto, &field, i, &scratch);
  376. PrintStringValue<false>(field, TStringBuf(), value, json);
  377. }
  378. break;
  379. }
  380. default:
  381. ythrow yexception() << "Unknown protobuf field type: "
  382. << static_cast<int>(field.cpp_type()) << ".";
  383. }
  384. if (isMap) {
  385. json.EndObject();
  386. } else {
  387. json.EndList();
  388. }
  389. } else {
  390. switch (GetConfig().MissingRepeatedKeyMode) {
  391. case TProto2JsonConfig::MissingKeyNull: {
  392. json.WriteKey(key).WriteNull();
  393. break;
  394. }
  395. case TProto2JsonConfig::MissingKeyDefault: {
  396. json.WriteKey(key);
  397. if (isMap) {
  398. json.BeginObject().EndObject();
  399. } else {
  400. json.BeginList().EndList();
  401. }
  402. break;
  403. }
  404. case TProto2JsonConfig::MissingKeySkip:
  405. case TProto2JsonConfig::MissingKeyExplicitDefaultThrowRequired:
  406. default:
  407. break;
  408. }
  409. }
  410. #undef REPEATED_FIELD_TO_JSON
  411. }
  412. void TProto2JsonPrinter::PrintKeyValue(const NProtoBuf::Message& proto,
  413. IJsonOutput& json) {
  414. const FieldDescriptor* keyField = proto.GetDescriptor()->map_key();
  415. Y_ABORT_UNLESS(keyField, "Map entry key field not found.");
  416. TString key = MakeKey(proto, *keyField);
  417. const FieldDescriptor* valueField = proto.GetDescriptor()->map_value();
  418. Y_ABORT_UNLESS(valueField, "Map entry value field not found.");
  419. PrintSingleField(proto, *valueField, json, key, true);
  420. }
  421. TString TProto2JsonPrinter::MakeKey(const NProtoBuf::Message& proto,
  422. const NProtoBuf::FieldDescriptor& field) {
  423. const Reflection* reflection = proto.GetReflection();
  424. TString result;
  425. switch (field.cpp_type()) {
  426. case FieldDescriptor::CPPTYPE_INT32:
  427. result = ToString(reflection->GetInt32(proto, &field));
  428. break;
  429. case FieldDescriptor::CPPTYPE_INT64:
  430. result = ToString(reflection->GetInt64(proto, &field));
  431. break;
  432. case FieldDescriptor::CPPTYPE_UINT32:
  433. result = ToString(reflection->GetUInt32(proto, &field));
  434. break;
  435. case FieldDescriptor::CPPTYPE_UINT64:
  436. result = ToString(reflection->GetUInt64(proto, &field));
  437. break;
  438. case FieldDescriptor::CPPTYPE_DOUBLE:
  439. result = ToString(reflection->GetDouble(proto, &field));
  440. break;
  441. case FieldDescriptor::CPPTYPE_FLOAT:
  442. result = ToString(reflection->GetFloat(proto, &field));
  443. break;
  444. case FieldDescriptor::CPPTYPE_BOOL:
  445. result = ToString(reflection->GetBool(proto, &field));
  446. break;
  447. case FieldDescriptor::CPPTYPE_ENUM: {
  448. const EnumValueDescriptor* value = reflection->GetEnum(proto, &field);
  449. switch (GetConfig().EnumMode) {
  450. case TProto2JsonConfig::EnumNumber:
  451. result = ToString(value->number());
  452. break;
  453. case TProto2JsonConfig::EnumName:
  454. result = value->name();
  455. break;
  456. case TProto2JsonConfig::EnumFullName:
  457. result = value->full_name();
  458. break;
  459. case TProto2JsonConfig::EnumNameLowerCase:
  460. result = value->name();
  461. result.to_lower();
  462. break;
  463. case TProto2JsonConfig::EnumFullNameLowerCase:
  464. result = value->full_name();
  465. result.to_lower();
  466. break;
  467. default:
  468. ythrow yexception() << "Unsupported enum mode.";
  469. }
  470. break;
  471. }
  472. case FieldDescriptor::CPPTYPE_STRING:
  473. result = reflection->GetString(proto, &field);
  474. break;
  475. default:
  476. ythrow yexception() << "Unsupported key type.";
  477. }
  478. return result;
  479. }
  480. void TProto2JsonPrinter::PrintField(const Message& proto,
  481. const FieldDescriptor& field,
  482. IJsonOutput& json,
  483. const TStringBuf key) {
  484. if (field.is_repeated())
  485. PrintRepeatedField(proto, field, json, key);
  486. else
  487. PrintSingleField(proto, field, json, key);
  488. }
  489. void TProto2JsonPrinter::PrintFields(const Message& proto, IJsonOutput& json) {
  490. const Descriptor* descriptor = proto.GetDescriptor();
  491. Y_ASSERT(descriptor);
  492. // Iterate over all non-extension fields
  493. for (int f = 0, endF = descriptor->field_count(); f < endF; ++f) {
  494. const FieldDescriptor* field = descriptor->field(f);
  495. Y_ASSERT(field);
  496. PrintField(proto, *field, json);
  497. }
  498. // Check extensions via ListFields
  499. std::vector<const FieldDescriptor*> fields;
  500. auto* ref = proto.GetReflection();
  501. ref->ListFields(proto, &fields);
  502. for (const FieldDescriptor* field : fields) {
  503. Y_ASSERT(field);
  504. if (field->is_extension()) {
  505. switch (GetConfig().ExtensionFieldNameMode) {
  506. case TProto2JsonConfig::ExtFldNameFull:
  507. PrintField(proto, *field, json, field->full_name());
  508. break;
  509. case TProto2JsonConfig::ExtFldNameShort:
  510. PrintField(proto, *field, json);
  511. break;
  512. }
  513. }
  514. }
  515. }
  516. void TProto2JsonPrinter::Print(const Message& proto, IJsonOutput& json, bool closeMap) {
  517. json.BeginObject();
  518. PrintFields(proto, json);
  519. if (closeMap) {
  520. json.EndObject();
  521. }
  522. }
  523. template <class T, class U>
  524. std::enable_if_t<!std::is_unsigned<T>::value, bool> ValueInRange(T value, U range) {
  525. return value > -range && value < range;
  526. }
  527. template <class T, class U>
  528. std::enable_if_t<std::is_unsigned<T>::value, bool> ValueInRange(T value, U range) {
  529. return value < (std::make_unsigned_t<U>)(range);
  530. }
  531. template <class T>
  532. bool TProto2JsonPrinter::NeedStringifyNumber(T value) const {
  533. constexpr long SAFE_INTEGER_RANGE_FLOAT = 1L << 24;
  534. constexpr long long SAFE_INTEGER_RANGE_DOUBLE = 1LL << 53;
  535. switch (GetConfig().StringifyNumbers) {
  536. case TProto2JsonConfig::StringifyLongNumbersNever:
  537. return false;
  538. case TProto2JsonConfig::StringifyLongNumbersForFloat:
  539. return !ValueInRange(value, SAFE_INTEGER_RANGE_FLOAT);
  540. case TProto2JsonConfig::StringifyLongNumbersForDouble:
  541. return !ValueInRange(value, SAFE_INTEGER_RANGE_DOUBLE);
  542. case TProto2JsonConfig::StringifyInt64Always:
  543. return std::is_same_v<T, i64> || std::is_same_v<T, ui64>;
  544. }
  545. return false;
  546. }
  547. template <class T>
  548. bool TProto2JsonPrinter::NeedStringifyRepeatedNumber(T value) const {
  549. constexpr long SAFE_INTEGER_RANGE_FLOAT = 1L << 24;
  550. constexpr long long SAFE_INTEGER_RANGE_DOUBLE = 1LL << 53;
  551. switch (GetConfig().StringifyNumbersRepeated) {
  552. case TProto2JsonConfig::StringifyLongNumbersNever:
  553. return false;
  554. case TProto2JsonConfig::StringifyLongNumbersForFloat:
  555. return !ValueInRange(value, SAFE_INTEGER_RANGE_FLOAT);
  556. case TProto2JsonConfig::StringifyLongNumbersForDouble:
  557. return !ValueInRange(value, SAFE_INTEGER_RANGE_DOUBLE);
  558. case TProto2JsonConfig::StringifyInt64Always:
  559. return std::is_same_v<T, i64> || std::is_same_v<T, ui64>;
  560. }
  561. return false;
  562. }
  563. }