fluent.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  1. #pragma once
  2. ///
  3. /// @file yt/cpp/mapreduce/interface/fluent.h
  4. ///
  5. /// Adapters for working with @ref NYson::IYsonConsumer in a structured way, with compile-time syntax checks.
  6. ///
  7. /// The following documentation is copied verbatim from `yt/core/ytree/fluent.h`.
  8. ///
  9. /// WHAT IS THIS
  10. ///
  11. /// Fluent adapters encapsulate invocation of IYsonConsumer methods in a
  12. /// convenient structured manner. Key advantage of fluent-like code is that
  13. /// attempt of building syntactically incorrect YSON structure will result
  14. /// in a compile-time error.
  15. ///
  16. /// Each fluent object is associated with a context that defines possible YSON
  17. /// tokens that may appear next. For example, TFluentMap is a fluent object
  18. /// that corresponds to a location within YSON map right before a key-value
  19. /// pair or the end of the map.
  20. ///
  21. /// More precisely, each object that may be obtained by a sequence of fluent
  22. /// method calls has the full history of its enclosing YSON composite types in
  23. /// its single template argument hereinafter referred to as TParent. This allows
  24. /// us not to forget the original context after opening and closing the embedded
  25. /// composite structure.
  26. ///
  27. /// It is possible to invoke a separate YSON building procedure by calling
  28. /// one of convenience Do* methods. There are two possibilities here: it is
  29. /// possible to delegate invocation context either as a fluent object (like
  30. /// TFluentMap, TFluentList, TFluentAttributes or TFluentAny) or as a raw
  31. /// IYsonConsumer*. The latter is discouraged since it is impossible to check
  32. /// if a given side-built YSON structure fits current fluent context.
  33. /// For example it is possible to call Do() method inside YSON map passing
  34. /// consumer to a procedure that will treat context like it is in a list.
  35. /// Passing typed fluent builder saves you from such a misbehaviour.
  36. ///
  37. /// TFluentXxx corresponds to an internal class of TXxx
  38. /// without any history hidden in template argument. It allows you to
  39. /// write procedures of form:
  40. ///
  41. /// void BuildSomeAttributesInYson(TFluentMap fluent) { ... }
  42. ///
  43. /// without thinking about the exact way how this procedure is nested in other
  44. /// procedures.
  45. ///
  46. /// An important notation: we will refer to a function whose first argument
  47. /// is TFluentXxx as TFuncXxx.
  48. ///
  49. ///
  50. /// BRIEF LIST OF AVAILABLE METHODS
  51. ///
  52. /// Only the most popular methods are covered here. Refer to the code for the
  53. /// rest of them.
  54. ///
  55. /// TAny:
  56. /// * Value(T value) -> TParent, serialize `value` using underlying consumer.
  57. /// T should be such that free function Serialize(NYson::IYsonConsumer*, const T&) is
  58. /// defined;
  59. /// * BeginMap() -> TFluentMap, open map;
  60. /// * BeginList() -> TFluentList, open list;
  61. /// * BeginAttributes() -> TFluentAttributes, open attributes;
  62. ///
  63. /// * Do(TFuncAny func) -> TAny, delegate invocation to a separate procedure.
  64. /// * DoIf(bool condition, TFuncAny func) -> TAny, same as Do() but invoke
  65. /// `func` only if `condition` is true;
  66. /// * DoFor(TCollection collection, TFuncAny func) -> TAny, same as Do()
  67. /// but iterate over `collection` and pass each of its elements as a second
  68. /// argument to `func`. Instead of passing a collection you may it is possible
  69. /// to pass two iterators as an argument;
  70. ///
  71. /// * DoMap(TFuncMap func) -> TAny, open a map, delegate invocation to a separate
  72. /// procedure and close map;
  73. /// * DoMapFor(TCollection collection, TFuncMap func) -> TAny, open a map, iterate
  74. /// over `collection` and pass each of its elements as a second argument to `func`
  75. /// and close map;
  76. /// * DoList(TFuncList func) -> TAny, same as DoMap();
  77. /// * DoListFor(TCollection collection, TFuncList func) -> TAny; same as DoMapFor().
  78. ///
  79. ///
  80. /// TFluentMap:
  81. /// * Item(TStringBuf key) -> TAny, open an element keyed with `key`;
  82. /// * EndMap() -> TParent, close map;
  83. /// * Do(TFuncMap func) -> TFluentMap, same as Do() for TAny;
  84. /// * DoIf(bool condition, TFuncMap func) -> TFluentMap, same as DoIf() for TAny;
  85. /// * DoFor(TCollection collection, TFuncMap func) -> TFluentMap, same as DoFor() for TAny.
  86. ///
  87. ///
  88. /// TFluentList:
  89. /// * Item() -> TAny, open an new list element;
  90. /// * EndList() -> TParent, close list;
  91. /// * Do(TFuncList func) -> TFluentList, same as Do() for TAny;
  92. /// * DoIf(bool condition, TFuncList func) -> TFluentList, same as DoIf() for TAny;
  93. /// * DoFor(TCollection collection, TListMap func) -> TFluentList, same as DoFor() for TAny.
  94. ///
  95. ///
  96. /// TFluentAttributes:
  97. /// * Item(TStringBuf key) -> TAny, open an element keyed with `key`.
  98. /// * EndAttributes() -> TParentWithoutAttributes, close attributes. Note that
  99. /// this method leads to a context that is forces not to have attributes,
  100. /// preventing us from putting attributes twice before an object.
  101. /// * Do(TFuncAttributes func) -> TFluentAttributes, same as Do() for TAny;
  102. /// * DoIf(bool condition, TFuncAttributes func) -> TFluentAttributes, same as DoIf()
  103. /// for TAny;
  104. /// * DoFor(TCollection collection, TListAttributes func) -> TFluentAttributes, same as DoFor()
  105. /// for TAny.
  106. ///
  107. #include "common.h"
  108. #include "serialize.h"
  109. #include <library/cpp/yson/node/serialize.h>
  110. #include <library/cpp/yson/node/node_builder.h>
  111. #include <library/cpp/yson/consumer.h>
  112. #include <library/cpp/yson/writer.h>
  113. #include <util/generic/noncopyable.h>
  114. #include <util/generic/ptr.h>
  115. #include <util/stream/str.h>
  116. namespace NYT {
  117. ////////////////////////////////////////////////////////////////////////////////
  118. template <class T>
  119. struct TFluentYsonUnwrapper
  120. {
  121. using TUnwrapped = T;
  122. static TUnwrapped Unwrap(T t)
  123. {
  124. return std::move(t);
  125. }
  126. };
  127. ////////////////////////////////////////////////////////////////////////////////
  128. struct TFluentYsonVoid
  129. { };
  130. template <>
  131. struct TFluentYsonUnwrapper<TFluentYsonVoid>
  132. {
  133. using TUnwrapped = void;
  134. static TUnwrapped Unwrap(TFluentYsonVoid)
  135. { }
  136. };
  137. ////////////////////////////////////////////////////////////////////////////////
  138. /// This class is actually a namespace for specific fluent adapter classes.
  139. class TFluentYsonBuilder
  140. : private TNonCopyable
  141. {
  142. private:
  143. template <class T>
  144. static void WriteValue(NYT::NYson::IYsonConsumer* consumer, const T& value)
  145. {
  146. Serialize(value, consumer);
  147. }
  148. public:
  149. class TFluentAny;
  150. template <class TParent> class TAny;
  151. template <class TParent> class TToAttributes;
  152. template <class TParent> class TAttributes;
  153. template <class TParent> class TListType;
  154. template <class TParent> class TMapType;
  155. /// Base class for all fluent adapters.
  156. template <class TParent>
  157. class TFluentBase
  158. {
  159. public:
  160. /// Implicit conversion to yson consumer
  161. operator NYT::NYson::IYsonConsumer* () const
  162. {
  163. return Consumer;
  164. }
  165. protected:
  166. /// @cond Doxygen_Suppress
  167. NYT::NYson::IYsonConsumer* Consumer;
  168. TParent Parent;
  169. TFluentBase(NYT::NYson::IYsonConsumer* consumer, TParent parent)
  170. : Consumer(consumer)
  171. , Parent(std::move(parent))
  172. { }
  173. using TUnwrappedParent = typename TFluentYsonUnwrapper<TParent>::TUnwrapped;
  174. TUnwrappedParent GetUnwrappedParent()
  175. {
  176. return TFluentYsonUnwrapper<TParent>::Unwrap(std::move(Parent));
  177. }
  178. /// @endcond Doxygen_Suppress
  179. };
  180. /// Base class for fluent adapters for fragment of list, map or attributes.
  181. template <template <class TParent> class TThis, class TParent>
  182. class TFluentFragmentBase
  183. : public TFluentBase<TParent>
  184. {
  185. public:
  186. using TDeepThis = TThis<TParent>;
  187. using TShallowThis = TThis<TFluentYsonVoid>;
  188. using TUnwrappedParent = typename TFluentYsonUnwrapper<TParent>::TUnwrapped;
  189. explicit TFluentFragmentBase(NYT::NYson::IYsonConsumer* consumer, TParent parent = TParent())
  190. : TFluentBase<TParent>(consumer, std::move(parent))
  191. { }
  192. /// Delegate invocation to a separate procedure.
  193. template <class TFunc>
  194. TDeepThis& Do(const TFunc& func)
  195. {
  196. func(TShallowThis(this->Consumer));
  197. return *static_cast<TDeepThis*>(this);
  198. }
  199. /// Conditionally delegate invocation to a separate procedure.
  200. template <class TFunc>
  201. TDeepThis& DoIf(bool condition, const TFunc& func)
  202. {
  203. if (condition) {
  204. func(TShallowThis(this->Consumer));
  205. }
  206. return *static_cast<TDeepThis*>(this);
  207. }
  208. /// Calls `func(*this, element)` for each `element` in range `[begin, end)`.
  209. template <class TFunc, class TIterator>
  210. TDeepThis& DoFor(const TIterator& begin, const TIterator& end, const TFunc& func)
  211. {
  212. for (auto current = begin; current != end; ++current) {
  213. func(TShallowThis(this->Consumer), current);
  214. }
  215. return *static_cast<TDeepThis*>(this);
  216. }
  217. /// Calls `func(*this, element)` for each `element` in `collection`.
  218. template <class TFunc, class TCollection>
  219. TDeepThis& DoFor(const TCollection& collection, const TFunc& func)
  220. {
  221. for (const auto& item : collection) {
  222. func(TShallowThis(this->Consumer), item);
  223. }
  224. return *static_cast<TDeepThis*>(this);
  225. }
  226. };
  227. /// Fluent adapter of a value without attributes.
  228. template <class TParent>
  229. class TAnyWithoutAttributes
  230. : public TFluentBase<TParent>
  231. {
  232. public:
  233. using TUnwrappedParent = typename TFluentYsonUnwrapper<TParent>::TUnwrapped;
  234. TAnyWithoutAttributes(NYT::NYson::IYsonConsumer* consumer, TParent parent)
  235. : TFluentBase<TParent>(consumer, std::move(parent))
  236. { }
  237. /// Pass `value` to underlying consumer.
  238. template <class T>
  239. TUnwrappedParent Value(const T& value)
  240. {
  241. WriteValue(this->Consumer, value);
  242. return this->GetUnwrappedParent();
  243. }
  244. /// Call `OnEntity()` of underlying consumer.
  245. TUnwrappedParent Entity()
  246. {
  247. this->Consumer->OnEntity();
  248. return this->GetUnwrappedParent();
  249. }
  250. /// Serialize `collection` to underlying consumer as a list.
  251. template <class TCollection>
  252. TUnwrappedParent List(const TCollection& collection)
  253. {
  254. this->Consumer->OnBeginList();
  255. for (const auto& item : collection) {
  256. this->Consumer->OnListItem();
  257. WriteValue(this->Consumer, item);
  258. }
  259. this->Consumer->OnEndList();
  260. return this->GetUnwrappedParent();
  261. }
  262. /// Serialize maximum `maxSize` elements of `collection` to underlying consumer as a list.
  263. template <class TCollection>
  264. TUnwrappedParent ListLimited(const TCollection& collection, size_t maxSize)
  265. {
  266. this->Consumer->OnBeginAttributes();
  267. this->Consumer->OnKeyedItem("count");
  268. this->Consumer->OnInt64Scalar(collection.size());
  269. this->Consumer->OnEndAttributes();
  270. this->Consumer->OnBeginList();
  271. size_t printedSize = 0;
  272. for (const auto& item : collection) {
  273. if (printedSize >= maxSize)
  274. break;
  275. this->Consumer->OnListItem();
  276. WriteValue(this->Consumer, item);
  277. ++printedSize;
  278. }
  279. this->Consumer->OnEndList();
  280. return this->GetUnwrappedParent();
  281. }
  282. /// Open a list.
  283. TListType<TParent> BeginList()
  284. {
  285. this->Consumer->OnBeginList();
  286. return TListType<TParent>(this->Consumer, this->Parent);
  287. }
  288. /// Open a list, delegate invocation to `func`, then close the list.
  289. template <class TFunc>
  290. TUnwrappedParent DoList(const TFunc& func)
  291. {
  292. this->Consumer->OnBeginList();
  293. func(TListType<TFluentYsonVoid>(this->Consumer));
  294. this->Consumer->OnEndList();
  295. return this->GetUnwrappedParent();
  296. }
  297. /// Open a list, call `func(*this, element)` for each `element` of range, then close the list.
  298. template <class TFunc, class TIterator>
  299. TUnwrappedParent DoListFor(const TIterator& begin, const TIterator& end, const TFunc& func)
  300. {
  301. this->Consumer->OnBeginList();
  302. for (auto current = begin; current != end; ++current) {
  303. func(TListType<TFluentYsonVoid>(this->Consumer), current);
  304. }
  305. this->Consumer->OnEndList();
  306. return this->GetUnwrappedParent();
  307. }
  308. /// Open a list, call `func(*this, element)` for each `element` of `collection`, then close the list.
  309. template <class TFunc, class TCollection>
  310. TUnwrappedParent DoListFor(const TCollection& collection, const TFunc& func)
  311. {
  312. this->Consumer->OnBeginList();
  313. for (const auto& item : collection) {
  314. func(TListType<TFluentYsonVoid>(this->Consumer), item);
  315. }
  316. this->Consumer->OnEndList();
  317. return this->GetUnwrappedParent();
  318. }
  319. /// Open a map.
  320. TMapType<TParent> BeginMap()
  321. {
  322. this->Consumer->OnBeginMap();
  323. return TMapType<TParent>(this->Consumer, this->Parent);
  324. }
  325. /// Open a map, delegate invocation to `func`, then close the map.
  326. template <class TFunc>
  327. TUnwrappedParent DoMap(const TFunc& func)
  328. {
  329. this->Consumer->OnBeginMap();
  330. func(TMapType<TFluentYsonVoid>(this->Consumer));
  331. this->Consumer->OnEndMap();
  332. return this->GetUnwrappedParent();
  333. }
  334. /// Open a map, call `func(*this, element)` for each `element` of range, then close the map.
  335. template <class TFunc, class TIterator>
  336. TUnwrappedParent DoMapFor(const TIterator& begin, const TIterator& end, const TFunc& func)
  337. {
  338. this->Consumer->OnBeginMap();
  339. for (auto current = begin; current != end; ++current) {
  340. func(TMapType<TFluentYsonVoid>(this->Consumer), current);
  341. }
  342. this->Consumer->OnEndMap();
  343. return this->GetUnwrappedParent();
  344. }
  345. /// Open a map, call `func(*this, element)` for each `element` of `collection`, then close the map.
  346. template <class TFunc, class TCollection>
  347. TUnwrappedParent DoMapFor(const TCollection& collection, const TFunc& func)
  348. {
  349. this->Consumer->OnBeginMap();
  350. for (const auto& item : collection) {
  351. func(TMapType<TFluentYsonVoid>(this->Consumer), item);
  352. }
  353. this->Consumer->OnEndMap();
  354. return this->GetUnwrappedParent();
  355. }
  356. };
  357. /// Fluent adapter of any value.
  358. template <class TParent>
  359. class TAny
  360. : public TAnyWithoutAttributes<TParent>
  361. {
  362. public:
  363. using TBase = TAnyWithoutAttributes<TParent>;
  364. explicit TAny(NYT::NYson::IYsonConsumer* consumer, TParent parent)
  365. : TBase(consumer, std::move(parent))
  366. { }
  367. /// Open attributes.
  368. TAttributes<TBase> BeginAttributes()
  369. {
  370. this->Consumer->OnBeginAttributes();
  371. return TAttributes<TBase>(
  372. this->Consumer,
  373. TBase(this->Consumer, this->Parent));
  374. }
  375. };
  376. /// Fluent adapter of attributes fragment (the inside part of attributes).
  377. template <class TParent = TFluentYsonVoid>
  378. class TAttributes
  379. : public TFluentFragmentBase<TAttributes, TParent>
  380. {
  381. public:
  382. using TThis = TAttributes<TParent>;
  383. using TUnwrappedParent = typename TFluentYsonUnwrapper<TParent>::TUnwrapped;
  384. explicit TAttributes(NYT::NYson::IYsonConsumer* consumer, TParent parent = TParent())
  385. : TFluentFragmentBase<TFluentYsonBuilder::TAttributes, TParent>(consumer, std::move(parent))
  386. { }
  387. /// Pass attribute key to underlying consumer.
  388. TAny<TThis> Item(const TStringBuf& key)
  389. {
  390. this->Consumer->OnKeyedItem(key);
  391. return TAny<TThis>(this->Consumer, *this);
  392. }
  393. /// Pass attribute key to underlying consumer.
  394. template <size_t Size>
  395. TAny<TThis> Item(const char (&key)[Size])
  396. {
  397. return Item(TStringBuf(key, Size - 1));
  398. }
  399. //TODO: from TNode
  400. /// Close the attributes.
  401. TUnwrappedParent EndAttributes()
  402. {
  403. this->Consumer->OnEndAttributes();
  404. return this->GetUnwrappedParent();
  405. }
  406. };
  407. /// Fluent adapter of list fragment (the inside part of a list).
  408. template <class TParent = TFluentYsonVoid>
  409. class TListType
  410. : public TFluentFragmentBase<TListType, TParent>
  411. {
  412. public:
  413. using TThis = TListType<TParent>;
  414. using TUnwrappedParent = typename TFluentYsonUnwrapper<TParent>::TUnwrapped;
  415. explicit TListType(NYT::NYson::IYsonConsumer* consumer, TParent parent = TParent())
  416. : TFluentFragmentBase<TFluentYsonBuilder::TListType, TParent>(consumer, std::move(parent))
  417. { }
  418. /// Call `OnListItem()` of underlying consumer.
  419. TAny<TThis> Item()
  420. {
  421. this->Consumer->OnListItem();
  422. return TAny<TThis>(this->Consumer, *this);
  423. }
  424. // TODO: from TNode
  425. /// Close the list.
  426. TUnwrappedParent EndList()
  427. {
  428. this->Consumer->OnEndList();
  429. return this->GetUnwrappedParent();
  430. }
  431. };
  432. /// Fluent adapter of map fragment (the inside part of a map).
  433. template <class TParent = TFluentYsonVoid>
  434. class TMapType
  435. : public TFluentFragmentBase<TMapType, TParent>
  436. {
  437. public:
  438. using TThis = TMapType<TParent>;
  439. using TUnwrappedParent = typename TFluentYsonUnwrapper<TParent>::TUnwrapped;
  440. explicit TMapType(NYT::NYson::IYsonConsumer* consumer, TParent parent = TParent())
  441. : TFluentFragmentBase<TFluentYsonBuilder::TMapType, TParent>(consumer, std::move(parent))
  442. { }
  443. /// Pass map key to underlying consumer.
  444. template <size_t Size>
  445. TAny<TThis> Item(const char (&key)[Size])
  446. {
  447. return Item(TStringBuf(key, Size - 1));
  448. }
  449. /// Pass map key to underlying consumer.
  450. TAny<TThis> Item(const TStringBuf& key)
  451. {
  452. this->Consumer->OnKeyedItem(key);
  453. return TAny<TThis>(this->Consumer, *this);
  454. }
  455. // TODO: from TNode
  456. /// Close the map.
  457. TUnwrappedParent EndMap()
  458. {
  459. this->Consumer->OnEndMap();
  460. return this->GetUnwrappedParent();
  461. }
  462. };
  463. };
  464. ////////////////////////////////////////////////////////////////////////////////
  465. /// Builder representing any value.
  466. using TFluentAny = TFluentYsonBuilder::TAny<TFluentYsonVoid>;
  467. /// Builder representing the inside of a list (list fragment).
  468. using TFluentList = TFluentYsonBuilder::TListType<TFluentYsonVoid>;
  469. /// Builder representing the inside of a map (map fragment).
  470. using TFluentMap = TFluentYsonBuilder::TMapType<TFluentYsonVoid>;
  471. /// Builder representing the inside of attributes.
  472. using TFluentAttributes = TFluentYsonBuilder::TAttributes<TFluentYsonVoid>;
  473. ////////////////////////////////////////////////////////////////////////////////
  474. /// Create a fluent adapter to invoke methods of `consumer`.
  475. static inline TFluentAny BuildYsonFluently(NYT::NYson::IYsonConsumer* consumer)
  476. {
  477. return TFluentAny(consumer, TFluentYsonVoid());
  478. }
  479. /// Create a fluent adapter to invoke methods of `consumer` describing the contents of a list.
  480. static inline TFluentList BuildYsonListFluently(NYT::NYson::IYsonConsumer* consumer)
  481. {
  482. return TFluentList(consumer);
  483. }
  484. /// Create a fluent adapter to invoke methods of `consumer` describing the contents of a map.
  485. static inline TFluentMap BuildYsonMapFluently(NYT::NYson::IYsonConsumer* consumer)
  486. {
  487. return TFluentMap(consumer);
  488. }
  489. ////////////////////////////////////////////////////////////////////////////////
  490. class TFluentYsonWriterState
  491. : public TThrRefBase
  492. {
  493. public:
  494. using TValue = TString;
  495. explicit TFluentYsonWriterState(::NYson::EYsonFormat format)
  496. : Writer(&Output, format)
  497. { }
  498. TString GetValue()
  499. {
  500. return Output.Str();
  501. }
  502. NYT::NYson::IYsonConsumer* GetConsumer()
  503. {
  504. return &Writer;
  505. }
  506. private:
  507. TStringStream Output;
  508. ::NYson::TYsonWriter Writer;
  509. };
  510. ////////////////////////////////////////////////////////////////////////////////
  511. class TFluentYsonBuilderState
  512. : public TThrRefBase
  513. {
  514. public:
  515. using TValue = TNode;
  516. explicit TFluentYsonBuilderState()
  517. : Builder(&Node)
  518. { }
  519. TNode GetValue()
  520. {
  521. return std::move(Node);
  522. }
  523. NYT::NYson::IYsonConsumer* GetConsumer()
  524. {
  525. return &Builder;
  526. }
  527. private:
  528. TNode Node;
  529. TNodeBuilder Builder;
  530. };
  531. ////////////////////////////////////////////////////////////////////////////////
  532. template <class TState>
  533. class TFluentYsonHolder
  534. {
  535. public:
  536. explicit TFluentYsonHolder(::TIntrusivePtr<TState> state)
  537. : State(state)
  538. { }
  539. ::TIntrusivePtr<TState> GetState() const
  540. {
  541. return State;
  542. }
  543. private:
  544. ::TIntrusivePtr<TState> State;
  545. };
  546. ////////////////////////////////////////////////////////////////////////////////
  547. template <class TState>
  548. struct TFluentYsonUnwrapper< TFluentYsonHolder<TState> >
  549. {
  550. using TUnwrapped = typename TState::TValue;
  551. static TUnwrapped Unwrap(const TFluentYsonHolder<TState>& holder)
  552. {
  553. return std::move(holder.GetState()->GetValue());
  554. }
  555. };
  556. ////////////////////////////////////////////////////////////////////////////////
  557. template <class TState>
  558. TFluentYsonBuilder::TAny<TFluentYsonHolder<TState>>
  559. BuildYsonFluentlyWithState(::TIntrusivePtr<TState> state)
  560. {
  561. return TFluentYsonBuilder::TAny<TFluentYsonHolder<TState>>(
  562. state->GetConsumer(),
  563. TFluentYsonHolder<TState>(state));
  564. }
  565. /// Create a fluent adapter returning a `TString` with corresponding YSON when construction is finished.
  566. inline TFluentYsonBuilder::TAny<TFluentYsonHolder<TFluentYsonWriterState>>
  567. BuildYsonStringFluently(::NYson::EYsonFormat format = ::NYson::EYsonFormat::Text)
  568. {
  569. ::TIntrusivePtr<TFluentYsonWriterState> state(new TFluentYsonWriterState(format));
  570. return BuildYsonFluentlyWithState(state);
  571. }
  572. /// Create a fluent adapter returning a @ref NYT::TNode when construction is finished.
  573. inline TFluentYsonBuilder::TAny<TFluentYsonHolder<TFluentYsonBuilderState>>
  574. BuildYsonNodeFluently()
  575. {
  576. ::TIntrusivePtr<TFluentYsonBuilderState> state(new TFluentYsonBuilderState);
  577. return BuildYsonFluentlyWithState(state);
  578. }
  579. ////////////////////////////////////////////////////////////////////////////////
  580. } // namespace NYT