diff --git a/libs/internal/include/launchdarkly/serialization/json_flag.hpp b/libs/internal/include/launchdarkly/serialization/json_flag.hpp index ec5a5604c..49b4f8cf0 100644 --- a/libs/internal/include/launchdarkly/serialization/json_flag.hpp +++ b/libs/internal/include/launchdarkly/serialization/json_flag.hpp @@ -7,6 +7,9 @@ namespace launchdarkly { +struct VariationOrRolloutContext {}; + + tl::expected, JsonError> tag_invoke( boost::json::value_to_tag< tl::expected, @@ -69,6 +72,11 @@ void tag_invoke(boost::json::value_from_tag const& unused, 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, diff --git a/libs/internal/include/launchdarkly/serialization/value_mapping.hpp b/libs/internal/include/launchdarkly/serialization/value_mapping.hpp index 69ad964fe..2758de0f8 100644 --- a/libs/internal/include/launchdarkly/serialization/value_mapping.hpp +++ b/libs/internal/include/launchdarkly/serialization/value_mapping.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -189,6 +190,25 @@ void WriteMinimal(boost::json::object& obj, } } +template +void WriteMinimal(boost::json::object& obj, + std::string const& key, + T const& val, + std::function 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); diff --git a/libs/internal/src/serialization/json_flag.cpp b/libs/internal/src/serialization/json_flag.cpp index 404ee1def..2331af82b 100644 --- a/libs/internal/src/serialization/json_flag.cpp +++ b/libs/internal/src/serialization/json_flag.cpp @@ -255,7 +255,7 @@ void tag_invoke(boost::json::value_from_tag const& unused, void tag_invoke( 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) { @@ -273,6 +273,13 @@ void tag_invoke( 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) { @@ -364,7 +371,7 @@ void tag_invoke(boost::json::value_from_tag const& unused, } }, flag.fallthrough); - }); + }, VariationOrRolloutContext()); WriteMinimal(obj, "clientSideAvailability", flag.clientSideAvailability, [&]() { return flag.clientSideAvailability.usingEnvironmentId || diff --git a/libs/internal/tests/data_model_serialization_test.cpp b/libs/internal/tests/data_model_serialization_test.cpp index 709af98f6..563d2e5f9 100644 --- a/libs/internal/tests/data_model_serialization_test.cpp +++ b/libs/internal/tests/data_model_serialization_test.cpp @@ -423,8 +423,13 @@ TEST(RolloutTests, SerializeAllFields) { 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); } @@ -438,8 +443,15 @@ TEST(VariationOrRolloutTests, SerializeRollout) { 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); + //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":{