From 6e4f420788bf2f9e1a6feda4ca5626f2084e6653 Mon Sep 17 00:00:00 2001 From: Andrew Krieger Date: Thu, 9 Feb 2017 16:54:55 -0800 Subject: [PATCH] Detect identity conversion in toDynamic Summary: D4499520 added typedefs to `dynamic` which made it start matching tests for ranges/containers. However, the typedefs are unconditional on the actual contents of the `dynamic`. This made toDynamic(dynamic) select the range-based conversion operator, always, which immediately asserts when trying to do range-based iteration over an Object or a primitive. Add tests to the converters that enable/disable depending on whether the object is already a `dynamic` and early-out in that case. Reviewed By: mzlee Differential Revision: D4538617 fbshipit-source-id: f3a5aafab07946a221dcead782fc27de51afa0a6 --- folly/DynamicConverter.h | 30 +++++++++++++++++++++-------- folly/test/DynamicConverterTest.cpp | 13 +++++++++++++ 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/folly/DynamicConverter.h b/folly/DynamicConverter.h index 19477b28..9ab4f73a 100644 --- a/folly/DynamicConverter.h +++ b/folly/DynamicConverter.h @@ -298,11 +298,23 @@ struct DynamicConstructor { } }; +// identity +template +struct DynamicConstructor< + C, + typename std::enable_if::value>::type> { + static dynamic construct(const C& x) { + return x; + } +}; + // maps -template -struct DynamicConstructor +struct DynamicConstructor< + C, typename std::enable_if< - dynamicconverter_detail::is_map::value>::type> { + !std::is_same::value && + dynamicconverter_detail::is_map::value>::type> { static dynamic construct(const C& x) { dynamic d = dynamic::object; for (auto& pair : x) { @@ -313,12 +325,14 @@ struct DynamicConstructor -struct DynamicConstructor +struct DynamicConstructor< + C, typename std::enable_if< - !dynamicconverter_detail::is_map::value && - !std::is_constructible::value && - dynamicconverter_detail::is_range::value>::type> { + !std::is_same::value && + !dynamicconverter_detail::is_map::value && + !std::is_constructible::value && + dynamicconverter_detail::is_range::value>::type> { static dynamic construct(const C& x) { dynamic d = dynamic::array; for (auto& item : x) { diff --git a/folly/test/DynamicConverterTest.cpp b/folly/test/DynamicConverterTest.cpp index 1029a11c..47165031 100644 --- a/folly/test/DynamicConverterTest.cpp +++ b/folly/test/DynamicConverterTest.cpp @@ -396,3 +396,16 @@ TEST(DynamicConverter, errors) { dynamic d2 = floatOver; EXPECT_THROW(convertTo(d2), std::range_error); } + +TEST(DynamicConverter, partial_dynamics) { + std::vector c{ + dynamic::array(2, 3, 4), dynamic::array(3, 4, 5), + }; + dynamic d = dynamic::array(dynamic::array(2, 3, 4), dynamic::array(3, 4, 5)); + EXPECT_EQ(d, toDynamic(c)); + + std::unordered_map m{{"one", 1}, {"two", 2}}; + + dynamic md = dynamic::object("one", 1)("two", 2); + EXPECT_EQ(md, toDynamic(m)); +} -- 2.34.1