diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/protobuf/json/inline.h | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/protobuf/json/inline.h')
-rw-r--r-- | library/cpp/protobuf/json/inline.h | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/library/cpp/protobuf/json/inline.h b/library/cpp/protobuf/json/inline.h new file mode 100644 index 0000000000..e2d7bb6ef0 --- /dev/null +++ b/library/cpp/protobuf/json/inline.h @@ -0,0 +1,115 @@ +#pragma once + +// A printer from protobuf to json string, with ability to inline some string fields of given protobuf message +// into output as ready json without additional escaping. These fields should be marked using special field option. +// An example of usage: +// 1) Define a field option in your .proto to identify fields which should be inlined, e.g. +// +// import "google/protobuf/descriptor.proto"; +// extend google.protobuf.FieldOptions { +// optional bool this_is_json = 58253; // do not forget assign some more or less unique tag +// } +// +// 2) Mark some fields of your protobuf message with this option, e.g.: +// +// message TMyObject { +// optional string A = 1 [(this_is_json) = true]; +// } +// +// 3) In the C++ code you prepare somehow an object of TMyObject type +// +// TMyObject o; +// o.Set("{\"inner\":\"value\"}"); +// +// 4) And then serialize it to json string with inlining, e.g.: +// +// Cout << NProtobufJson::PrintInlined(o, MakeFieldOptionFunctor(this_is_json)) << Endl; +// +// 5) Alternatively you can specify a some more abstract functor for defining raw json fields +// +// which will print following json to stdout: +// {"A":{"inner":"value"}} +// instead of +// {"A":"{\"inner\":\"value\"}"} +// which would be printed with normal Proto2Json printer. +// +// See ut/inline_ut.cpp for additional examples of usage. + +#include "config.h" +#include "proto2json_printer.h" +#include "json_output_create.h" + +#include <library/cpp/protobuf/util/simple_reflection.h> + +#include <util/generic/maybe.h> +#include <util/generic/yexception.h> +#include <util/generic/utility.h> + +#include <functional> + +namespace NProtobufJson { + template <typename TBasePrinter = TProto2JsonPrinter> // TBasePrinter is assumed to be a TProto2JsonPrinter descendant + class TInliningPrinter: public TBasePrinter { + public: + using TFieldPredicate = std::function<bool(const NProtoBuf::Message&, + const NProtoBuf::FieldDescriptor*)>; + + template <typename... TArgs> + TInliningPrinter(TFieldPredicate isInlined, TArgs&&... args) + : TBasePrinter(std::forward<TArgs>(args)...) + , IsInlined(std::move(isInlined)) + { + } + + virtual void PrintField(const NProtoBuf::Message& proto, + const NProtoBuf::FieldDescriptor& field, + IJsonOutput& json, + TStringBuf key) override { + const NProtoBuf::TConstField f(proto, &field); + if (!key && IsInlined(proto, &field) && ShouldPrint(f)) { + key = this->MakeKey(field); + json.WriteKey(key); + if (!field.is_repeated()) { + json.WriteRawJson(f.Get<TString>()); + } else { + json.BeginList(); + for (size_t i = 0, sz = f.Size(); i < sz; ++i) + json.WriteRawJson(f.Get<TString>(i)); + json.EndList(); + } + + } else { + TBasePrinter::PrintField(proto, field, json, key); + } + } + + private: + bool ShouldPrint(const NProtoBuf::TConstField& f) const { + if (!f.IsString()) + ythrow yexception() << "TInliningPrinter: json field " + << f.Field()->name() << " should be a string"; + + if (f.HasValue()) + return true; + + // we may want write default value for given field in case of its absence + const auto& cfg = this->GetConfig(); + return (f.Field()->is_repeated() ? cfg.MissingRepeatedKeyMode : cfg.MissingSingleKeyMode) == TProto2JsonConfig::MissingKeyDefault; + } + + private: + TFieldPredicate IsInlined; + }; + + inline void PrintInlined(const NProtoBuf::Message& msg, TInliningPrinter<>::TFieldPredicate isInlined, IJsonOutput& output, const TProto2JsonConfig& config = TProto2JsonConfig()) { + TInliningPrinter<> printer(std::move(isInlined), config); + printer.Print(msg, output); + } + + inline TString PrintInlined(const NProtoBuf::Message& msg, TInliningPrinter<>::TFieldPredicate isInlined, const TProto2JsonConfig& config = TProto2JsonConfig()) { + TString ret; + PrintInlined(msg, std::move(isInlined), *CreateJsonMapOutput(ret, config), config); + return ret; + } + +} |