Skip to content

Commit

Permalink
Enc, Dec: add support for additional standard empty types
Browse files Browse the repository at this point in the history
In addition to `std::nullptr_t`, there are at least 2 more standard empty
types, namely `std::monostate` and `std::nullopt_t`, which should
correspond to `MP_NIL` in the MsgPack codec.

Refactor the codec to support an empty type abstraction, and add
`std::monostate` and `std::nullopt_t` to this abstraction.

Closes #82
  • Loading branch information
CuriousGeorgiy committed Jan 29, 2024
1 parent 7af7f2f commit ccfdc8d
Show file tree
Hide file tree
Showing 6 changed files with 32 additions and 8 deletions.
12 changes: 12 additions & 0 deletions src/Utils/Traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
#include <cstddef>
#include <iterator>
#include <functional>
#include <optional>
#include <tuple>
#include <type_traits>
#include <variant>
Expand Down Expand Up @@ -638,6 +639,17 @@ template <class T>
constexpr bool is_uni_member_ptr_v =
std::is_member_object_pointer_v<uni_integral_base_t<T>>;

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.
Expand Down
5 changes: 2 additions & 3 deletions src/mpp/Constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
4 changes: 2 additions & 2 deletions src/mpp/Dec.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ constexpr auto detectFamily()
detectFamily<BUF, tnt::value_type_t<U>>());
} else if constexpr (tnt::is_variant_v<U>) {
return detectFamilyVariant<BUF, U>();
} else if constexpr (std::is_same_v<U, std::nullptr_t>) {
} else if constexpr (std::is_convertible_v<U, tnt::empty_type>) {
return family_sequence<compact::MP_NIL>{};
} else if constexpr (std::is_same_v<U, bool>) {
return family_sequence<compact::MP_BOOL>{};
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/mpp/Enc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ constexpr compact::Family detectFamily()
using V = std::remove_cv_t<tnt::uni_integral_base_t<U>>;
if constexpr (is_wrapped_family_v<T>) {
return T::family;
} else if constexpr (std::is_same_v<V, std::nullptr_t>) {
} else if constexpr (std::is_convertible_v<V, tnt::empty_type>) {
return compact::MP_NIL;
} else if constexpr (std::is_same_v<V, bool>) {
return compact::MP_BOOL;
Expand Down
2 changes: 1 addition & 1 deletion src/mpp/Rules.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ struct BaseRule {
using simplex_value_range_t = RuleRange<simplex_value_t>;
};

struct NilRule : BaseRule<compact::MP_NIL, std::nullptr_t> {
struct NilRule : BaseRule<compact::MP_NIL, std::nullptr_t, std::monostate> {
static constexpr simplex_value_range_t simplex_value_range = {0, 0};
static constexpr uint8_t simplex_tag = 0xc0;
};
Expand Down
15 changes: 14 additions & 1 deletion test/EncDecTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1257,7 +1257,7 @@ test_optional()

TEST_CASE("number");
mpp::encode(buf, std::optional<int>(100), std::optional<int>(),
std::optional<int>(42));
std::optional<int>(42), std::nullopt);

auto run = buf.begin<true>();
std::optional<int> opt_num;
Expand All @@ -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");
Expand Down Expand Up @@ -1669,6 +1674,14 @@ test_variant()
mpp::encode(buf, wr);
mpp::decode(run, rd);
fail_unless(wr == rd);

std::variant<int, std::monostate, std::string> monostate_wr;
std::variant<int, std::monostate, std::string> monostate_rd;

monostate_wr.emplace<1>();
mpp::encode(buf, monostate_wr);
mpp::decode(run, monostate_rd);
fail_unless(monostate_wr == monostate_rd);
}

int main()
Expand Down

0 comments on commit ccfdc8d

Please sign in to comment.