message: Support prepending payloads

Needed solely so that we can support adding the necessary
bits for oem and group commands. We shouldn't be using this anywhere
else, which is why it is not generalized to non-payload types.

Change-Id: I6573f981fbe68cebb89abcdfb3de5de5d139e1e0
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/include/ipmid/message.hpp b/include/ipmid/message.hpp
index 9bc1147..92a0c25 100644
--- a/include/ipmid/message.hpp
+++ b/include/ipmid/message.hpp
@@ -257,6 +257,27 @@
         return packRet;
     }
 
+    /**
+     * @brief Prepends another payload to this one
+     *
+     * Avoid using this unless absolutely required since it inserts into the
+     * front of the response payload.
+     *
+     * @param p - The payload to prepend
+     *
+     * @retunr int - non-zero on prepend errors
+     */
+    int prepend(const ipmi::message::Payload& p)
+    {
+        if (bitCount != 0 || p.bitCount != 0)
+        {
+            return 1;
+        }
+        raw.reserve(raw.size() + p.raw.size());
+        raw.insert(raw.begin(), p.raw.begin(), p.raw.end());
+        return 0;
+    }
+
     /******************************************************************
      * Request operations
      *****************************************************************/
@@ -518,6 +539,21 @@
         return payload.pack(t);
     }
 
+    /**
+     * @brief Prepends another payload to this one
+     *
+     * Avoid using this unless absolutely required since it inserts into the
+     * front of the response payload.
+     *
+     * @param p - The payload to prepend
+     *
+     * @retunr int - non-zero on prepend errors
+     */
+    int prepend(const ipmi::message::Payload& p)
+    {
+        return payload.prepend(p);
+    }
+
     Payload payload;
     Context::ptr ctx;
     Cc cc;
diff --git a/test/message/pack.cpp b/test/message/pack.cpp
index 7fb67ba..9e88f2b 100644
--- a/test/message/pack.cpp
+++ b/test/message/pack.cpp
@@ -306,6 +306,32 @@
     EXPECT_EQ(p.raw, std::vector<uint8_t>({0b1}));
 }
 
+TEST(PackBasics, PrependPayload)
+{
+    ipmi::message::Payload p;
+    EXPECT_EQ(p.pack(true), 0);
+    EXPECT_EQ(p.prepend(ipmi::message::Payload({0x24, 0x30})), 0);
+    EXPECT_EQ(p.raw, std::vector<uint8_t>({0x24, 0x30, 0b1}));
+}
+
+TEST(PackBasics, PrependPayloadUnaligned)
+{
+    ipmi::message::Payload p;
+    p.appendBits(1, 1);
+    EXPECT_EQ(p.prepend(ipmi::message::Payload({0x24})), 1);
+    p.drain();
+    EXPECT_EQ(p.raw, std::vector<uint8_t>({0b1}));
+}
+
+TEST(PackBasics, PrependPayloadOtherUnaligned)
+{
+    ipmi::message::Payload p, q;
+    q.appendBits(1, 1);
+    EXPECT_EQ(p.pack(true), 0);
+    EXPECT_EQ(p.prepend(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