diff options
| author | pechatnov <[email protected]> | 2026-03-26 10:11:59 +0300 |
|---|---|---|
| committer | pechatnov <[email protected]> | 2026-03-26 11:00:16 +0300 |
| commit | 9852998440dcaa3eec11377553e996ff9852bb4e (patch) | |
| tree | 83fd6cf6a491aba90ce28060576fdbf736939227 /library | |
| parent | 46c6fa262d8246e71e7f5ed33eb8458f45c5ddf7 (diff) | |
Add suggestions on enum parse error
commit_hash:3b7f35f613737aa92f473877e8b24782f7dfcd2a
Diffstat (limited to 'library')
| -rw-r--r-- | library/cpp/yt/string/enum-inl.h | 26 | ||||
| -rw-r--r-- | library/cpp/yt/string/enum.cpp | 40 | ||||
| -rw-r--r-- | library/cpp/yt/string/enum.h | 3 | ||||
| -rw-r--r-- | library/cpp/yt/string/unittests/enum_ut.cpp | 2 |
4 files changed, 63 insertions, 8 deletions
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 <util/string/printf.h> #include <util/string/strip.h> +#include <span> + namespace NYT { //////////////////////////////////////////////////////////////////////////////// namespace NDetail { +//////////////////////////////////////////////////////////////////////////////// + +using TEnumSuggestionsCalculator = std::string (*)( + TStringBuf value, + const std::span<const TStringBuf>& domainNames); + +extern "C" TEnumSuggestionsCalculator TryGetEnumSuggestionsCalculator(); + [[noreturn]] void ThrowMalformedEnumValueException( TStringBuf typeName, - TStringBuf value); + TStringBuf value, + const std::span<const TStringBuf>& domainNames = {}); + void FormatUnknownEnumValue( auto* builder, @@ -32,8 +44,12 @@ void FormatUnknownEnumValue( builder->AppendFormat("%v::unknown-%v", name, ToUnderlying(value)); } +//////////////////////////////////////////////////////////////////////////////// + } // namespace NDetail +//////////////////////////////////////////////////////////////////////////////// + template <class T> std::optional<T> TryParseEnum(TStringBuf str, bool enableUnknown) { @@ -80,7 +96,13 @@ T ParseEnum(TStringBuf str) if (auto optionalResult = TryParseEnum<T>(str, /*enableUnkown*/ true)) { return *optionalResult; } - NYT::NDetail::ThrowMalformedEnumValueException(TEnumTraits<T>::GetTypeName(), str); + + std::span<const TStringBuf> domainNames; + if constexpr (requires { TEnumTraits<T>::GetDomainNames(); }) { + domainNames = TEnumTraits<T>::GetDomainNames(); + } + + NYT::NDetail::ThrowMalformedEnumValueException(TEnumTraits<T>::GetTypeName(), str, domainNames); } template <class T> 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<const TStringBuf>& 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 <bool ThrowOnError> @@ -32,8 +60,12 @@ std::optional<std::string> DecodeEnumValueImpl(TStringBuf value) return camelValue; } +//////////////////////////////////////////////////////////////////////////////// + } // namespace NDetail +//////////////////////////////////////////////////////////////////////////////// + std::optional<std::string> TryDecodeEnumValue(TStringBuf value) { return NDetail::DecodeEnumValueImpl<false>(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 <class T> std::optional<T> 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 <class T> 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 - - |
