diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 0000000..b1adabc --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,3 @@ +RELEASE_TYPE: patch + +Internal refactor of `one_of`. \ No newline at end of file diff --git a/include/hegel/generators/combinators.h b/include/hegel/generators/combinators.h index 935d653..f1f34bc 100644 --- a/include/hegel/generators/combinators.h +++ b/include/hegel/generators/combinators.h @@ -62,21 +62,18 @@ namespace hegel::generators { basics.push_back(std::move(*b)); } - // Tag each branch with its index so the client knows which - // parser to apply. Schema per branch is [constant(i), value]. - hegel::internal::json::json tagged = + // The protocol guarantees `one_of` responses arrive as + // `[index, value]`, so the schema is just the raw children + // without any per-branch tagging. The index tells us which + // branch's parser (which carries any per-branch transforms + // composed in via map()) to apply to the value. + hegel::internal::json::json children = hegel::internal::json::json::array(); - for (size_t i = 0; i < basics.size(); ++i) { - hegel::internal::json::json elements = - hegel::internal::json::json::array(); - elements.push_back(hegel::internal::json::json{ - {"type", "constant"}, {"value", (int64_t)i}}); - elements.push_back(basics[i].schema); - tagged.push_back(hegel::internal::json::json{ - {"type", "tuple"}, {"elements", elements}}); + for (const auto& b : basics) { + children.push_back(b.schema); } hegel::internal::json::json schema = {{"type", "one_of"}, - {"generators", tagged}}; + {"generators", children}}; return BasicGenerator{ std::move(schema), @@ -220,8 +217,9 @@ namespace hegel::generators { } // namespace detail // Concrete IGenerator for variant(). Schema path requires every branch - // to be basic and uses a tagged one_of (same wire format as - // OneOfGenerator, but branches can have heterogeneous types). + // to be basic; uses the same one_of protocol as OneOfGenerator, but + // branches can have heterogeneous types so each branch has its own + // typed parser. template class VariantGenerator : public IGenerator> { public: @@ -242,25 +240,18 @@ namespace hegel::generators { if (!all_basic) return std::nullopt; - hegel::internal::json::json tagged = + // Server returns `[index, value]` for `one_of` schemas, so we + // can emit the children directly without per-branch tagging. + hegel::internal::json::json children = hegel::internal::json::json::array(); - size_t i = 0; std::apply( - [&tagged, &i](const auto&... b) { - ((tagged.push_back(hegel::internal::json::json{ - {"type", "tuple"}, - {"elements", hegel::internal::json::json::array( - {hegel::internal::json::json{ - {"type", "constant"}, - {"value", (int64_t)i}}, - b->schema})}}), - ++i), - ...); + [&children](const auto&... b) { + (children.push_back(b->schema), ...); }, basics); hegel::internal::json::json schema = {{"type", "one_of"}, - {"generators", tagged}}; + {"generators", children}}; auto parsers = std::apply( [](const auto&... b) { return std::make_tuple(b->parse...); }, @@ -320,10 +311,13 @@ namespace hegel::generators { [parse = std::move(parse)]( const hegel::internal::json::json_raw_ref& raw) -> std::optional { - if (raw.is_null()) { + // `one_of` responses arrive as `[index, value]`. Index + // 0 is the null branch, index 1 is the inner value. + size_t idx = static_cast(raw[0].get_int64_t()); + if (idx == 0) { return std::nullopt; } - return parse(raw); + return parse(raw[1]); }}; } diff --git a/nix/flake.lock b/nix/flake.lock index b32d9ef..16cb45c 100644 --- a/nix/flake.lock +++ b/nix/flake.lock @@ -38,17 +38,17 @@ }, "locked": { "dir": "nix", - "lastModified": 1777391584, - "narHash": "sha256-XOjidnAqsGzfF9PdpRaYampqBBW6c8aAiXfDUP32vhw=", - "ref": "refs/tags/v0.4.14", - "rev": "4bbc128836f8b027b3ff77a55b755568d006bd1e", - "revCount": 642, + "lastModified": 1777479227, + "narHash": "sha256-s1JjMvJX3SRebwlSQeo6S99OWIoP0CFuPALvG1itzGw=", + "ref": "refs/tags/v0.5.0", + "rev": "a95da271bb026037d13656b4317a445a308fded3", + "revCount": 653, "type": "git", "url": "https://github.com/hegeldev/hegel-core" }, "original": { "dir": "nix", - "ref": "refs/tags/v0.4.14", + "ref": "refs/tags/v0.5.0", "type": "git", "url": "https://github.com/hegeldev/hegel-core" } diff --git a/nix/flake.nix b/nix/flake.nix index 58a8a28..85e166d 100644 --- a/nix/flake.nix +++ b/nix/flake.nix @@ -4,7 +4,7 @@ inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; flake-compat.url = "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"; - hegel.url = "git+https://github.com/hegeldev/hegel-core?dir=nix&ref=refs/tags/v0.4.14"; + hegel.url = "git+https://github.com/hegeldev/hegel-core?dir=nix&ref=refs/tags/v0.5.0"; }; outputs = diff --git a/src/connection.cpp b/src/connection.cpp index a4b4599..d1c0d40 100644 --- a/src/connection.cpp +++ b/src/connection.cpp @@ -18,8 +18,8 @@ using hegel::internal::json::ImplUtil; namespace hegel::impl { - static constexpr const char* MIN_PROTOCOL_VERSION = "0.10"; - static constexpr const char* MAX_PROTOCOL_VERSION = "0.10"; + static constexpr const char* MIN_PROTOCOL_VERSION = "0.11"; + static constexpr const char* MAX_PROTOCOL_VERSION = "0.11"; static constexpr const char* HANDSHAKE_STRING = "hegel_handshake_start"; Connection::Connection(int read_fd, int write_fd) diff --git a/src/installer.h b/src/installer.h index b004073..a58f430 100644 --- a/src/installer.h +++ b/src/installer.h @@ -12,7 +12,7 @@ namespace hegel::impl { /// hegel-core version that this library is built against. Kept in sync /// with the Rust library's `HEGEL_SERVER_VERSION`. - constexpr const char* HEGEL_SERVER_VERSION = "0.4.14"; + constexpr const char* HEGEL_SERVER_VERSION = "0.5.0"; /// Returns the argv prefix used to invoke the hegel server. ///