Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
RELEASE_TYPE: patch

Internal refactor of `one_of`.
52 changes: 23 additions & 29 deletions include/hegel/generators/combinators.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>{
std::move(schema),
Expand Down Expand Up @@ -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 <typename... Ts>
class VariantGenerator : public IGenerator<std::variant<Ts...>> {
public:
Expand All @@ -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...); },
Expand Down Expand Up @@ -320,10 +311,13 @@ namespace hegel::generators {
[parse = std::move(parse)](
const hegel::internal::json::json_raw_ref& raw)
-> std::optional<T> {
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<size_t>(raw[0].get_int64_t());
if (idx == 0) {
return std::nullopt;
}
return parse(raw);
return parse(raw[1]);
}};
}

Expand Down
12 changes: 6 additions & 6 deletions nix/flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion nix/flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
4 changes: 2 additions & 2 deletions src/connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/installer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down
Loading