types: Add constexpr InAddrAny / IfAddr parser

Change-Id: I08d27f3e52a703d2f3c45a886c69b081ffd69558
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/src/types.hpp b/src/types.hpp
index 70d9e0a..73d2778 100644
--- a/src/types.hpp
+++ b/src/types.hpp
@@ -369,6 +369,34 @@
     }
 };
 
+template <>
+struct ToAddr<InAddrAny>
+{
+    constexpr InAddrAny operator()(std::string_view str) const
+    {
+        if (str.find(':') == str.npos)
+        {
+            return ToAddr<in_addr>{}(str);
+        }
+        return ToAddr<in6_addr>{}(str);
+    }
+};
+
+template <>
+struct ToAddr<IfAddr>
+{
+    constexpr IfAddr operator()(std::string_view str) const
+    {
+        auto pos = str.rfind('/');
+        if (pos == str.npos)
+        {
+            throw std::invalid_argument("Invalid IfAddr");
+        }
+        return {ToAddr<InAddrAny>{}(str.substr(0, pos)),
+                DecodeInt<uint8_t, 10>{}(str.substr(pos + 1))};
+    }
+};
+
 namespace detail
 {
 
diff --git a/test/test_types.cpp b/test/test_types.cpp
index b72ecfa..5c2fa78 100644
--- a/test/test_types.cpp
+++ b/test/test_types.cpp
@@ -181,6 +181,28 @@
               ta("0:1:2:3:4:5:255.168.0.1"));
 }
 
+TEST(ToAddr, InAddrAny)
+{
+    constexpr ToAddr<InAddrAny> ta;
+    EXPECT_EQ((InAddrAny{in_addr{}}), ta("0.0.0.0"));
+    EXPECT_EQ((InAddrAny{in6_addr{}}), ta("::"));
+    EXPECT_EQ((InAddrAny{in6_addr{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 192,
+                                  168, 0, 1}}),
+              ta("::ffff:192.168.0.1"));
+}
+
+TEST(ToAddr, IfAddr)
+{
+    constexpr ToAddr<IfAddr> ta;
+    EXPECT_THROW(ta("10"), std::invalid_argument);
+    EXPECT_THROW(ta("/10"), std::invalid_argument);
+    EXPECT_THROW(ta("0.0.0.0"), std::invalid_argument);
+    EXPECT_THROW(ta("0.0.0.0/"), std::invalid_argument);
+    EXPECT_EQ((IfAddr{in_addr{}, 0}), ta("0.0.0.0/0"));
+    EXPECT_EQ((IfAddr{in_addr{}, 30}), ta("0.0.0.0/30"));
+    EXPECT_EQ((IfAddr{in6_addr{}, 80}), ta("::/80"));
+}
+
 namespace detail
 {