From 508c457688e4be878f75f7951ac2e5e95e7de3a8 Mon Sep 17 00:00:00 2001 From: Vernon Mauery Date: Mon, 8 Apr 2019 10:01:33 -0700 Subject: Add a tuple type for packing At the top level, payload had the ability to pack a tuple, but it did it by splitting it into its parts and packing those individually. But if one of those parts was a tuple, it would fail. This moves the tuple packing code into the packing templates so that it is possible to pack a nested tuple of tuples. Tested-by: newly written tuple unit tests pass Change-Id: Icd80926314072df78b0083a823dcfb46e944e365 Signed-off-by: Vernon Mauery --- include/ipmid/message.hpp | 18 ------------- include/ipmid/message/pack.hpp | 11 ++++++++ test/message/pack.cpp | 61 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 18 deletions(-) diff --git a/include/ipmid/message.hpp b/include/ipmid/message.hpp index 4079eab..030618f 100644 --- a/include/ipmid/message.hpp +++ b/include/ipmid/message.hpp @@ -252,24 +252,6 @@ struct Payload return packRet; } - /** - * @brief pack a tuple of values (of any supported type) into the buffer - * - * This will pack the elements of the tuple as if each one was passed in - * individually, as if passed into the above variadic function. - * - * @tparam Types - the implicitly declared list of the tuple element types - * - * @param t - the tuple of values to pack - * - * @return int - non-zero on pack errors - */ - template - int pack(std::tuple& t) - { - return std::apply([this](Types&... args) { return pack(args...); }, t); - } - /****************************************************************** * Request operations *****************************************************************/ diff --git a/include/ipmid/message/pack.hpp b/include/ipmid/message/pack.hpp index 8a9abe1..4314ac1 100644 --- a/include/ipmid/message/pack.hpp +++ b/include/ipmid/message/pack.hpp @@ -93,6 +93,17 @@ struct PackSingle } }; +/** @brief Specialization of PackSingle for std::tuple */ +template +struct PackSingle> +{ + static int op(Payload& p, const std::tuple& v) + { + return std::apply([&p](const T&... args) { return p.pack(args...); }, + v); + } +}; + /** @brief Specialization of PackSingle for std::string * represented as a UCSD-Pascal style string */ diff --git a/test/message/pack.cpp b/test/message/pack.cpp index 03846c5..d0a738a 100644 --- a/test/message/pack.cpp +++ b/test/message/pack.cpp @@ -156,6 +156,19 @@ TEST(PackBasics, Bitset32) ASSERT_EQ(p.raw, k); } +TEST(PackBasics, Tuple) +{ + // tuples are the new struct, pack a tuple + ipmi::message::Payload p; + auto v = std::make_tuple(static_cast(0x8604), 'A'); + p.pack(v); + // check that the number of bytes matches + ASSERT_EQ(p.size(), sizeof(uint16_t) + sizeof(char)); + // check that the bytes were correctly packed (LSB first) + std::vector k = {0x04, 0x86, 0x41}; + ASSERT_EQ(p.raw, k); +} + TEST(PackBasics, Array4xUint8) { // an array of bytes will be output verbatim, low-order element first @@ -363,3 +376,51 @@ TEST(PackAdvanced, UnalignedBitPacking) std::vector k = {0x96, 0xd2, 0x2a, 0xcd, 0xd3, 0x3b, 0xbc, 0x9d}; ASSERT_EQ(p.raw, k); } + +TEST(PackAdvanced, ComplexOptionalTuple) +{ + constexpr size_t macSize = 6; + // inspired from a real-world case of Get Session Info + constexpr uint8_t handle = 0x23; // handle for active session + constexpr uint8_t maxSessions = 15; // number of possible active sessions + constexpr uint8_t currentSessions = 4; // number of current active sessions + std::optional< // only returned for active session + std::tuple> + activeSession; + std::optional< // only returned for channel type LAN + std::tuple, // MAC address + uint16_t // port + >> + lanSession; + + constexpr uint8_t userID = 7; + constexpr uint8_t priv = 4; + constexpr uint4_t channel = 2; + constexpr uint4_t protocol = 1; + activeSession.emplace(userID, priv, channel, protocol); + constexpr std::array macAddr{0}; + lanSession.emplace(0x0a010105, macAddr, 55327); + + ipmi::message::Payload p; + p.pack(handle, maxSessions, currentSessions, activeSession, lanSession); + ASSERT_EQ(p.size(), sizeof(handle) + sizeof(maxSessions) + + sizeof(currentSessions) + 3 * sizeof(uint8_t) + + sizeof(uint32_t) + sizeof(uint8_t) * macSize + + sizeof(uint16_t)); + uint8_t protocol_channel = + (static_cast(protocol) << 4) | static_cast(channel); + std::vector k = {handle, maxSessions, currentSessions, userID, + priv, protocol_channel, + // ip addr + 0x05, 0x01, 0x01, 0x0a, + // mac addr + 0, 0, 0, 0, 0, 0, + // port + 0x1f, 0xd8}; + ASSERT_EQ(p.raw, k); +} -- cgit v1.2.1