Skip to content

Commit 2aab682

Browse files
authored
Fix converting a pair of pairs to JSON using json_auto templates (#1767)
Fixes: #1768 Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
1 parent f0f4314 commit 2aab682

File tree

2 files changed

+43
-11
lines changed

2 files changed

+43
-11
lines changed

src/core/json/include/sourcemeta/core/json_auto.h

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33

44
#include <sourcemeta/core/json_value.h>
55

6-
#include <concepts> // std::same_as, std::constructible_from
7-
#include <functional> // std::function
8-
#include <optional> // std::optional
9-
#include <tuple> // std::tuple, std::apply
10-
#include <type_traits> // std::false_type, std::true_type, std::void_t, std::is_enum_v, std::underlying_type_t, std::is_same_v
6+
#include <concepts> // std::same_as, std::constructible_from
7+
#include <functional> // std::function
8+
#include <optional> // std::optional
9+
#include <tuple> // std::tuple, std::apply, std::tuple_element_t, std::tuple_size, std::tuple_size_v
10+
#include <type_traits> // std::false_type, std::true_type, std::void_t, std::is_enum_v, std::underlying_type_t, std::is_same_v, std::is_base_of_v, std::remove_cvref_t
1111
#include <utility> // std::pair
1212

1313
namespace sourcemeta::core {
@@ -203,17 +203,37 @@ auto to_json(
203203
template <typename L, typename R>
204204
auto to_json(const std::pair<L, R> &value) -> JSON {
205205
auto tuple{JSON::make_array()};
206-
tuple.push_back(to_json<L>(value.first));
207-
tuple.push_back(to_json<R>(value.second));
206+
tuple.push_back(to_json(value.first));
207+
tuple.push_back(to_json(value.second));
208208
return tuple;
209209
}
210210

211+
// Handle 1-element tuples
211212
/// @ingroup json
212-
template <typename... Args>
213-
auto to_json(const std::tuple<Args...> &value) -> JSON {
214-
auto tuple{JSON::make_array()};
213+
template <typename T>
214+
requires(std::tuple_size_v<std::remove_cvref_t<std::tuple<T>>> == 1)
215+
auto to_json(const std::tuple<T> &value) -> JSON {
216+
auto tuple = JSON::make_array();
217+
std::apply([&](const T &element) { tuple.push_back(to_json(element)); },
218+
value);
219+
return tuple;
220+
}
221+
222+
// We have to do this mess because MSVC seems confuses `std::pair`
223+
// of 2 elements with this overload
224+
/// @ingroup json
225+
template <typename TupleT>
226+
requires(requires {
227+
typename std::tuple_size<std::remove_cvref_t<TupleT>>::type;
228+
} && (std::tuple_size_v<std::remove_cvref_t<TupleT>> >= 2) &&
229+
(!std::is_base_of_v<
230+
std::pair<std::tuple_element_t<0, std::remove_cvref_t<TupleT>>,
231+
std::tuple_element_t<1, std::remove_cvref_t<TupleT>>>,
232+
std::remove_cvref_t<TupleT>>))
233+
auto to_json(const TupleT &value) -> JSON {
234+
auto tuple = JSON::make_array();
215235
std::apply(
216-
[&tuple](const Args &...elements) {
236+
[&tuple](const auto &...elements) {
217237
(tuple.push_back(to_json(elements)), ...);
218238
},
219239
value);

test/json/json_to_json_test.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,18 @@ TEST(JSON_to_json, pair) {
173173
EXPECT_EQ(result, expected);
174174
}
175175

176+
TEST(JSON_to_json, pair_with_pair) {
177+
const std::pair<sourcemeta::core::JSON::Type,
178+
std::pair<sourcemeta::core::JSON::Type, std::size_t>>
179+
value{sourcemeta::core::JSON::Type::String,
180+
{sourcemeta::core::JSON::Type::String, 5}};
181+
182+
const auto result{sourcemeta::core::to_json(value)};
183+
const auto expected{
184+
sourcemeta::core::parse_json(R"JSON([ 4, [ 4, 5 ] ])JSON")};
185+
EXPECT_EQ(result, expected);
186+
}
187+
176188
TEST(JSON_to_json, tuple_1) {
177189
const std::tuple<std::string> value{"foo"};
178190
const auto result{sourcemeta::core::to_json(value)};

0 commit comments

Comments
 (0)