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
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#pragma once

#include <launchdarkly/data_model/flag.hpp>
Expand All @@ -7,6 +7,9 @@

namespace launchdarkly {

struct VariationOrRolloutContext {};
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is effectively a "tag" which can be used as a discriminator.



tl::expected<std::optional<data_model::Flag::Rollout>, JsonError> tag_invoke(
boost::json::value_to_tag<
tl::expected<std::optional<data_model::Flag::Rollout>,
Expand Down Expand Up @@ -69,6 +72,11 @@
boost::json::value& json_value,
data_model::Flag::Rollout const& rollout);

void tag_invoke(
boost::json::value_from_tag const& unused,
boost::json::value& json_value,
data_model::Flag::VariationOrRollout const& variation_or_rollout, const VariationOrRolloutContext&);

void tag_invoke(
boost::json::value_from_tag const& unused,
boost::json::value& json_value,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#pragma once

#include <launchdarkly/detail/serialization/json_primitives.hpp>
Expand All @@ -5,6 +5,7 @@
#include <boost/core/ignore_unused.hpp>
#include <boost/json.hpp>
#include <tl/expected.hpp>
#include <boost/version.hpp>

#include <optional>
#include <type_traits>
Expand Down Expand Up @@ -189,6 +190,25 @@
}
}

template <typename T, typename C>
void WriteMinimal(boost::json::object& obj,
std::string const& key,
T const& val,
std::function<bool()> const& predicate, const C &c) {
if (predicate()) {
// In Boost 1.83 the ability to have a conversion context was added.
// It also introduces the potential for the wrong conversion to be used,
// so for boost 1.83 and greater we use a conversion context to ensure
// the correct serialization is used.
#if BOOST_VERSION >= 108300
obj.emplace(key, boost::json::value_from(val, c));
#else
boost::ignore_unused(c);
obj.emplace(key, boost::json::value_from(val));
#endif
}
}

void WriteMinimal(boost::json::object& obj,
std::string const& key, // No copy when not used.
bool val);
Expand Down
11 changes: 9 additions & 2 deletions libs/internal/src/serialization/json_flag.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#include <boost/json.hpp>
#include <launchdarkly/serialization/json_context_aware_reference.hpp>
#include <launchdarkly/serialization/json_flag.hpp>
Expand Down Expand Up @@ -255,7 +255,7 @@
void tag_invoke(
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the situation arose this function was not getting called for serialization. Instead the standard handling for std::variant was being called. This resulted in the value being directly serialized. So for example 42 instead of {variant: 42}. This would only happen for fallthrough. A rule directly serializes the value into a root field.

boost::json::value_from_tag const& unused,
boost::json::value& json_value,
data_model::Flag::VariationOrRollout const& variation_or_rollout) {
data_model::Flag::VariationOrRollout const& variation_or_rollout, const VariationOrRolloutContext&) {
auto& obj = json_value.emplace_object();
std::visit(
[&obj](auto&& arg) {
Expand All @@ -273,6 +273,13 @@
variation_or_rollout);
}

void tag_invoke(
boost::json::value_from_tag const& unused,
boost::json::value& json_value,
data_model::Flag::VariationOrRollout const& variation_or_rollout) {
tag_invoke(unused, json_value, variation_or_rollout, VariationOrRolloutContext());
}

void tag_invoke(boost::json::value_from_tag const& unused,
boost::json::value& json_value,
data_model::Flag::Prerequisite const& prerequisite) {
Expand Down Expand Up @@ -364,7 +371,7 @@
}
},
flag.fallthrough);
});
}, VariationOrRolloutContext());
WriteMinimal(obj, "clientSideAvailability", flag.clientSideAvailability,
[&]() {
return flag.clientSideAvailability.usingEnvironmentId ||
Expand Down
16 changes: 14 additions & 2 deletions libs/internal/tests/data_model_serialization_test.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#include <gtest/gtest.h>

#include <boost/json/value_from.hpp>
Expand Down Expand Up @@ -423,8 +423,13 @@
TEST(VariationOrRolloutTests, SerializeVariation) {
data_model::Flag::VariationOrRollout variation = 5;

auto json = boost::json::value_from(variation);

//Explanation in value_mapping.hpp.
#if BOOST_VERSION >= 108300
auto json = boost::json::value_from(variation, VariationOrRolloutContext());
#else
auto json = boost::json::value_from(variation);
#endif
auto expected = boost::json::parse(R"({"variation":5})");
EXPECT_EQ(expected, json);
}
Expand All @@ -438,8 +443,15 @@
rollout.seed = 42;
rollout.variations = {
data_model::Flag::Rollout::WeightedVariation::Untracked(1, 2), {3, 4}};
data_model::Flag::VariationOrRollout var_or_roll = rollout;
data_model::Flag::VariationOrRollout var_or_roll;
var_or_roll.emplace<Rollout>(rollout);
//Explanation in value_mapping.hpp.
#if BOOST_VERSION >= 108300
auto json = boost::json::value_from(var_or_roll, VariationOrRolloutContext());
#else
auto json = boost::json::value_from(var_or_roll);
#endif


auto expected = boost::json::parse(R"({
"rollout":{
Expand Down
Loading