From 9cdbc0bb56469a6d9c253f6f0869a69a65a8530f Mon Sep 17 00:00:00 2001 From: Sergey Alexeev Date: Wed, 9 Oct 2024 20:16:45 +0300 Subject: [PATCH 1/4] support for x-enum-varnames in chaotic --- .../chaotic/back/cpp/templates/type.hpp.jinja | 4 +-- .../back/cpp/templates/type_parsers.ipp.jinja | 2 +- chaotic/chaotic/back/cpp/translator.py | 27 +++++++++++++++++-- chaotic/chaotic/back/cpp/types.py | 11 +++++++- 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/chaotic/chaotic/back/cpp/templates/type.hpp.jinja b/chaotic/chaotic/back/cpp/templates/type.hpp.jinja index af6cca4694ad..747343819c93 100644 --- a/chaotic/chaotic/back/cpp/templates/type.hpp.jinja +++ b/chaotic/chaotic/back/cpp/templates/type.hpp.jinja @@ -44,13 +44,13 @@ {% elif type.get_py_type() == 'CppIntEnum' %} enum class {{ type.cpp_local_name() }} { {%- for item in type.enums %} - k{{ item }} = {{ item }}, + k{{ item.cpp_name }} = {{ item.value }}, {%- endfor -%} }; static constexpr {{ type.cpp_local_name() }} k{{ type.cpp_local_name() }}Values [] = { {%- for item in type.enums %} - {{ type.cpp_local_name() }}::k{{ item }}, + {{ type.cpp_local_name() }}::k{{ item.cpp_name }}, {%- endfor -%} }; {% elif type.get_py_type() == 'CppStringEnum' %} diff --git a/chaotic/chaotic/back/cpp/templates/type_parsers.ipp.jinja b/chaotic/chaotic/back/cpp/templates/type_parsers.ipp.jinja index 81120329e530..d79c4470a3dd 100644 --- a/chaotic/chaotic/back/cpp/templates/type_parsers.ipp.jinja +++ b/chaotic/chaotic/back/cpp/templates/type_parsers.ipp.jinja @@ -35,7 +35,7 @@ [](auto selector) { return selector().template Type<{{ type.cpp_global_name() }}, int>() {%- for item in type.enums %} - .Case({{ type.cpp_global_name() }}::k{{ item }}, {{ item }}) + .Case({{ type.cpp_global_name() }}::k{{ item.cpp_name }}, {{ item.value }}) {%- endfor -%} ; }; diff --git a/chaotic/chaotic/back/cpp/translator.py b/chaotic/chaotic/back/cpp/translator.py index c375f7aee109..97e4fefc5116 100644 --- a/chaotic/chaotic/back/cpp/translator.py +++ b/chaotic/chaotic/back/cpp/translator.py @@ -38,7 +38,8 @@ class GeneratorState: NON_NAME_SYMBOL_RE = re.compile('[^_0-9a-zA-Z]') - +SPLIT_RE = re.compile(r'[a-zA-Z0-9]+') +SPLIT_WORDS_RE = re.compile(r'[A-Z]+(?=[A-Z][a-z0-9])|[A-Z][a-z0-9]+|[a-z0-9]+|[A-Z]+') class FormatChooser: def __init__(self, types: List[cpp_types.CppType]) -> None: @@ -262,13 +263,35 @@ def _gen_integer( assert schema.format is None assert user_cpp_type is None + enum_names = [] + + if hasattr(schema, 'x_properties') and 'x-enum-varnames' in schema.x_properties: + enum_names = schema.x_properties['x-enum-varnames'] + + emum_items: List[cpp_types.CppIntEnumItem] = [] + + def to_camel_case(text: str) -> str: + words = SPLIT_RE.findall(text) + result = [] + for word in words: + result.extend([part.capitalize() for part in SPLIT_WORDS_RE.findall(word)]) + return ''.join(result) + + for i in range(len(schema.enum)): + raw_name = str(schema.enum[i]) + if i < len(enum_names): + raw_name = enum_names[i] + emum_items.append(cpp_types.CppIntEnumItem(value=schema.enum[i], + raw_name=raw_name, + cpp_name=to_camel_case(raw_name), )) + return cpp_types.CppIntEnum( json_schema=schema, nullable=schema.nullable, raw_cpp_type=name, user_cpp_type=None, name=name.in_global_scope(), - enums=schema.enum, + enums=emum_items, ) if schema.format is None: diff --git a/chaotic/chaotic/back/cpp/types.py b/chaotic/chaotic/back/cpp/types.py index 493219b2c0b5..5e28f9f3a54c 100644 --- a/chaotic/chaotic/back/cpp/types.py +++ b/chaotic/chaotic/back/cpp/types.py @@ -513,11 +513,20 @@ def camel_case(string: str, no_lower_casing: bool = False) -> str: class EnumItemName(str): pass +@dataclasses.dataclass +class CppIntEnumItem: + value: int + raw_name: str + cpp_name: str + + def definition_includes(self) -> List[str]: + return ['fmt/format.h'] + @dataclasses.dataclass class CppIntEnum(CppType): name: str - enums: List[int] + enums: List[CppIntEnumItem] __hash__ = CppType.__hash__ From 885faab7b743e39d8d29fa6465197914a24afd2a Mon Sep 17 00:00:00 2001 From: Sergey Alexeev Date: Wed, 9 Oct 2024 22:02:42 +0300 Subject: [PATCH 2/4] support for x-enum-varnames in chaotic with test --- .../chaotic/back/cpp/templates/type.hpp.jinja | 6 +- chaotic/chaotic/back/cpp/translator.py | 6 +- .../output/schemas/int_enum/int_enum.cpp | 81 +++++++++++++++++++ .../output/schemas/int_enum/int_enum.hpp | 70 ++++++++++++++++ .../output/schemas/int_enum/int_enum_fwd.hpp | 7 ++ .../schemas/int_enum/int_enum_parsers.ipp | 63 +++++++++++++++ .../schemas/schemas/int_enum/int_enum.cpp | 81 +++++++++++++++++++ .../schemas/schemas/int_enum/int_enum.hpp | 65 +++++++++++++++ .../schemas/schemas/int_enum/int_enum_fwd.hpp | 7 ++ .../schemas/int_enum/int_enum_parsers.ipp | 63 +++++++++++++++ .../schemas/int_enum/int_enum.yaml | 14 ++++ 11 files changed, 457 insertions(+), 6 deletions(-) create mode 100644 chaotic/golden_tests/output/schemas/int_enum/int_enum.cpp create mode 100644 chaotic/golden_tests/output/schemas/int_enum/int_enum.hpp create mode 100644 chaotic/golden_tests/output/schemas/int_enum/int_enum_fwd.hpp create mode 100644 chaotic/golden_tests/output/schemas/int_enum/int_enum_parsers.ipp create mode 100644 chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum.cpp create mode 100644 chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum.hpp create mode 100644 chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum_fwd.hpp create mode 100644 chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum_parsers.ipp create mode 100644 chaotic/golden_tests/schemas/int_enum/int_enum.yaml diff --git a/chaotic/chaotic/back/cpp/templates/type.hpp.jinja b/chaotic/chaotic/back/cpp/templates/type.hpp.jinja index 747343819c93..8c039ea8606c 100644 --- a/chaotic/chaotic/back/cpp/templates/type.hpp.jinja +++ b/chaotic/chaotic/back/cpp/templates/type.hpp.jinja @@ -44,14 +44,14 @@ {% elif type.get_py_type() == 'CppIntEnum' %} enum class {{ type.cpp_local_name() }} { {%- for item in type.enums %} - k{{ item.cpp_name }} = {{ item.value }}, - {%- endfor -%} + k{{ item.cpp_name }} = {{ item.value }}, // {{ item.raw_name }} + {%- endfor %} }; static constexpr {{ type.cpp_local_name() }} k{{ type.cpp_local_name() }}Values [] = { {%- for item in type.enums %} {{ type.cpp_local_name() }}::k{{ item.cpp_name }}, - {%- endfor -%} + {%- endfor %} }; {% elif type.get_py_type() == 'CppStringEnum' %} enum class {{ type.cpp_local_name() }} { diff --git a/chaotic/chaotic/back/cpp/translator.py b/chaotic/chaotic/back/cpp/translator.py index 97e4fefc5116..2dad6bdf9bee 100644 --- a/chaotic/chaotic/back/cpp/translator.py +++ b/chaotic/chaotic/back/cpp/translator.py @@ -265,7 +265,7 @@ def _gen_integer( enum_names = [] - if hasattr(schema, 'x_properties') and 'x-enum-varnames' in schema.x_properties: + if 'x-enum-varnames' in schema.x_properties: enum_names = schema.x_properties['x-enum-varnames'] emum_items: List[cpp_types.CppIntEnumItem] = [] @@ -277,8 +277,8 @@ def to_camel_case(text: str) -> str: result.extend([part.capitalize() for part in SPLIT_WORDS_RE.findall(word)]) return ''.join(result) - for i in range(len(schema.enum)): - raw_name = str(schema.enum[i]) + for i, val in enumerate(schema.enum): + raw_name = str(val) if i < len(enum_names): raw_name = enum_names[i] emum_items.append(cpp_types.CppIntEnumItem(value=schema.enum[i], diff --git a/chaotic/golden_tests/output/schemas/int_enum/int_enum.cpp b/chaotic/golden_tests/output/schemas/int_enum/int_enum.cpp new file mode 100644 index 000000000000..ebad2ddd460a --- /dev/null +++ b/chaotic/golden_tests/output/schemas/int_enum/int_enum.cpp @@ -0,0 +1,81 @@ +#include "int_enum.hpp" + +#include + +#include "int_enum_parsers.ipp" + +namespace ns { + +bool operator==(const ns::Enum& lhs, const ns::Enum& rhs) { + return lhs.foo == rhs.foo && true; +} + +USERVER_NAMESPACE::logging::LogHelper& operator<<( + USERVER_NAMESPACE::logging::LogHelper& lh, const ns::Enum::Foo& value) { + return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value) + .ExtractValue()); +} + +USERVER_NAMESPACE::logging::LogHelper& operator<<( + USERVER_NAMESPACE::logging::LogHelper& lh, const ns::Enum& value) { + return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value) + .ExtractValue()); +} + +Enum::Foo Parse(USERVER_NAMESPACE::formats::json::Value json, + USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); +} + +Enum Parse(USERVER_NAMESPACE::formats::json::Value json, + USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); +} + +Enum::Foo Parse(USERVER_NAMESPACE::formats::yaml::Value json, + USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); +} + +Enum Parse(USERVER_NAMESPACE::formats::yaml::Value json, + USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); +} + +Enum::Foo Parse(USERVER_NAMESPACE::yaml_config::Value json, + USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); +} + +Enum Parse(USERVER_NAMESPACE::yaml_config::Value json, + USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); +} + +USERVER_NAMESPACE::formats::json::Value Serialize( + const ns::Enum::Foo& value, USERVER_NAMESPACE::formats::serialize::To< + USERVER_NAMESPACE::formats::json::Value> + to) { + const auto result = kns__Enum__Foo_Mapping.TryFindByFirst(value); + if (result.has_value()) { + return Serialize(*result, to); + } + throw std::runtime_error("Bad enum value"); +} + +USERVER_NAMESPACE::formats::json::Value Serialize( + [[maybe_unused]] const ns::Enum& value, + USERVER_NAMESPACE::formats::serialize::To< + USERVER_NAMESPACE::formats::json::Value>) { + USERVER_NAMESPACE::formats::json::ValueBuilder vb = + USERVER_NAMESPACE::formats::common::Type::kObject; + + if (value.foo) { + vb["foo"] = + USERVER_NAMESPACE::chaotic::Primitive{*value.foo}; + } + + return vb.ExtractValue(); +} + +} // namespace ns diff --git a/chaotic/golden_tests/output/schemas/int_enum/int_enum.hpp b/chaotic/golden_tests/output/schemas/int_enum/int_enum.hpp new file mode 100644 index 000000000000..e1c3512b7aa4 --- /dev/null +++ b/chaotic/golden_tests/output/schemas/int_enum/int_enum.hpp @@ -0,0 +1,70 @@ +#pragma once + +#include "int_enum_fwd.hpp" + +#include +#include + +#include + +namespace ns { + +struct Enum { + enum class Foo { + kOne, + kTwo, + kThree, + }; + + static constexpr Foo kFooValues[] = { + Foo::kOne, + Foo::kTwo, + Foo::kThree, + }; + + std::optional foo{}; +}; + +bool operator==(const ns::Enum& lhs, const ns::Enum& rhs); + +USERVER_NAMESPACE::logging::LogHelper& operator<<( + USERVER_NAMESPACE::logging::LogHelper& lh, const ns::Enum::Foo& value); + +USERVER_NAMESPACE::logging::LogHelper& operator<<( + USERVER_NAMESPACE::logging::LogHelper& lh, const ns::Enum& value); + +Enum::Foo Parse(USERVER_NAMESPACE::formats::json::Value json, + USERVER_NAMESPACE::formats::parse::To); + +Enum Parse(USERVER_NAMESPACE::formats::json::Value json, + USERVER_NAMESPACE::formats::parse::To); + +Enum::Foo Parse(USERVER_NAMESPACE::formats::yaml::Value json, + USERVER_NAMESPACE::formats::parse::To); + +Enum Parse(USERVER_NAMESPACE::formats::yaml::Value json, + USERVER_NAMESPACE::formats::parse::To); + +Enum::Foo Parse(USERVER_NAMESPACE::yaml_config::Value json, + USERVER_NAMESPACE::formats::parse::To); + +Enum Parse(USERVER_NAMESPACE::yaml_config::Value json, + USERVER_NAMESPACE::formats::parse::To); + +Enum::Foo FromString(std::string_view value, + USERVER_NAMESPACE::formats::parse::To); + +Enum::Foo Parse(std::string_view value, + USERVER_NAMESPACE::formats::parse::To); + +USERVER_NAMESPACE::formats::json::Value Serialize( + const ns::Enum::Foo& value, USERVER_NAMESPACE::formats::serialize::To< + USERVER_NAMESPACE::formats::json::Value>); + +USERVER_NAMESPACE::formats::json::Value Serialize( + const ns::Enum& value, USERVER_NAMESPACE::formats::serialize::To< + USERVER_NAMESPACE::formats::json::Value>); + +std::string ToString(ns::Enum::Foo value); + +} // namespace ns diff --git a/chaotic/golden_tests/output/schemas/int_enum/int_enum_fwd.hpp b/chaotic/golden_tests/output/schemas/int_enum/int_enum_fwd.hpp new file mode 100644 index 000000000000..fe76c3d643b8 --- /dev/null +++ b/chaotic/golden_tests/output/schemas/int_enum/int_enum_fwd.hpp @@ -0,0 +1,7 @@ +#pragma once + +namespace ns { + +struct Enum; + +} // namespace ns diff --git a/chaotic/golden_tests/output/schemas/int_enum/int_enum_parsers.ipp b/chaotic/golden_tests/output/schemas/int_enum/int_enum_parsers.ipp new file mode 100644 index 000000000000..519d374d130c --- /dev/null +++ b/chaotic/golden_tests/output/schemas/int_enum/int_enum_parsers.ipp @@ -0,0 +1,63 @@ +#pragma once + +#include "int_enum.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ns { + +static constexpr USERVER_NAMESPACE::utils::TrivialBiMap kns__Enum__Foo_Mapping = + [](auto selector) { + return selector() + .template Type() + .Case(ns::Enum::Foo::kInner, 0) + .Case(ns::Enum::Foo::kLeft, 1) + .Case(ns::Enum::Foo::kRight, 2) + .Case(ns::Enum::Foo::kOuter, 3) + .Case(ns::Enum::Foo::k5, 5); + }; + +static constexpr USERVER_NAMESPACE::utils::TrivialSet + kns__Enum_PropertiesNames = [](auto selector) { + return selector().template Type().Case("foo"); + }; + +template +ns::Enum::Foo Parse(Value val, + USERVER_NAMESPACE::formats::parse::To) { + const auto value = val.template As(); + const auto result = kns__Enum__Foo_Mapping.TryFindBySecond(value); + if (result.has_value()) { + return *result; + } + USERVER_NAMESPACE::chaotic::ThrowForValue( + fmt::format("Invalid enum value ({}) for type ns::Enum::Foo", value), + val); +} + +template +ns::Enum Parse(Value value, USERVER_NAMESPACE::formats::parse::To) { + value.CheckNotMissing(); + value.CheckObjectOrNull(); + + ns::Enum res; + + res.foo = value["foo"] + .template As>>(); + + USERVER_NAMESPACE::chaotic::ValidateNoAdditionalProperties( + value, kns__Enum_PropertiesNames); + + return res; +} + +} // namespace ns diff --git a/chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum.cpp b/chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum.cpp new file mode 100644 index 000000000000..ebad2ddd460a --- /dev/null +++ b/chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum.cpp @@ -0,0 +1,81 @@ +#include "int_enum.hpp" + +#include + +#include "int_enum_parsers.ipp" + +namespace ns { + +bool operator==(const ns::Enum& lhs, const ns::Enum& rhs) { + return lhs.foo == rhs.foo && true; +} + +USERVER_NAMESPACE::logging::LogHelper& operator<<( + USERVER_NAMESPACE::logging::LogHelper& lh, const ns::Enum::Foo& value) { + return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value) + .ExtractValue()); +} + +USERVER_NAMESPACE::logging::LogHelper& operator<<( + USERVER_NAMESPACE::logging::LogHelper& lh, const ns::Enum& value) { + return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value) + .ExtractValue()); +} + +Enum::Foo Parse(USERVER_NAMESPACE::formats::json::Value json, + USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); +} + +Enum Parse(USERVER_NAMESPACE::formats::json::Value json, + USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); +} + +Enum::Foo Parse(USERVER_NAMESPACE::formats::yaml::Value json, + USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); +} + +Enum Parse(USERVER_NAMESPACE::formats::yaml::Value json, + USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); +} + +Enum::Foo Parse(USERVER_NAMESPACE::yaml_config::Value json, + USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); +} + +Enum Parse(USERVER_NAMESPACE::yaml_config::Value json, + USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); +} + +USERVER_NAMESPACE::formats::json::Value Serialize( + const ns::Enum::Foo& value, USERVER_NAMESPACE::formats::serialize::To< + USERVER_NAMESPACE::formats::json::Value> + to) { + const auto result = kns__Enum__Foo_Mapping.TryFindByFirst(value); + if (result.has_value()) { + return Serialize(*result, to); + } + throw std::runtime_error("Bad enum value"); +} + +USERVER_NAMESPACE::formats::json::Value Serialize( + [[maybe_unused]] const ns::Enum& value, + USERVER_NAMESPACE::formats::serialize::To< + USERVER_NAMESPACE::formats::json::Value>) { + USERVER_NAMESPACE::formats::json::ValueBuilder vb = + USERVER_NAMESPACE::formats::common::Type::kObject; + + if (value.foo) { + vb["foo"] = + USERVER_NAMESPACE::chaotic::Primitive{*value.foo}; + } + + return vb.ExtractValue(); +} + +} // namespace ns diff --git a/chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum.hpp b/chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum.hpp new file mode 100644 index 000000000000..7b8b034781b9 --- /dev/null +++ b/chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include "int_enum_fwd.hpp" + +#include + +#include + +namespace ns { + +struct Enum { + enum class Foo { + kInner = 0, // Inner + kLeft = 1, // Left + kRight = 2, // Right + kOuter = 3, // Outer + k5 = 5, // 5 + }; + + static constexpr Foo kFooValues[] = { + Foo::kInner, + Foo::kLeft, + Foo::kRight, + Foo::kOuter, + Foo::k5, + }; + + std::optional foo{}; +}; + +bool operator==(const ns::Enum& lhs, const ns::Enum& rhs); + +USERVER_NAMESPACE::logging::LogHelper& operator<<( + USERVER_NAMESPACE::logging::LogHelper& lh, const ns::Enum::Foo& value); + +USERVER_NAMESPACE::logging::LogHelper& operator<<( + USERVER_NAMESPACE::logging::LogHelper& lh, const ns::Enum& value); + +Enum::Foo Parse(USERVER_NAMESPACE::formats::json::Value json, + USERVER_NAMESPACE::formats::parse::To); + +Enum Parse(USERVER_NAMESPACE::formats::json::Value json, + USERVER_NAMESPACE::formats::parse::To); + +Enum::Foo Parse(USERVER_NAMESPACE::formats::yaml::Value json, + USERVER_NAMESPACE::formats::parse::To); + +Enum Parse(USERVER_NAMESPACE::formats::yaml::Value json, + USERVER_NAMESPACE::formats::parse::To); + +Enum::Foo Parse(USERVER_NAMESPACE::yaml_config::Value json, + USERVER_NAMESPACE::formats::parse::To); + +Enum Parse(USERVER_NAMESPACE::yaml_config::Value json, + USERVER_NAMESPACE::formats::parse::To); + +USERVER_NAMESPACE::formats::json::Value Serialize( + const ns::Enum::Foo& value, USERVER_NAMESPACE::formats::serialize::To< + USERVER_NAMESPACE::formats::json::Value>); + +USERVER_NAMESPACE::formats::json::Value Serialize( + const ns::Enum& value, USERVER_NAMESPACE::formats::serialize::To< + USERVER_NAMESPACE::formats::json::Value>); + +} // namespace ns \ No newline at end of file diff --git a/chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum_fwd.hpp b/chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum_fwd.hpp new file mode 100644 index 000000000000..fe76c3d643b8 --- /dev/null +++ b/chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum_fwd.hpp @@ -0,0 +1,7 @@ +#pragma once + +namespace ns { + +struct Enum; + +} // namespace ns diff --git a/chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum_parsers.ipp b/chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum_parsers.ipp new file mode 100644 index 000000000000..519d374d130c --- /dev/null +++ b/chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum_parsers.ipp @@ -0,0 +1,63 @@ +#pragma once + +#include "int_enum.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ns { + +static constexpr USERVER_NAMESPACE::utils::TrivialBiMap kns__Enum__Foo_Mapping = + [](auto selector) { + return selector() + .template Type() + .Case(ns::Enum::Foo::kInner, 0) + .Case(ns::Enum::Foo::kLeft, 1) + .Case(ns::Enum::Foo::kRight, 2) + .Case(ns::Enum::Foo::kOuter, 3) + .Case(ns::Enum::Foo::k5, 5); + }; + +static constexpr USERVER_NAMESPACE::utils::TrivialSet + kns__Enum_PropertiesNames = [](auto selector) { + return selector().template Type().Case("foo"); + }; + +template +ns::Enum::Foo Parse(Value val, + USERVER_NAMESPACE::formats::parse::To) { + const auto value = val.template As(); + const auto result = kns__Enum__Foo_Mapping.TryFindBySecond(value); + if (result.has_value()) { + return *result; + } + USERVER_NAMESPACE::chaotic::ThrowForValue( + fmt::format("Invalid enum value ({}) for type ns::Enum::Foo", value), + val); +} + +template +ns::Enum Parse(Value value, USERVER_NAMESPACE::formats::parse::To) { + value.CheckNotMissing(); + value.CheckObjectOrNull(); + + ns::Enum res; + + res.foo = value["foo"] + .template As>>(); + + USERVER_NAMESPACE::chaotic::ValidateNoAdditionalProperties( + value, kns__Enum_PropertiesNames); + + return res; +} + +} // namespace ns diff --git a/chaotic/golden_tests/schemas/int_enum/int_enum.yaml b/chaotic/golden_tests/schemas/int_enum/int_enum.yaml new file mode 100644 index 000000000000..83618e8daa7d --- /dev/null +++ b/chaotic/golden_tests/schemas/int_enum/int_enum.yaml @@ -0,0 +1,14 @@ +components: + schemas: + Enum: + type: object + additionalProperties: false + properties: + foo: + type: integer + enum: [ 0, 1, 2, 3, 5] + x-enum-varnames: + - Inner + - Left + - Right + - Outer From 9ddba79fe70aa9dfcfde560e20e682103f52bb55 Mon Sep 17 00:00:00 2001 From: Sergey Alexeev Date: Thu, 10 Oct 2024 08:52:00 +0300 Subject: [PATCH 3/4] support for x-enum-varnames in chaotic with test fix (int_enum.hpp) --- .../output/schemas/int_enum/int_enum.hpp | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/chaotic/golden_tests/output/schemas/int_enum/int_enum.hpp b/chaotic/golden_tests/output/schemas/int_enum/int_enum.hpp index e1c3512b7aa4..7b8b034781b9 100644 --- a/chaotic/golden_tests/output/schemas/int_enum/int_enum.hpp +++ b/chaotic/golden_tests/output/schemas/int_enum/int_enum.hpp @@ -3,7 +3,6 @@ #include "int_enum_fwd.hpp" #include -#include #include @@ -11,15 +10,19 @@ namespace ns { struct Enum { enum class Foo { - kOne, - kTwo, - kThree, + kInner = 0, // Inner + kLeft = 1, // Left + kRight = 2, // Right + kOuter = 3, // Outer + k5 = 5, // 5 }; static constexpr Foo kFooValues[] = { - Foo::kOne, - Foo::kTwo, - Foo::kThree, + Foo::kInner, + Foo::kLeft, + Foo::kRight, + Foo::kOuter, + Foo::k5, }; std::optional foo{}; @@ -51,12 +54,6 @@ Enum::Foo Parse(USERVER_NAMESPACE::yaml_config::Value json, Enum Parse(USERVER_NAMESPACE::yaml_config::Value json, USERVER_NAMESPACE::formats::parse::To); -Enum::Foo FromString(std::string_view value, - USERVER_NAMESPACE::formats::parse::To); - -Enum::Foo Parse(std::string_view value, - USERVER_NAMESPACE::formats::parse::To); - USERVER_NAMESPACE::formats::json::Value Serialize( const ns::Enum::Foo& value, USERVER_NAMESPACE::formats::serialize::To< USERVER_NAMESPACE::formats::json::Value>); @@ -65,6 +62,4 @@ USERVER_NAMESPACE::formats::json::Value Serialize( const ns::Enum& value, USERVER_NAMESPACE::formats::serialize::To< USERVER_NAMESPACE::formats::json::Value>); -std::string ToString(ns::Enum::Foo value); - -} // namespace ns +} // namespace ns \ No newline at end of file From 6bc1f20e5ebe3dd944bea7eb49b816749d147716 Mon Sep 17 00:00:00 2001 From: Sergey Alexeev Date: Thu, 10 Oct 2024 09:02:21 +0300 Subject: [PATCH 4/4] support for x-enum-varnames in chaotic with test fix (remove duplicated files) --- .../schemas/schemas/int_enum/int_enum.cpp | 81 ------------------- .../schemas/schemas/int_enum/int_enum.hpp | 65 --------------- .../schemas/schemas/int_enum/int_enum_fwd.hpp | 7 -- .../schemas/int_enum/int_enum_parsers.ipp | 63 --------------- 4 files changed, 216 deletions(-) delete mode 100644 chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum.cpp delete mode 100644 chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum.hpp delete mode 100644 chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum_fwd.hpp delete mode 100644 chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum_parsers.ipp diff --git a/chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum.cpp b/chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum.cpp deleted file mode 100644 index ebad2ddd460a..000000000000 --- a/chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "int_enum.hpp" - -#include - -#include "int_enum_parsers.ipp" - -namespace ns { - -bool operator==(const ns::Enum& lhs, const ns::Enum& rhs) { - return lhs.foo == rhs.foo && true; -} - -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, const ns::Enum::Foo& value) { - return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value) - .ExtractValue()); -} - -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, const ns::Enum& value) { - return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value) - .ExtractValue()); -} - -Enum::Foo Parse(USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); -} - -Enum Parse(USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); -} - -Enum::Foo Parse(USERVER_NAMESPACE::formats::yaml::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); -} - -Enum Parse(USERVER_NAMESPACE::formats::yaml::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); -} - -Enum::Foo Parse(USERVER_NAMESPACE::yaml_config::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); -} - -Enum Parse(USERVER_NAMESPACE::yaml_config::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); -} - -USERVER_NAMESPACE::formats::json::Value Serialize( - const ns::Enum::Foo& value, USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value> - to) { - const auto result = kns__Enum__Foo_Mapping.TryFindByFirst(value); - if (result.has_value()) { - return Serialize(*result, to); - } - throw std::runtime_error("Bad enum value"); -} - -USERVER_NAMESPACE::formats::json::Value Serialize( - [[maybe_unused]] const ns::Enum& value, - USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value>) { - USERVER_NAMESPACE::formats::json::ValueBuilder vb = - USERVER_NAMESPACE::formats::common::Type::kObject; - - if (value.foo) { - vb["foo"] = - USERVER_NAMESPACE::chaotic::Primitive{*value.foo}; - } - - return vb.ExtractValue(); -} - -} // namespace ns diff --git a/chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum.hpp b/chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum.hpp deleted file mode 100644 index 7b8b034781b9..000000000000 --- a/chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum.hpp +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include "int_enum_fwd.hpp" - -#include - -#include - -namespace ns { - -struct Enum { - enum class Foo { - kInner = 0, // Inner - kLeft = 1, // Left - kRight = 2, // Right - kOuter = 3, // Outer - k5 = 5, // 5 - }; - - static constexpr Foo kFooValues[] = { - Foo::kInner, - Foo::kLeft, - Foo::kRight, - Foo::kOuter, - Foo::k5, - }; - - std::optional foo{}; -}; - -bool operator==(const ns::Enum& lhs, const ns::Enum& rhs); - -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, const ns::Enum::Foo& value); - -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, const ns::Enum& value); - -Enum::Foo Parse(USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To); - -Enum Parse(USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To); - -Enum::Foo Parse(USERVER_NAMESPACE::formats::yaml::Value json, - USERVER_NAMESPACE::formats::parse::To); - -Enum Parse(USERVER_NAMESPACE::formats::yaml::Value json, - USERVER_NAMESPACE::formats::parse::To); - -Enum::Foo Parse(USERVER_NAMESPACE::yaml_config::Value json, - USERVER_NAMESPACE::formats::parse::To); - -Enum Parse(USERVER_NAMESPACE::yaml_config::Value json, - USERVER_NAMESPACE::formats::parse::To); - -USERVER_NAMESPACE::formats::json::Value Serialize( - const ns::Enum::Foo& value, USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value>); - -USERVER_NAMESPACE::formats::json::Value Serialize( - const ns::Enum& value, USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value>); - -} // namespace ns \ No newline at end of file diff --git a/chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum_fwd.hpp b/chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum_fwd.hpp deleted file mode 100644 index fe76c3d643b8..000000000000 --- a/chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum_fwd.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -namespace ns { - -struct Enum; - -} // namespace ns diff --git a/chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum_parsers.ipp b/chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum_parsers.ipp deleted file mode 100644 index 519d374d130c..000000000000 --- a/chaotic/golden_tests/output/schemas/schemas/int_enum/int_enum_parsers.ipp +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once - -#include "int_enum.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ns { - -static constexpr USERVER_NAMESPACE::utils::TrivialBiMap kns__Enum__Foo_Mapping = - [](auto selector) { - return selector() - .template Type() - .Case(ns::Enum::Foo::kInner, 0) - .Case(ns::Enum::Foo::kLeft, 1) - .Case(ns::Enum::Foo::kRight, 2) - .Case(ns::Enum::Foo::kOuter, 3) - .Case(ns::Enum::Foo::k5, 5); - }; - -static constexpr USERVER_NAMESPACE::utils::TrivialSet - kns__Enum_PropertiesNames = [](auto selector) { - return selector().template Type().Case("foo"); - }; - -template -ns::Enum::Foo Parse(Value val, - USERVER_NAMESPACE::formats::parse::To) { - const auto value = val.template As(); - const auto result = kns__Enum__Foo_Mapping.TryFindBySecond(value); - if (result.has_value()) { - return *result; - } - USERVER_NAMESPACE::chaotic::ThrowForValue( - fmt::format("Invalid enum value ({}) for type ns::Enum::Foo", value), - val); -} - -template -ns::Enum Parse(Value value, USERVER_NAMESPACE::formats::parse::To) { - value.CheckNotMissing(); - value.CheckObjectOrNull(); - - ns::Enum res; - - res.foo = value["foo"] - .template As>>(); - - USERVER_NAMESPACE::chaotic::ValidateNoAdditionalProperties( - value, kns__Enum_PropertiesNames); - - return res; -} - -} // namespace ns