aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordgolear <dgolear@yandex-team.com>2024-10-10 11:05:17 +0300
committerdgolear <dgolear@yandex-team.com>2024-10-10 11:34:56 +0300
commit9e123c4656b0ef4973531b837f30e9e542207590 (patch)
tree2b0ace1c8b13b4da76c50b03d3cde321395484fe
parent2d78fdbaebf316aaddd8674538b6d2fcd9e095d7 (diff)
downloadydb-9e123c4656b0ef4973531b837f30e9e542207590.tar.gz
YT: Support plain enum deserialization
(HIDDEN_URL commit_hash:d9358ac48da1ab4a4ef9ccdbf7eb77a100cf3897
-rw-r--r--library/cpp/yt/misc/cast-inl.h30
-rw-r--r--library/cpp/yt/misc/cast.h10
-rw-r--r--library/cpp/yt/misc/enum.h3
-rw-r--r--yt/yt/client/table_client/helpers-inl.h42
-rw-r--r--yt/yt/client/table_client/helpers.h14
-rw-r--r--yt/yt/core/yson/pull_parser_deserialize-inl.h14
-rw-r--r--yt/yt/core/yson/pull_parser_deserialize.h3
-rw-r--r--yt/yt/core/ytree/serialize-inl.h25
-rw-r--r--yt/yt/core/ytree/serialize.h6
-rw-r--r--yt/yt/core/ytree/unittests/serialize_ut.cpp13
10 files changed, 148 insertions, 12 deletions
diff --git a/library/cpp/yt/misc/cast-inl.h b/library/cpp/yt/misc/cast-inl.h
index a694394f88..00e6e240b8 100644
--- a/library/cpp/yt/misc/cast-inl.h
+++ b/library/cpp/yt/misc/cast-inl.h
@@ -18,35 +18,35 @@ namespace NYT {
namespace NDetail {
template <class T, class S>
-bool IsInIntegralRange(S value)
+constexpr bool IsInIntegralRange(S value)
requires std::is_signed_v<T> && std::is_signed_v<S>
{
return value >= std::numeric_limits<T>::lowest() && value <= std::numeric_limits<T>::max();
}
template <class T, class S>
-bool IsInIntegralRange(S value)
+constexpr bool IsInIntegralRange(S value)
requires std::is_signed_v<T> && std::is_unsigned_v<S>
{
return value <= static_cast<typename std::make_unsigned<T>::type>(std::numeric_limits<T>::max());
}
template <class T, class S>
-bool IsInIntegralRange(S value)
+constexpr bool IsInIntegralRange(S value)
requires std::is_unsigned_v<T> && std::is_signed_v<S>
{
return value >= 0 && static_cast<typename std::make_unsigned<S>::type>(value) <= std::numeric_limits<T>::max();
}
template <class T, class S>
-bool IsInIntegralRange(S value)
+constexpr bool IsInIntegralRange(S value)
requires std::is_unsigned_v<T> && std::is_unsigned_v<S>
{
return value <= std::numeric_limits<T>::max();
}
template <class T, class S>
-bool IsInIntegralRange(S value)
+constexpr bool IsInIntegralRange(S value)
requires std::is_enum_v<S>
{
return IsInIntegralRange<T>(static_cast<std::underlying_type_t<S>>(value));
@@ -79,10 +79,24 @@ inline TString FormatInvalidCastValue(char8_t value)
////////////////////////////////////////////////////////////////////////////////
+
+template <class T, class S>
+constexpr bool CanFitSubtype()
+{
+ return NDetail::IsInIntegralRange<T>(std::numeric_limits<S>::min()) &&
+ NDetail::IsInIntegralRange<T>(std::numeric_limits<S>::max());
+}
+
+template <class T, class S>
+constexpr bool IsInIntegralRange(S value)
+{
+ return NDetail::IsInIntegralRange<T>(value);
+}
+
template <class T, class S>
-bool TryIntegralCast(S value, T* result)
+constexpr bool TryIntegralCast(S value, T* result)
{
- if (!NYT::NDetail::IsInIntegralRange<T>(value)) {
+ if (!NDetail::IsInIntegralRange<T>(value)) {
return false;
}
*result = static_cast<T>(value);
@@ -105,7 +119,7 @@ T CheckedIntegralCast(S value)
}
template <class T, class S>
-bool TryEnumCast(S value, T* result)
+constexpr bool TryEnumCast(S value, T* result)
{
std::underlying_type_t<T> underlying;
if (!TryIntegralCast<std::underlying_type_t<T>>(value, &underlying)) {
diff --git a/library/cpp/yt/misc/cast.h b/library/cpp/yt/misc/cast.h
index c7565c9e6d..e8654cc122 100644
--- a/library/cpp/yt/misc/cast.h
+++ b/library/cpp/yt/misc/cast.h
@@ -7,7 +7,13 @@ namespace NYT {
////////////////////////////////////////////////////////////////////////////////
template <class T, class S>
-bool TryIntegralCast(S value, T* result);
+constexpr bool CanFitSubtype();
+
+template <class T, class S>
+constexpr bool IsInIntegralRange(S value);
+
+template <class T, class S>
+constexpr bool TryIntegralCast(S value, T* result);
template <class T, class S>
T CheckedIntegralCast(S value);
@@ -15,7 +21,7 @@ T CheckedIntegralCast(S value);
////////////////////////////////////////////////////////////////////////////////
template <class T, class S>
-bool TryEnumCast(S value, T* result);
+constexpr bool TryEnumCast(S value, T* result);
template <class T, class S>
T CheckedEnumCast(S value);
diff --git a/library/cpp/yt/misc/enum.h b/library/cpp/yt/misc/enum.h
index 954b63cbc0..4d40ab8ec4 100644
--- a/library/cpp/yt/misc/enum.h
+++ b/library/cpp/yt/misc/enum.h
@@ -26,6 +26,9 @@ namespace NYT {
template <class T>
void GetEnumTraitsImpl(T);
+template <class T, class S>
+constexpr bool CanFitSubtype();
+
template <class T>
using TEnumTraitsImpl = decltype(GetEnumTraitsImpl(T()));
diff --git a/yt/yt/client/table_client/helpers-inl.h b/yt/yt/client/table_client/helpers-inl.h
index a4e39d7a6c..86cc5a793c 100644
--- a/yt/yt/client/table_client/helpers-inl.h
+++ b/yt/yt/client/table_client/helpers-inl.h
@@ -14,6 +14,7 @@
#include <yt/yt/core/concurrency/scheduler.h>
#include <library/cpp/yt/misc/strong_typedef.h>
+#include <library/cpp/yt/misc/cast.h>
#include <array>
@@ -142,8 +143,10 @@ void ToUnversionedValue(
if constexpr (TEnumTraits<T>::IsStringSerializableEnum) {
ToUnversionedValue(unversionedValue, NYT::FormatEnum(value), rowBuffer, id, flags);
} else if constexpr (TEnumTraits<T>::IsBitEnum) {
+ static_assert(CanFitSubtype<ui64, std::underlying_type_t<T>>());
ToUnversionedValue(unversionedValue, static_cast<ui64>(value), rowBuffer, id, flags);
} else {
+ static_assert(CanFitSubtype<i64, std::underlying_type_t<T>>());
ToUnversionedValue(unversionedValue, static_cast<i64>(value), rowBuffer, id, flags);
}
}
@@ -154,12 +157,16 @@ void FromUnversionedValue(
T* value,
TUnversionedValue unversionedValue)
{
+ static_assert(TEnumTraits<T>::IsStringSerializableEnum ||
+ TEnumTraits<T>::IsBitEnum && CanFitSubtype<ui64, std::underlying_type_t<T>>() ||
+ !TEnumTraits<T>::IsBitEnum && CanFitSubtype<i64, std::underlying_type_t<T>>());
+
switch (unversionedValue.Type) {
case EValueType::Int64:
- *value = static_cast<T>(unversionedValue.Data.Int64);
+ *value = static_cast<T>(CheckedIntegralCast<std::underlying_type_t<T>>(unversionedValue.Data.Int64));
break;
case EValueType::Uint64:
- *value = static_cast<T>(unversionedValue.Data.Uint64);
+ *value = static_cast<T>(CheckedIntegralCast<std::underlying_type_t<T>>(unversionedValue.Data.Uint64));
break;
case EValueType::String:
*value = NYT::ParseEnum<T>(unversionedValue.AsStringBuf());
@@ -170,6 +177,37 @@ void FromUnversionedValue(
}
}
+template <class T>
+ requires (!TEnumTraits<T>::IsEnum) && std::is_enum_v<T>
+void ToUnversionedValue(
+ TUnversionedValue* unversionedValue,
+ T value,
+ const TRowBufferPtr& rowBuffer,
+ int id,
+ EValueFlags flags)
+{
+ static_assert(CanFitSubtype<i64, std::underlying_type_t<T>>());
+ ToUnversionedValue(unversionedValue, static_cast<i64>(value), rowBuffer, id, flags);
+}
+
+template <class T>
+ requires (!TEnumTraits<T>::IsEnum) && std::is_enum_v<T>
+void FromUnversionedValue(
+ T* value,
+ TUnversionedValue unversionedValue)
+{
+ static_assert(CanFitSubtype<i64, std::underlying_type_t<T>>());
+
+ switch (unversionedValue.Type) {
+ case EValueType::Int64:
+ *value = static_cast<T>(CheckedIntegralCast<std::underlying_type_t<T>>(unversionedValue.Data.Int64));
+ break;
+ default:
+ THROW_ERROR_EXCEPTION("Cannot parse enum value from %Qlv",
+ unversionedValue.Type);
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
void ProtobufToUnversionedValueImpl(
diff --git a/yt/yt/client/table_client/helpers.h b/yt/yt/client/table_client/helpers.h
index b86124557e..d1c5d17325 100644
--- a/yt/yt/client/table_client/helpers.h
+++ b/yt/yt/client/table_client/helpers.h
@@ -148,6 +148,20 @@ void FromUnversionedValue(
TUnversionedValue unversionedValue);
template <class T>
+ requires (!TEnumTraits<T>::IsEnum) && std::is_enum_v<T>
+void ToUnversionedValue(
+ TUnversionedValue* unversionedValue,
+ T value,
+ const TRowBufferPtr& rowBuffer,
+ int id = 0,
+ EValueFlags flags = EValueFlags::None);
+template <class T>
+ requires (!TEnumTraits<T>::IsEnum) && std::is_enum_v<T>
+void FromUnversionedValue(
+ T* value,
+ TUnversionedValue unversionedValue);
+
+template <class T>
TUnversionedValue ToUnversionedValue(
T&& value,
const TRowBufferPtr& rowBuffer,
diff --git a/yt/yt/core/yson/pull_parser_deserialize-inl.h b/yt/yt/core/yson/pull_parser_deserialize-inl.h
index b0f6b9d8ca..78e343d917 100644
--- a/yt/yt/core/yson/pull_parser_deserialize-inl.h
+++ b/yt/yt/core/yson/pull_parser_deserialize-inl.h
@@ -8,6 +8,8 @@
#include <yt/yt/core/yson/token_writer.h>
+#include <library/cpp/yt/misc/cast.h>
+
#include <vector>
namespace NYT::NYson {
@@ -239,6 +241,18 @@ void Deserialize(T& value, TYsonPullParserCursor* cursor)
}
}
+template <class T>
+requires (!TEnumTraits<T>::IsEnum) && std::is_enum_v<T>
+void Deserialize(T& value, TYsonPullParserCursor* cursor)
+{
+ static_assert(CanFitSubtype<i64, std::underlying_type_t<T>>());
+
+ MaybeSkipAttributes(cursor);
+ EnsureYsonToken("enum", *cursor, EYsonItemType::Int64Value);
+ value = static_cast<T>(CheckedIntegralCast<std::underlying_type_t<T>>((*cursor)->UncheckedAsInt64()));
+ cursor->Next();
+}
+
// TCompactVector
template <class T, size_t N>
void Deserialize(TCompactVector<T, N>& value, TYsonPullParserCursor* cursor, std::enable_if_t<ArePullParserDeserializable<T>(), void*>)
diff --git a/yt/yt/core/yson/pull_parser_deserialize.h b/yt/yt/core/yson/pull_parser_deserialize.h
index 5f6215180b..669b976394 100644
--- a/yt/yt/core/yson/pull_parser_deserialize.h
+++ b/yt/yt/core/yson/pull_parser_deserialize.h
@@ -113,6 +113,9 @@ void Deserialize(
template <class T>
requires TEnumTraits<T>::IsEnum
void Deserialize(T& value, TYsonPullParserCursor* cursor);
+template <class T>
+ requires (!TEnumTraits<T>::IsEnum) && std::is_enum_v<T>
+void Deserialize(T& value, TYsonPullParserCursor* cursor);
// TCompactVector.
template <class T, size_t N>
diff --git a/yt/yt/core/ytree/serialize-inl.h b/yt/yt/core/ytree/serialize-inl.h
index fe1ce789e6..01fc90c73a 100644
--- a/yt/yt/core/ytree/serialize-inl.h
+++ b/yt/yt/core/ytree/serialize-inl.h
@@ -344,6 +344,14 @@ void Serialize(T value, NYson::IYsonConsumer* consumer)
}
}
+template <class T>
+ requires (!TEnumTraits<T>::IsEnum) && std::is_enum_v<T>
+void Serialize(T value, NYson::IYsonConsumer* consumer)
+{
+ static_assert(CanFitSubtype<i64, std::underlying_type_t<T>>());
+ consumer->OnInt64Scalar(static_cast<i64>(value));
+}
+
// std::optional
template <class T>
void Serialize(const std::optional<T>& value, NYson::IYsonConsumer* consumer)
@@ -528,6 +536,23 @@ void Deserialize(T& value, INodePtr node)
}
}
+template <class T>
+ requires (!TEnumTraits<T>::IsEnum) && std::is_enum_v<T>
+void Deserialize(T& value, INodePtr node)
+{
+ switch (node->GetType()) {
+ case ENodeType::Int64: {
+ // TODO: CheckedEnumCast via __PRETTY_FUNCTION__?
+ i64 serialized = node->AsInt64()->GetValue();
+ value = static_cast<T>(CheckedIntegralCast<std::underlying_type_t<T>>(serialized));
+ break;
+ }
+ default:
+ THROW_ERROR_EXCEPTION("Cannot deserialize enum from %Qlv node",
+ node->GetType());
+ }
+}
+
// std::optional
template <class T>
void Deserialize(std::optional<T>& value, INodePtr node)
diff --git a/yt/yt/core/ytree/serialize.h b/yt/yt/core/ytree/serialize.h
index 3aa784ac8d..2d5185f18d 100644
--- a/yt/yt/core/ytree/serialize.h
+++ b/yt/yt/core/ytree/serialize.h
@@ -109,6 +109,9 @@ void Serialize(IInputStream& input, NYson::IYsonConsumer* consumer);
template <class T>
requires TEnumTraits<T>::IsEnum
void Serialize(T value, NYson::IYsonConsumer* consumer);
+template <class T>
+ requires (!TEnumTraits<T>::IsEnum) && std::is_enum_v<T>
+void Serialize(T value, NYson::IYsonConsumer* consumer);
// std::optional
template <class T>
@@ -218,6 +221,9 @@ void Deserialize(TGuid& value, INodePtr node);
template <class T>
requires TEnumTraits<T>::IsEnum
void Deserialize(T& value, INodePtr node);
+template <class T>
+ requires (!TEnumTraits<T>::IsEnum) && std::is_enum_v<T>
+void Deserialize(T& value, INodePtr node);
// std::optional
template <class T>
diff --git a/yt/yt/core/ytree/unittests/serialize_ut.cpp b/yt/yt/core/ytree/unittests/serialize_ut.cpp
index ee36997f70..63bf71b0d2 100644
--- a/yt/yt/core/ytree/unittests/serialize_ut.cpp
+++ b/yt/yt/core/ytree/unittests/serialize_ut.cpp
@@ -51,6 +51,12 @@ DEFINE_BIT_ENUM(ETestBitEnum,
((Green) (0x0004))
);
+enum class EPlainTestEnum
+{
+ First,
+ Second,
+};
+
template <typename T>
T PullParserConvert(TYsonStringBuf s)
{
@@ -427,6 +433,13 @@ TEST(TSerializationTest, SerializableArcadiaEnum)
}
}
+TEST(TSerializationTest, PlainEnum)
+{
+ TestSerializationDeserialization(EPlainTestEnum::First);
+
+ TestSerializationDeserialization(static_cast<EPlainTestEnum>(42));
+}
+
TEST(TYTreeSerializationTest, Protobuf)
{
NProto::TTestMessage message;