diff --git a/src/Utils/Traits.hpp b/src/Utils/Traits.hpp index 6100d5f87..040c12b5c 100644 --- a/src/Utils/Traits.hpp +++ b/src/Utils/Traits.hpp @@ -88,6 +88,7 @@ #include #include #include +#include #include #include #include @@ -638,6 +639,17 @@ template constexpr bool is_uni_member_ptr_v = std::is_member_object_pointer_v>; +struct empty_type { + constexpr empty_type() noexcept = default; + constexpr empty_type(std::nullptr_t) noexcept {} + constexpr empty_type(std::monostate) noexcept {} + constexpr empty_type(std::nullopt_t) noexcept {} + + constexpr operator std::nullptr_t() const noexcept { return {}; } + constexpr operator std::monostate() const noexcept { return {}; } + constexpr operator std::nullopt_t() const noexcept { return std::nullopt; } +} constexpr empty_value; + /** * Safe getter that for pointer to member returns class and original * type in any other case. diff --git a/src/mpp/Constants.hpp b/src/mpp/Constants.hpp index 4aed36729..116ac9b35 100644 --- a/src/mpp/Constants.hpp +++ b/src/mpp/Constants.hpp @@ -306,8 +306,7 @@ struct ExtValue { int8_t type; uint8_t offset; uint32_t size; }; // The order of types must be exactly the same as in compact::Family! using Value_t = std::variant< - std::nullptr_t, bool, uint64_t, int64_t, float, double, - StrValue, BinValue, ArrValue, MapValue, ExtValue ->; + std::nullptr_t, std::monostate, bool, uint64_t, int64_t, float, double, + StrValue, BinValue, ArrValue, MapValue, ExtValue>; } // namespace mpp { diff --git a/src/mpp/Dec.hpp b/src/mpp/Dec.hpp index 70a8162e8..91f51d851 100644 --- a/src/mpp/Dec.hpp +++ b/src/mpp/Dec.hpp @@ -135,7 +135,7 @@ constexpr auto detectFamily() detectFamily>()); } else if constexpr (tnt::is_variant_v) { return detectFamilyVariant(); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_convertible_v) { return family_sequence{}; } else if constexpr (std::is_same_v) { return family_sequence{}; @@ -419,7 +419,7 @@ auto read_value(BUF& buf) tag - RULE::simplex_tag; if constexpr (FAMILY == compact::MP_NIL) - return nullptr; + return tnt::empty_value; else if constexpr (RULE::is_bool) return bool(val); else if constexpr (RULE::is_simplex_log_range) diff --git a/src/mpp/Enc.hpp b/src/mpp/Enc.hpp index f0dda3886..eaf732cbc 100644 --- a/src/mpp/Enc.hpp +++ b/src/mpp/Enc.hpp @@ -76,7 +76,7 @@ constexpr compact::Family detectFamily() using V = std::remove_cv_t>; if constexpr (is_wrapped_family_v) { return T::family; - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_convertible_v) { return compact::MP_NIL; } else if constexpr (std::is_same_v) { return compact::MP_BOOL; diff --git a/src/mpp/Rules.hpp b/src/mpp/Rules.hpp index 7bab27977..e3f4eabec 100644 --- a/src/mpp/Rules.hpp +++ b/src/mpp/Rules.hpp @@ -161,7 +161,7 @@ struct BaseRule { using simplex_value_range_t = RuleRange; }; -struct NilRule : BaseRule { +struct NilRule : BaseRule { static constexpr simplex_value_range_t simplex_value_range = {0, 0}; static constexpr uint8_t simplex_tag = 0xc0; }; diff --git a/test/EncDecTest.cpp b/test/EncDecTest.cpp index 26498a3da..1e2be533b 100644 --- a/test/EncDecTest.cpp +++ b/test/EncDecTest.cpp @@ -1257,7 +1257,7 @@ test_optional() TEST_CASE("number"); mpp::encode(buf, std::optional(100), std::optional(), - std::optional(42)); + std::optional(42), std::nullopt); auto run = buf.begin(); std::optional opt_num; @@ -1275,6 +1275,11 @@ test_optional() fail_unless(opt_num.has_value()); fail_unless(opt_num.value() == 42); + ok = mpp::decode(run, opt_num); + fail_unless(ok); + fail_unless(!opt_num.has_value()); + fail_unless(opt_num == std::nullopt); + buf.flush(); TEST_CASE("containers with numbers"); @@ -1669,6 +1674,14 @@ test_variant() mpp::encode(buf, wr); mpp::decode(run, rd); fail_unless(wr == rd); + + std::variant monostate_wr; + std::variant monostate_rd; + + monostate_wr.emplace<1>(); + mpp::encode(buf, monostate_wr); + mpp::decode(run, monostate_rd); + fail_unless(monostate_wr == monostate_rd); } int main()