aboutsummaryrefslogtreecommitdiffstats
path: root/yt/cpp/mapreduce/interface/fluent.h
diff options
context:
space:
mode:
authormax42 <max42@yandex-team.com>2023-07-29 00:02:16 +0300
committermax42 <max42@yandex-team.com>2023-07-29 00:02:16 +0300
commit73b89de71748a21e102d27b9f3ed1bf658766cb5 (patch)
tree188bbd2d622fa91cdcbb1b6d6d77fbc84a0646f5 /yt/cpp/mapreduce/interface/fluent.h
parent528e321bcc2a2b67b53aeba58c3bd88305a141ee (diff)
downloadydb-73b89de71748a21e102d27b9f3ed1bf658766cb5.tar.gz
YT-19210: expose YQL shared library for YT.
After this, a new target libyqlplugin.so appears. in open-source cmake build. Diff in open-source YDB repo looks like the following: https://paste.yandex-team.ru/f302bdb4-7ef2-4362-91c7-6ca45f329264
Diffstat (limited to 'yt/cpp/mapreduce/interface/fluent.h')
-rw-r--r--yt/cpp/mapreduce/interface/fluent.h678
1 files changed, 678 insertions, 0 deletions
diff --git a/yt/cpp/mapreduce/interface/fluent.h b/yt/cpp/mapreduce/interface/fluent.h
new file mode 100644
index 0000000000..8ca6e86336
--- /dev/null
+++ b/yt/cpp/mapreduce/interface/fluent.h
@@ -0,0 +1,678 @@
+#pragma once
+
+///
+/// @file yt/cpp/mapreduce/interface/fluent.h
+///
+/// Adapters for working with @ref NYson::IYsonConsumer in a structured way, with compile-time syntax checks.
+///
+/// The following documentation is copied verbatim from `yt/core/ytree/fluent.h`.
+///
+/// WHAT IS THIS
+///
+/// Fluent adapters encapsulate invocation of IYsonConsumer methods in a
+/// convenient structured manner. Key advantage of fluent-like code is that
+/// attempt of building syntactically incorrect YSON structure will result
+/// in a compile-time error.
+///
+/// Each fluent object is associated with a context that defines possible YSON
+/// tokens that may appear next. For example, TFluentMap is a fluent object
+/// that corresponds to a location within YSON map right before a key-value
+/// pair or the end of the map.
+///
+/// More precisely, each object that may be obtained by a sequence of fluent
+/// method calls has the full history of its enclosing YSON composite types in
+/// its single template argument hereinafter referred to as TParent. This allows
+/// us not to forget the original context after opening and closing the embedded
+/// composite structure.
+///
+/// It is possible to invoke a separate YSON building procedure by calling
+/// one of convenience Do* methods. There are two possibilities here: it is
+/// possible to delegate invocation context either as a fluent object (like
+/// TFluentMap, TFluentList, TFluentAttributes or TFluentAny) or as a raw
+/// IYsonConsumer*. The latter is discouraged since it is impossible to check
+/// if a given side-built YSON structure fits current fluent context.
+/// For example it is possible to call Do() method inside YSON map passing
+/// consumer to a procedure that will treat context like it is in a list.
+/// Passing typed fluent builder saves you from such a misbehaviour.
+///
+/// TFluentXxx corresponds to an internal class of TXxx
+/// without any history hidden in template argument. It allows you to
+/// write procedures of form:
+///
+/// void BuildSomeAttributesInYson(TFluentMap fluent) { ... }
+///
+/// without thinking about the exact way how this procedure is nested in other
+/// procedures.
+///
+/// An important notation: we will refer to a function whose first argument
+/// is TFluentXxx as TFuncXxx.
+///
+///
+/// BRIEF LIST OF AVAILABLE METHODS
+///
+/// Only the most popular methods are covered here. Refer to the code for the
+/// rest of them.
+///
+/// TAny:
+/// * Value(T value) -> TParent, serialize `value` using underlying consumer.
+/// T should be such that free function Serialize(NYson::IYsonConsumer*, const T&) is
+/// defined;
+/// * BeginMap() -> TFluentMap, open map;
+/// * BeginList() -> TFluentList, open list;
+/// * BeginAttributes() -> TFluentAttributes, open attributes;
+///
+/// * Do(TFuncAny func) -> TAny, delegate invocation to a separate procedure.
+/// * DoIf(bool condition, TFuncAny func) -> TAny, same as Do() but invoke
+/// `func` only if `condition` is true;
+/// * DoFor(TCollection collection, TFuncAny func) -> TAny, same as Do()
+/// but iterate over `collection` and pass each of its elements as a second
+/// argument to `func`. Instead of passing a collection you may it is possible
+/// to pass two iterators as an argument;
+///
+/// * DoMap(TFuncMap func) -> TAny, open a map, delegate invocation to a separate
+/// procedure and close map;
+/// * DoMapFor(TCollection collection, TFuncMap func) -> TAny, open a map, iterate
+/// over `collection` and pass each of its elements as a second argument to `func`
+/// and close map;
+/// * DoList(TFuncList func) -> TAny, same as DoMap();
+/// * DoListFor(TCollection collection, TFuncList func) -> TAny; same as DoMapFor().
+///
+///
+/// TFluentMap:
+/// * Item(TStringBuf key) -> TAny, open an element keyed with `key`;
+/// * EndMap() -> TParent, close map;
+/// * Do(TFuncMap func) -> TFluentMap, same as Do() for TAny;
+/// * DoIf(bool condition, TFuncMap func) -> TFluentMap, same as DoIf() for TAny;
+/// * DoFor(TCollection collection, TFuncMap func) -> TFluentMap, same as DoFor() for TAny.
+///
+///
+/// TFluentList:
+/// * Item() -> TAny, open an new list element;
+/// * EndList() -> TParent, close list;
+/// * Do(TFuncList func) -> TFluentList, same as Do() for TAny;
+/// * DoIf(bool condition, TFuncList func) -> TFluentList, same as DoIf() for TAny;
+/// * DoFor(TCollection collection, TListMap func) -> TFluentList, same as DoFor() for TAny.
+///
+///
+/// TFluentAttributes:
+/// * Item(TStringBuf key) -> TAny, open an element keyed with `key`.
+/// * EndAttributes() -> TParentWithoutAttributes, close attributes. Note that
+/// this method leads to a context that is forces not to have attributes,
+/// preventing us from putting attributes twice before an object.
+/// * Do(TFuncAttributes func) -> TFluentAttributes, same as Do() for TAny;
+/// * DoIf(bool condition, TFuncAttributes func) -> TFluentAttributes, same as DoIf()
+/// for TAny;
+/// * DoFor(TCollection collection, TListAttributes func) -> TFluentAttributes, same as DoFor()
+/// for TAny.
+///
+
+
+#include "common.h"
+#include "serialize.h"
+
+#include <library/cpp/yson/node/serialize.h>
+#include <library/cpp/yson/node/node_builder.h>
+
+#include <library/cpp/yson/consumer.h>
+#include <library/cpp/yson/writer.h>
+
+#include <util/generic/noncopyable.h>
+#include <util/generic/ptr.h>
+#include <util/stream/str.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+struct TFluentYsonUnwrapper
+{
+ using TUnwrapped = T;
+
+ static TUnwrapped Unwrap(T t)
+ {
+ return std::move(t);
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+struct TFluentYsonVoid
+{ };
+
+template <>
+struct TFluentYsonUnwrapper<TFluentYsonVoid>
+{
+ using TUnwrapped = void;
+
+ static TUnwrapped Unwrap(TFluentYsonVoid)
+ { }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+/// This class is actually a namespace for specific fluent adapter classes.
+class TFluentYsonBuilder
+ : private TNonCopyable
+{
+private:
+ template <class T>
+ static void WriteValue(NYT::NYson::IYsonConsumer* consumer, const T& value)
+ {
+ Serialize(value, consumer);
+ }
+
+public:
+ class TFluentAny;
+ template <class TParent> class TAny;
+ template <class TParent> class TToAttributes;
+ template <class TParent> class TAttributes;
+ template <class TParent> class TListType;
+ template <class TParent> class TMapType;
+
+ /// Base class for all fluent adapters.
+ template <class TParent>
+ class TFluentBase
+ {
+ public:
+ /// Implicit conversion to yson consumer
+ operator NYT::NYson::IYsonConsumer* () const
+ {
+ return Consumer;
+ }
+
+ protected:
+ /// @cond Doxygen_Suppress
+ NYT::NYson::IYsonConsumer* Consumer;
+ TParent Parent;
+
+ TFluentBase(NYT::NYson::IYsonConsumer* consumer, TParent parent)
+ : Consumer(consumer)
+ , Parent(std::move(parent))
+ { }
+
+ using TUnwrappedParent = typename TFluentYsonUnwrapper<TParent>::TUnwrapped;
+
+ TUnwrappedParent GetUnwrappedParent()
+ {
+ return TFluentYsonUnwrapper<TParent>::Unwrap(std::move(Parent));
+ }
+ /// @endcond Doxygen_Suppress
+ };
+
+ /// Base class for fluent adapters for fragment of list, map or attributes.
+ template <template <class TParent> class TThis, class TParent>
+ class TFluentFragmentBase
+ : public TFluentBase<TParent>
+ {
+ public:
+ using TDeepThis = TThis<TParent>;
+ using TShallowThis = TThis<TFluentYsonVoid>;
+ using TUnwrappedParent = typename TFluentYsonUnwrapper<TParent>::TUnwrapped;
+
+ explicit TFluentFragmentBase(NYT::NYson::IYsonConsumer* consumer, TParent parent = TParent())
+ : TFluentBase<TParent>(consumer, std::move(parent))
+ { }
+
+ /// Delegate invocation to a separate procedure.
+ template <class TFunc>
+ TDeepThis& Do(const TFunc& func)
+ {
+ func(TShallowThis(this->Consumer));
+ return *static_cast<TDeepThis*>(this);
+ }
+
+ /// Conditionally delegate invocation to a separate procedure.
+ template <class TFunc>
+ TDeepThis& DoIf(bool condition, const TFunc& func)
+ {
+ if (condition) {
+ func(TShallowThis(this->Consumer));
+ }
+ return *static_cast<TDeepThis*>(this);
+ }
+
+ /// Calls `func(*this, element)` for each `element` in range `[begin, end)`.
+ template <class TFunc, class TIterator>
+ TDeepThis& DoFor(const TIterator& begin, const TIterator& end, const TFunc& func)
+ {
+ for (auto current = begin; current != end; ++current) {
+ func(TShallowThis(this->Consumer), current);
+ }
+ return *static_cast<TDeepThis*>(this);
+ }
+
+ /// Calls `func(*this, element)` for each `element` in `collection`.
+ template <class TFunc, class TCollection>
+ TDeepThis& DoFor(const TCollection& collection, const TFunc& func)
+ {
+ for (const auto& item : collection) {
+ func(TShallowThis(this->Consumer), item);
+ }
+ return *static_cast<TDeepThis*>(this);
+ }
+
+ };
+
+ /// Fluent adapter of a value without attributes.
+ template <class TParent>
+ class TAnyWithoutAttributes
+ : public TFluentBase<TParent>
+ {
+ public:
+ using TUnwrappedParent = typename TFluentYsonUnwrapper<TParent>::TUnwrapped;
+
+ TAnyWithoutAttributes(NYT::NYson::IYsonConsumer* consumer, TParent parent)
+ : TFluentBase<TParent>(consumer, std::move(parent))
+ { }
+
+ /// Pass `value` to underlying consumer.
+ template <class T>
+ TUnwrappedParent Value(const T& value)
+ {
+ WriteValue(this->Consumer, value);
+ return this->GetUnwrappedParent();
+ }
+
+ /// Call `OnEntity()` of underlying consumer.
+ TUnwrappedParent Entity()
+ {
+ this->Consumer->OnEntity();
+ return this->GetUnwrappedParent();
+ }
+
+ /// Serialize `collection` to underlying consumer as a list.
+ template <class TCollection>
+ TUnwrappedParent List(const TCollection& collection)
+ {
+ this->Consumer->OnBeginList();
+ for (const auto& item : collection) {
+ this->Consumer->OnListItem();
+ WriteValue(this->Consumer, item);
+ }
+ this->Consumer->OnEndList();
+ return this->GetUnwrappedParent();
+ }
+
+ /// Serialize maximum `maxSize` elements of `collection` to underlying consumer as a list.
+ template <class TCollection>
+ TUnwrappedParent ListLimited(const TCollection& collection, size_t maxSize)
+ {
+ this->Consumer->OnBeginAttributes();
+ this->Consumer->OnKeyedItem("count");
+ this->Consumer->OnInt64Scalar(collection.size());
+ this->Consumer->OnEndAttributes();
+ this->Consumer->OnBeginList();
+ size_t printedSize = 0;
+ for (const auto& item : collection) {
+ if (printedSize >= maxSize)
+ break;
+ this->Consumer->OnListItem();
+ WriteValue(this->Consumer, item);
+ ++printedSize;
+ }
+ this->Consumer->OnEndList();
+ return this->GetUnwrappedParent();
+ }
+
+ /// Open a list.
+ TListType<TParent> BeginList()
+ {
+ this->Consumer->OnBeginList();
+ return TListType<TParent>(this->Consumer, this->Parent);
+ }
+
+ /// Open a list, delegate invocation to `func`, then close the list.
+ template <class TFunc>
+ TUnwrappedParent DoList(const TFunc& func)
+ {
+ this->Consumer->OnBeginList();
+ func(TListType<TFluentYsonVoid>(this->Consumer));
+ this->Consumer->OnEndList();
+ return this->GetUnwrappedParent();
+ }
+
+ /// Open a list, call `func(*this, element)` for each `element` of range, then close the list.
+ template <class TFunc, class TIterator>
+ TUnwrappedParent DoListFor(const TIterator& begin, const TIterator& end, const TFunc& func)
+ {
+ this->Consumer->OnBeginList();
+ for (auto current = begin; current != end; ++current) {
+ func(TListType<TFluentYsonVoid>(this->Consumer), current);
+ }
+ this->Consumer->OnEndList();
+ return this->GetUnwrappedParent();
+ }
+
+ /// Open a list, call `func(*this, element)` for each `element` of `collection`, then close the list.
+ template <class TFunc, class TCollection>
+ TUnwrappedParent DoListFor(const TCollection& collection, const TFunc& func)
+ {
+ this->Consumer->OnBeginList();
+ for (const auto& item : collection) {
+ func(TListType<TFluentYsonVoid>(this->Consumer), item);
+ }
+ this->Consumer->OnEndList();
+ return this->GetUnwrappedParent();
+ }
+
+ /// Open a map.
+ TMapType<TParent> BeginMap()
+ {
+ this->Consumer->OnBeginMap();
+ return TMapType<TParent>(this->Consumer, this->Parent);
+ }
+
+ /// Open a map, delegate invocation to `func`, then close the map.
+ template <class TFunc>
+ TUnwrappedParent DoMap(const TFunc& func)
+ {
+ this->Consumer->OnBeginMap();
+ func(TMapType<TFluentYsonVoid>(this->Consumer));
+ this->Consumer->OnEndMap();
+ return this->GetUnwrappedParent();
+ }
+
+ /// Open a map, call `func(*this, element)` for each `element` of range, then close the map.
+ template <class TFunc, class TIterator>
+ TUnwrappedParent DoMapFor(const TIterator& begin, const TIterator& end, const TFunc& func)
+ {
+ this->Consumer->OnBeginMap();
+ for (auto current = begin; current != end; ++current) {
+ func(TMapType<TFluentYsonVoid>(this->Consumer), current);
+ }
+ this->Consumer->OnEndMap();
+ return this->GetUnwrappedParent();
+ }
+
+ /// Open a map, call `func(*this, element)` for each `element` of `collection`, then close the map.
+ template <class TFunc, class TCollection>
+ TUnwrappedParent DoMapFor(const TCollection& collection, const TFunc& func)
+ {
+ this->Consumer->OnBeginMap();
+ for (const auto& item : collection) {
+ func(TMapType<TFluentYsonVoid>(this->Consumer), item);
+ }
+ this->Consumer->OnEndMap();
+ return this->GetUnwrappedParent();
+ }
+ };
+
+ /// Fluent adapter of any value.
+ template <class TParent>
+ class TAny
+ : public TAnyWithoutAttributes<TParent>
+ {
+ public:
+ using TBase = TAnyWithoutAttributes<TParent>;
+
+ explicit TAny(NYT::NYson::IYsonConsumer* consumer, TParent parent)
+ : TBase(consumer, std::move(parent))
+ { }
+
+ /// Open attributes.
+ TAttributes<TBase> BeginAttributes()
+ {
+ this->Consumer->OnBeginAttributes();
+ return TAttributes<TBase>(
+ this->Consumer,
+ TBase(this->Consumer, this->Parent));
+ }
+ };
+
+ /// Fluent adapter of attributes fragment (the inside part of attributes).
+ template <class TParent = TFluentYsonVoid>
+ class TAttributes
+ : public TFluentFragmentBase<TAttributes, TParent>
+ {
+ public:
+ using TThis = TAttributes<TParent>;
+ using TUnwrappedParent = typename TFluentYsonUnwrapper<TParent>::TUnwrapped;
+
+ explicit TAttributes(NYT::NYson::IYsonConsumer* consumer, TParent parent = TParent())
+ : TFluentFragmentBase<TFluentYsonBuilder::TAttributes, TParent>(consumer, std::move(parent))
+ { }
+
+ /// Pass attribute key to underlying consumer.
+ TAny<TThis> Item(const TStringBuf& key)
+ {
+ this->Consumer->OnKeyedItem(key);
+ return TAny<TThis>(this->Consumer, *this);
+ }
+
+ /// Pass attribute key to underlying consumer.
+ template <size_t Size>
+ TAny<TThis> Item(const char (&key)[Size])
+ {
+ return Item(TStringBuf(key, Size - 1));
+ }
+
+ //TODO: from TNode
+
+ /// Close the attributes.
+ TUnwrappedParent EndAttributes()
+ {
+ this->Consumer->OnEndAttributes();
+ return this->GetUnwrappedParent();
+ }
+ };
+
+ /// Fluent adapter of list fragment (the inside part of a list).
+ template <class TParent = TFluentYsonVoid>
+ class TListType
+ : public TFluentFragmentBase<TListType, TParent>
+ {
+ public:
+ using TThis = TListType<TParent>;
+ using TUnwrappedParent = typename TFluentYsonUnwrapper<TParent>::TUnwrapped;
+
+ explicit TListType(NYT::NYson::IYsonConsumer* consumer, TParent parent = TParent())
+ : TFluentFragmentBase<TFluentYsonBuilder::TListType, TParent>(consumer, std::move(parent))
+ { }
+
+ /// Call `OnListItem()` of underlying consumer.
+ TAny<TThis> Item()
+ {
+ this->Consumer->OnListItem();
+ return TAny<TThis>(this->Consumer, *this);
+ }
+
+ // TODO: from TNode
+
+ /// Close the list.
+ TUnwrappedParent EndList()
+ {
+ this->Consumer->OnEndList();
+ return this->GetUnwrappedParent();
+ }
+ };
+
+ /// Fluent adapter of map fragment (the inside part of a map).
+ template <class TParent = TFluentYsonVoid>
+ class TMapType
+ : public TFluentFragmentBase<TMapType, TParent>
+ {
+ public:
+ using TThis = TMapType<TParent>;
+ using TUnwrappedParent = typename TFluentYsonUnwrapper<TParent>::TUnwrapped;
+
+ explicit TMapType(NYT::NYson::IYsonConsumer* consumer, TParent parent = TParent())
+ : TFluentFragmentBase<TFluentYsonBuilder::TMapType, TParent>(consumer, std::move(parent))
+ { }
+
+ /// Pass map key to underlying consumer.
+ template <size_t Size>
+ TAny<TThis> Item(const char (&key)[Size])
+ {
+ return Item(TStringBuf(key, Size - 1));
+ }
+
+ /// Pass map key to underlying consumer.
+ TAny<TThis> Item(const TStringBuf& key)
+ {
+ this->Consumer->OnKeyedItem(key);
+ return TAny<TThis>(this->Consumer, *this);
+ }
+
+ // TODO: from TNode
+
+ /// Close the map.
+ TUnwrappedParent EndMap()
+ {
+ this->Consumer->OnEndMap();
+ return this->GetUnwrappedParent();
+ }
+ };
+
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+/// Builder representing any value.
+using TFluentAny = TFluentYsonBuilder::TAny<TFluentYsonVoid>;
+
+/// Builder representing the inside of a list (list fragment).
+using TFluentList = TFluentYsonBuilder::TListType<TFluentYsonVoid>;
+
+/// Builder representing the inside of a map (map fragment).
+using TFluentMap = TFluentYsonBuilder::TMapType<TFluentYsonVoid>;
+
+/// Builder representing the inside of attributes.
+using TFluentAttributes = TFluentYsonBuilder::TAttributes<TFluentYsonVoid>;
+
+////////////////////////////////////////////////////////////////////////////////
+
+/// Create a fluent adapter to invoke methods of `consumer`.
+static inline TFluentAny BuildYsonFluently(NYT::NYson::IYsonConsumer* consumer)
+{
+ return TFluentAny(consumer, TFluentYsonVoid());
+}
+
+/// Create a fluent adapter to invoke methods of `consumer` describing the contents of a list.
+static inline TFluentList BuildYsonListFluently(NYT::NYson::IYsonConsumer* consumer)
+{
+ return TFluentList(consumer);
+}
+
+/// Create a fluent adapter to invoke methods of `consumer` describing the contents of a map.
+static inline TFluentMap BuildYsonMapFluently(NYT::NYson::IYsonConsumer* consumer)
+{
+ return TFluentMap(consumer);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TFluentYsonWriterState
+ : public TThrRefBase
+{
+public:
+ using TValue = TString;
+
+ explicit TFluentYsonWriterState(::NYson::EYsonFormat format)
+ : Writer(&Output, format)
+ { }
+
+ TString GetValue()
+ {
+ return Output.Str();
+ }
+
+ NYT::NYson::IYsonConsumer* GetConsumer()
+ {
+ return &Writer;
+ }
+
+private:
+ TStringStream Output;
+ ::NYson::TYsonWriter Writer;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TFluentYsonBuilderState
+ : public TThrRefBase
+{
+public:
+ using TValue = TNode;
+
+ explicit TFluentYsonBuilderState()
+ : Builder(&Node)
+ { }
+
+ TNode GetValue()
+ {
+ return std::move(Node);
+ }
+
+ NYT::NYson::IYsonConsumer* GetConsumer()
+ {
+ return &Builder;
+ }
+
+private:
+ TNode Node;
+ TNodeBuilder Builder;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class TState>
+class TFluentYsonHolder
+{
+public:
+ explicit TFluentYsonHolder(::TIntrusivePtr<TState> state)
+ : State(state)
+ { }
+
+ ::TIntrusivePtr<TState> GetState() const
+ {
+ return State;
+ }
+
+private:
+ ::TIntrusivePtr<TState> State;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class TState>
+struct TFluentYsonUnwrapper< TFluentYsonHolder<TState> >
+{
+ using TUnwrapped = typename TState::TValue;
+
+ static TUnwrapped Unwrap(const TFluentYsonHolder<TState>& holder)
+ {
+ return std::move(holder.GetState()->GetValue());
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class TState>
+TFluentYsonBuilder::TAny<TFluentYsonHolder<TState>>
+BuildYsonFluentlyWithState(::TIntrusivePtr<TState> state)
+{
+ return TFluentYsonBuilder::TAny<TFluentYsonHolder<TState>>(
+ state->GetConsumer(),
+ TFluentYsonHolder<TState>(state));
+}
+
+/// Create a fluent adapter returning a `TString` with corresponding YSON when construction is finished.
+inline TFluentYsonBuilder::TAny<TFluentYsonHolder<TFluentYsonWriterState>>
+BuildYsonStringFluently(::NYson::EYsonFormat format = ::NYson::EYsonFormat::Text)
+{
+ ::TIntrusivePtr<TFluentYsonWriterState> state(new TFluentYsonWriterState(format));
+ return BuildYsonFluentlyWithState(state);
+}
+
+/// Create a fluent adapter returning a @ref NYT::TNode when construction is finished.
+inline TFluentYsonBuilder::TAny<TFluentYsonHolder<TFluentYsonBuilderState>>
+BuildYsonNodeFluently()
+{
+ ::TIntrusivePtr<TFluentYsonBuilderState> state(new TFluentYsonBuilderState);
+ return BuildYsonFluentlyWithState(state);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT