From 9852998440dcaa3eec11377553e996ff9852bb4e Mon Sep 17 00:00:00 2001 From: pechatnov Date: Thu, 26 Mar 2026 10:11:59 +0300 Subject: Add suggestions on enum parse error commit_hash:3b7f35f613737aa92f473877e8b24782f7dfcd2a --- library/cpp/yt/string/enum-inl.h | 26 +++++++++++++++++-- library/cpp/yt/string/enum.cpp | 40 ++++++++++++++++++++++++++--- library/cpp/yt/string/enum.h | 3 +++ library/cpp/yt/string/unittests/enum_ut.cpp | 2 -- 4 files changed, 63 insertions(+), 8 deletions(-) (limited to 'library/cpp') diff --git a/library/cpp/yt/string/enum-inl.h b/library/cpp/yt/string/enum-inl.h index 9f8ca893d2f..14d26c61158 100644 --- a/library/cpp/yt/string/enum-inl.h +++ b/library/cpp/yt/string/enum-inl.h @@ -13,16 +13,28 @@ #include #include +#include + namespace NYT { //////////////////////////////////////////////////////////////////////////////// namespace NDetail { +//////////////////////////////////////////////////////////////////////////////// + +using TEnumSuggestionsCalculator = std::string (*)( + TStringBuf value, + const std::span& domainNames); + +extern "C" TEnumSuggestionsCalculator TryGetEnumSuggestionsCalculator(); + [[noreturn]] void ThrowMalformedEnumValueException( TStringBuf typeName, - TStringBuf value); + TStringBuf value, + const std::span& domainNames = {}); + void FormatUnknownEnumValue( auto* builder, @@ -32,8 +44,12 @@ void FormatUnknownEnumValue( builder->AppendFormat("%v::unknown-%v", name, ToUnderlying(value)); } +//////////////////////////////////////////////////////////////////////////////// + } // namespace NDetail +//////////////////////////////////////////////////////////////////////////////// + template std::optional TryParseEnum(TStringBuf str, bool enableUnknown) { @@ -80,7 +96,13 @@ T ParseEnum(TStringBuf str) if (auto optionalResult = TryParseEnum(str, /*enableUnkown*/ true)) { return *optionalResult; } - NYT::NDetail::ThrowMalformedEnumValueException(TEnumTraits::GetTypeName(), str); + + std::span domainNames; + if constexpr (requires { TEnumTraits::GetDomainNames(); }) { + domainNames = TEnumTraits::GetDomainNames(); + } + + NYT::NDetail::ThrowMalformedEnumValueException(TEnumTraits::GetTypeName(), str, domainNames); } template diff --git a/library/cpp/yt/string/enum.cpp b/library/cpp/yt/string/enum.cpp index 844254faa0f..beeba753daf 100644 --- a/library/cpp/yt/string/enum.cpp +++ b/library/cpp/yt/string/enum.cpp @@ -8,11 +8,39 @@ namespace NYT { namespace NDetail { -void ThrowMalformedEnumValueException(TStringBuf typeName, TStringBuf value) +//////////////////////////////////////////////////////////////////////////////// + +#if defined(_MSC_VER) + +extern "C" TEnumSuggestionsCalculator TryGetEnumSuggestionsCalculatorWeak() +{ + return nullptr; +} + +__pragma(comment(linker, "/alternatename:TryGetEnumSuggestionsCalculator=TryGetEnumSuggestionsCalculatorWeak")) + +#else + +extern "C" Y_WEAK TEnumSuggestionsCalculator TryGetEnumSuggestionsCalculator() { - throw TSimpleException(Format("Error parsing %v value %Qv", - typeName, - value)); + return nullptr; +} + +#endif + +//////////////////////////////////////////////////////////////////////////////// + +void ThrowMalformedEnumValueException( + TStringBuf typeName, + TStringBuf value, + const std::span& domainNames) +{ + auto errorMessage = Format("Error parsing %v value %Qv", typeName, value); + auto suggestionsCalculator = TryGetEnumSuggestionsCalculator(); + if (!domainNames.empty() && suggestionsCalculator) { + errorMessage += Format("; closest possible values are %v", suggestionsCalculator(value, domainNames)); + } + throw TSimpleException(errorMessage); } template @@ -32,8 +60,12 @@ std::optional DecodeEnumValueImpl(TStringBuf value) return camelValue; } +//////////////////////////////////////////////////////////////////////////////// + } // namespace NDetail +//////////////////////////////////////////////////////////////////////////////// + std::optional TryDecodeEnumValue(TStringBuf value) { return NDetail::DecodeEnumValueImpl(value); diff --git a/library/cpp/yt/string/enum.h b/library/cpp/yt/string/enum.h index de7d6a52fac..322485a560d 100644 --- a/library/cpp/yt/string/enum.h +++ b/library/cpp/yt/string/enum.h @@ -17,6 +17,9 @@ std::string EncodeEnumValue(TStringBuf value); template std::optional TryParseEnum(TStringBuf str, bool enableUnknown = false); +//! Parses an enum value from a string. +//! Link against library/cpp/yt/string/enable_enum_suggestions_on_enum_parse_error +//! to include suggestions in the exception message on parse failure. template T ParseEnum(TStringBuf str); diff --git a/library/cpp/yt/string/unittests/enum_ut.cpp b/library/cpp/yt/string/unittests/enum_ut.cpp index 39dbdfd2075..b262568565c 100644 --- a/library/cpp/yt/string/unittests/enum_ut.cpp +++ b/library/cpp/yt/string/unittests/enum_ut.cpp @@ -126,5 +126,3 @@ TEST(TParseEnumTest, ParseBitEnum) } // namespace } // namespace NYT - - -- cgit v1.3