Skip to content

Commit

Permalink
Implement basic_obytestream
Browse files Browse the repository at this point in the history
  • Loading branch information
StarQTius committed May 16, 2024
1 parent eaeb9c5 commit be14202
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 14 deletions.
69 changes: 69 additions & 0 deletions include/upd/basic_obytestream.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#pragma once

#include <algorithm> // IWYU pragma: keep
#include <array>
#include <cstddef>

#include "upd/detail/always_false.hpp"
#include "upd/detail/is_bounded_array.hpp" // IWYU pragma: keep
#include "upd/upd.hpp"

namespace upd {

template<typename Consumer_T, typename Serializer_T>
class basic_obytestream {
public:
basic_obytestream(Consumer_T consumer, Serializer_T serializer) noexcept
: m_consumer{UPD_FWD(consumer)}, m_serializer{UPD_FWD(serializer)} {}

template<typename... Args>
void encode(const Args &...args) {
if constexpr (sizeof...(args) > 1) {
(encode(UPD_FWD(args)), ...);
} else {
encode_one(UPD_FWD(args)...);
}
}

private:
template<typename T>
void encode_one(const T &x) {
if constexpr (std::is_signed_v<T>) {
encode_signed(UPD_FWD(x));
} else if constexpr (std::is_unsigned_v<T>) {
encode_unsigned(UPD_FWD(x));
} else if constexpr (detail::is_bounded_array_v<T>) {
encode_bounded_array(UPD_FWD(x));
} else {
static_assert(UPD_ALWAYS_FALSE, "`T` cannot be serialized");
}
}

template<typename T>
void encode_signed(const T &value) {
auto buf = std::array<std::byte, sizeof value>{};

m_serializer.serialize_signed(UPD_FWD(value), buf.size(), buf.data());
m_consumer = std::copy(buf.begin(), buf.end(), m_consumer);
};

template<typename T>
void encode_unsigned(const T &value) {
auto buf = std::array<std::byte, sizeof value>{};

m_serializer.serialize_unsigned(UPD_FWD(value), buf.size(), buf.data());
m_consumer = std::copy(buf.begin(), buf.end(), m_consumer);
};

template<typename T>
void encode_bounded_array(const T &array) {
for (const auto &value : array) {
encode_one(value);
}
};

Consumer_T m_consumer;
Serializer_T m_serializer;
};

} // namespace upd
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ add_custom_target(check_revamp COMMAND ctest -L check_revamp

add_revamp_test(basic_tuple basic_tuple.cpp)
add_revamp_test(basic_ibytestream basic_ibytestream.cpp)
add_revamp_test(basic_obytestream basic_obytestream.cpp)
add_revamp_test(detail_variadic_clean detail/variadic/clean.cpp)
add_revamp_test(detail_variadic_clip detail/variadic/clip.cpp)
add_revamp_test(literals literals.cpp)
15 changes: 1 addition & 14 deletions test/basic_ibytestream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <utility>
#include <variant>

#include "mock/serializer_interface.hpp"
#include "utility/generators.hpp"
#include "utility/mocking.hpp"
#include <catch2/catch_test_macros.hpp>
Expand All @@ -23,20 +24,6 @@

using namespace fakeit;

struct serializer_interface {
serializer_interface(const serializer_interface &) = delete;
auto operator=(const serializer_interface &) -> serializer_interface & = delete;

serializer_interface(serializer_interface &&) = delete;
auto operator=(serializer_interface &&) -> serializer_interface & = delete;

virtual void serialize_unsigned(std::uintmax_t value, std::size_t size, std::byte *output) = 0;
virtual void serialize_signed(std::intmax_t value, std::size_t size, std::byte *output) = 0;
virtual auto deserialize_unsigned(const std::byte *input, std::size_t size) -> std::uintmax_t = 0;
virtual auto deserialize_signed(const std::byte *input, std::size_t size) -> std::intmax_t = 0;
virtual ~serializer_interface() = default;
};

// NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers)

TEST_CASE("Deserializing a packet...") {
Expand Down
60 changes: 60 additions & 0 deletions test/basic_obytestream.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define UPD_ASSERT(...) \
if (!(__VA_ARGS__)) { \
throw std::exception{}; \
}

#include <any>
#include <iterator>
#include <optional>
#include <utility>
#include <variant>

#include "mock/serializer_interface.hpp"
#include "utility/generators.hpp"
#include "utility/mocking.hpp"
#include <catch2/catch_test_macros.hpp>
#include <catch2/generators/catch_generators_all.hpp>
#include <fakeit.hpp>
#include <upd/basic_ibytestream.hpp>
#include <upd/basic_obytestream.hpp>
#include <upd/basic_tuple.hpp>
#include <upd/detail/assertion.hpp>
#include <upd/detail/variadic/map.hpp>
#include <upd/detail/variadic/max.hpp>
#include <upd/static_vector.hpp>

using namespace fakeit;

// NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers)

TEST_CASE("Serializing a packet...") {
auto storage = std::vector<std::byte>{};
auto mock_serializer = Mock<serializer_interface>{};

auto consumer = std::back_inserter(storage);
auto &serializer = mock_serializer.get();
auto bstream = upd::basic_obytestream<decltype(consumer), decltype(serializer)>{consumer, serializer};

When(Method(mock_serializer, serialize_signed)).AlwaysReturn();
When(Method(mock_serializer, serialize_unsigned)).AlwaysReturn();

SECTION("...containing integers and array of integer") {
int int_array[] = {-1, 2, -3, 4};
unsigned long ulong_array[] = {100, 200};
bstream.encode(int{-64}, (unsigned int)48, int_array, (unsigned short)16, ulong_array, char{1});

Verify(Method(mock_serializer, serialize_signed).Using(-64, sizeof(int), _),
Method(mock_serializer, serialize_unsigned).Using(48, sizeof(unsigned int), _),
Method(mock_serializer, serialize_signed).Using(-1, sizeof(int), _),
Method(mock_serializer, serialize_signed).Using(2, sizeof(int), _),
Method(mock_serializer, serialize_signed).Using(-3, sizeof(int), _),
Method(mock_serializer, serialize_signed).Using(4, sizeof(int), _),
Method(mock_serializer, serialize_unsigned).Using(16, sizeof(unsigned short), _),
Method(mock_serializer, serialize_unsigned).Using(100, sizeof(unsigned long), _),
Method(mock_serializer, serialize_unsigned).Using(200, sizeof(unsigned long), _),
Method(mock_serializer, serialize_signed).Using(1, sizeof(char), _));
}
}

// NOLINTEND(cppcoreguidelines-avoid-magic-numbers)
17 changes: 17 additions & 0 deletions test/mock/serializer_interface.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include <cstdint>

struct serializer_interface {
serializer_interface(const serializer_interface &) = delete;
auto operator=(const serializer_interface &) -> serializer_interface & = delete;

serializer_interface(serializer_interface &&) = delete;
auto operator=(serializer_interface &&) -> serializer_interface & = delete;

virtual void serialize_unsigned(std::uintmax_t value, std::size_t size, std::byte *output) = 0;
virtual void serialize_signed(std::intmax_t value, std::size_t size, std::byte *output) = 0;
virtual auto deserialize_unsigned(const std::byte *input, std::size_t size) -> std::uintmax_t = 0;
virtual auto deserialize_signed(const std::byte *input, std::size_t size) -> std::intmax_t = 0;
virtual ~serializer_interface() = default;
};

0 comments on commit be14202

Please sign in to comment.