#ifndef ENUM_INL_H_ #error "Direct inclusion of this file is not allowed, include enum.h" // For the sake of sane code completion. #include "enum.h" #endif #include "format.h" #include #include namespace NYT { //////////////////////////////////////////////////////////////////////////////// namespace NDetail { [[noreturn]] void ThrowMalformedEnumValueException( TStringBuf typeName, TStringBuf value); void FormatUnknownEnumValue( TStringBuilderBase* builder, TStringBuf name, i64 value); } // namespace NDetail template std::optional TryParseEnum(TStringBuf value) { auto tryFromString = [] (TStringBuf value) -> std::optional { if (auto decodedValue = TryDecodeEnumValue(value)) { auto enumValue = TEnumTraits::FindValueByLiteral(*decodedValue); return enumValue ? enumValue : TEnumTraits::FindValueByLiteral(value); } auto reportError = [value] () { throw TSimpleException(Format("Enum value %Qv is neither in a proper underscore case nor in a format \"%v(123)\"", value, TEnumTraits::GetTypeName())); }; TStringBuf typeName; auto isTypeNameCorrect = value.NextTok('(', typeName) && typeName == TEnumTraits::GetTypeName(); if (!isTypeNameCorrect) { reportError(); } TStringBuf enumValue; std::underlying_type_t underlyingValue = 0; auto isEnumValueCorrect = value.NextTok(')', enumValue) && TryFromString(enumValue, underlyingValue); if (!isEnumValueCorrect) { reportError(); } auto isParsingComplete = value.empty(); if (!isParsingComplete) { reportError(); } return static_cast(underlyingValue); }; if constexpr (TEnumTraits::IsBitEnum) { T result{}; TStringBuf token; while (value.NextTok('|', token)) { if (auto scalar = tryFromString(StripString(token))) { result |= *scalar; } else { return {}; } } return result; } else { return tryFromString(value); } } template T ParseEnum(TStringBuf value) { if (auto optionalResult = TryParseEnum(value)) { return *optionalResult; } NYT::NDetail::ThrowMalformedEnumValueException(TEnumTraits::GetTypeName(), value); } template void FormatEnum(TStringBuilderBase* builder, T value, bool lowerCase) { auto formatScalarValue = [builder, lowerCase] (T value) { auto optionalLiteral = TEnumTraits::FindLiteralByValue(value); if (!optionalLiteral) { NYT::NDetail::FormatUnknownEnumValue( builder, TEnumTraits::GetTypeName(), ToUnderlying(value)); return; } if (lowerCase) { CamelCaseToUnderscoreCase(builder, *optionalLiteral); } else { builder->AppendString(*optionalLiteral); } }; if constexpr (TEnumTraits::IsBitEnum) { if (TEnumTraits::FindLiteralByValue(value)) { formatScalarValue(value); return; } auto first = true; for (auto scalarValue : TEnumTraits::GetDomainValues()) { if (Any(value & scalarValue)) { if (!first) { builder->AppendString(TStringBuf(" | ")); } first = false; formatScalarValue(scalarValue); } } } else { formatScalarValue(value); } } template TString FormatEnum(T value) { TStringBuilder builder; FormatEnum(&builder, value, /*lowerCase*/ true); return builder.Flush(); } //////////////////////////////////////////////////////////////////////////////// } // namespace NYT