message/pack: Support packing string_views

Now we don't need to make an intermediate copy of our data into an array
before packing it into a payload.

Change-Id: Iac79a79e0ae95835cb67d617a966a92ce8dcd5f8
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 deb0a5a..388bf2f 100644
--- a/include/ipmid/message/pack.hpp
+++ b/include/ipmid/message/pack.hpp
@@ -20,6 +20,7 @@
 #include <memory>
 #include <optional>
 #include <phosphor-logging/log.hpp>
+#include <string_view>
 #include <tuple>
 #include <utility>
 #include <variant>
@@ -249,6 +250,22 @@
     }
 };
 
+/** @brief Specialization of PackSingle for std::string_view */
+template <>
+struct PackSingle<std::string_view>
+{
+    static int op(Payload& p, const std::string_view& t)
+    {
+        if (p.bitCount != 0)
+        {
+            return 1;
+        }
+        p.raw.reserve(p.raw.size() + t.size());
+        p.raw.insert(p.raw.end(), t.begin(), t.end());
+        return 0;
+    }
+};
+
 /** @brief Specialization of PackSingle for std::variant<T, N> */
 template <typename... T>
 struct PackSingle<std::variant<T...>>
diff --git a/test/message/pack.cpp b/test/message/pack.cpp
index 7e6cf31..939b356 100644
--- a/test/message/pack.cpp
+++ b/test/message/pack.cpp
@@ -242,6 +242,20 @@
     EXPECT_EQ(p.raw, std::vector<uint8_t>{0b1});
 }
 
+TEST(PackBasics, StringView)
+{
+    ipmi::message::Payload p;
+    EXPECT_EQ(p.pack(std::string_view{"\x24\x30\x11"}), 0);
+    EXPECT_EQ(p.raw, std::vector<uint8_t>({0x24, 0x30, 0x11}));
+}
+
+TEST(PackBasics, StringViewUnaligned)
+{
+    ipmi::message::Payload p;
+    EXPECT_EQ(p.pack(true, std::string_view{"abc"}), 1);
+    EXPECT_EQ(p.raw, std::vector<uint8_t>({0b1}));
+}
+
 TEST(PackBasics, OptionalEmpty)
 {
     // an optional will only pack if the value is present