message/pack: Allow packing payloads

Some IPMI handlers need the ability to support variable return types.
The easiest way to do that is to be able to return payloads and pack
them into the final payload.

Change-Id: I5098a1ab0998ada712096929eae40a3c88a6dea0
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/include/ipmid/message/pack.hpp b/include/ipmid/message/pack.hpp
index 388bf2f..598e650 100644
--- a/include/ipmid/message/pack.hpp
+++ b/include/ipmid/message/pack.hpp
@@ -280,6 +280,22 @@
     }
 };
 
+/** @brief Specialization of PackSingle for Payload */
+template <>
+struct PackSingle<Payload>
+{
+    static int op(Payload& p, const Payload& t)
+    {
+        if (p.bitCount != 0 || t.bitCount != 0)
+        {
+            return 1;
+        }
+        p.raw.reserve(p.raw.size() + t.raw.size());
+        p.raw.insert(p.raw.end(), t.raw.begin(), t.raw.end());
+        return 0;
+    }
+};
+
 } // namespace details
 
 } // namespace message
diff --git a/test/message/pack.cpp b/test/message/pack.cpp
index 939b356..7fb67ba 100644
--- a/test/message/pack.cpp
+++ b/test/message/pack.cpp
@@ -282,6 +282,30 @@
     ASSERT_EQ(p.raw, k);
 }
 
+TEST(PackBasics, Payload)
+{
+    ipmi::message::Payload p;
+    EXPECT_EQ(p.pack(true), 0);
+    EXPECT_EQ(p.pack(ipmi::message::Payload({0x24, 0x30})), 0);
+    EXPECT_EQ(p.raw, std::vector<uint8_t>({0b1, 0x24, 0x30}));
+}
+
+TEST(PackBasics, PayloadUnaligned)
+{
+    ipmi::message::Payload p;
+    EXPECT_EQ(p.pack(true, ipmi::message::Payload({0x24})), 1);
+    EXPECT_EQ(p.raw, std::vector<uint8_t>({0b1}));
+}
+
+TEST(PackBasics, PayloadOtherUnaligned)
+{
+    ipmi::message::Payload p, q;
+    q.appendBits(1, 1);
+    EXPECT_EQ(p.pack(true), 0);
+    EXPECT_EQ(p.pack(q), 1);
+    EXPECT_EQ(p.raw, std::vector<uint8_t>({0b1}));
+}
+
 TEST(PackAdvanced, Uints)
 {
     // all elements will be processed in order, with each multi-byte