match: add utilities for match-rules

Change-Id: I47a8c6044f7275994b124e90984cbd8dbef0f0ed
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
diff --git a/sdbusplus/bus/match.hpp b/sdbusplus/bus/match.hpp
index 8b15750..8a048df 100644
--- a/sdbusplus/bus/match.hpp
+++ b/sdbusplus/bus/match.hpp
@@ -2,6 +2,7 @@
 
 #include <functional>
 #include <memory>
+#include <string>
 #include <sdbusplus/slot.hpp>
 #include <sdbusplus/bus.hpp>
 #include <sdbusplus/message.hpp>
@@ -85,6 +86,47 @@
         }
 };
 
+/** Utilities for defining match rules based on the DBus specification */
+namespace rules
+{
+
+using namespace std::string_literals;
+
+namespace type
+{
+
+inline auto signal() { return "type='signal',"s; }
+inline auto method() { return "type='method',"s; }
+inline auto method_return() { return "type='method_return',"s; }
+inline auto error() { return "type='error',"s; }
+
+} // namespace type
+
+inline auto sender(const std::string& s) { return "sender='"s + s + "',"; }
+inline auto interface(const std::string& s)
+        { return "interface='"s + s + "',"; }
+inline auto member(const std::string& s) { return "member='"s + s + "',"; }
+inline auto path(const std::string& s) { return "path='"s + s + "',"; }
+inline auto path_namespace(const std::string& s)
+        { return "path_namespace='"s + s + "',"; }
+inline auto destination(const std::string& s)
+        { return "destination='"s + s + "',"; }
+inline auto argN(size_t n, const std::string& s)
+        { return "arg"s + std::to_string(n) + "='"s + s + "',"; }
+inline auto argNpath(size_t n, const std::string& s)
+        { return "arg"s + std::to_string(n) + "path='"s + s + "',"; }
+inline auto arg0namespace(const std::string& s)
+        { return "arg0namespace='"s + s + "',"; }
+inline auto eavesdrop() { return "eavesdrop='true',"s; }
+
+inline auto nameOwnerChanged()
+{
+    return "type='signal',"
+           "sender='org.freedesktop.DBus',"
+           "member='NameOwnerChanged',"s;
+}
+
+} // namespace rules
 } // namespace match
 
 using match_t = match::match;
diff --git a/test/bus/match.cpp b/test/bus/match.cpp
index 764392a..12d2336 100644
--- a/test/bus/match.cpp
+++ b/test/bus/match.cpp
@@ -11,11 +11,12 @@
         static constexpr auto busName =
                 "xyz.openbmc_project.sdbusplus.test.Match";
 
-        static constexpr auto matchRule =
-                "type='signal',"
-                "interface=org.freedesktop.DBus,"
-                "member='NameOwnerChanged',"
-                "arg0='xyz.openbmc_project.sdbusplus.test.Match'";
+
+        static auto matchRule()
+        {
+            using namespace sdbusplus::bus::match::rules;
+            return nameOwnerChanged() + argN(0, busName);
+        }
 
         void waitForIt(bool& triggered)
         {
@@ -36,7 +37,7 @@
             return 0;
         };
 
-    sdbusplus::bus::match_t m{bus, matchRule, trigger, &triggered};
+    sdbusplus::bus::match_t m{bus, matchRule().c_str(), trigger, &triggered};
     auto m2 = std::move(m);  // ensure match is move-safe.
 
     waitForIt(triggered);
@@ -56,7 +57,7 @@
             triggered = true;
         };
 
-    sdbusplus::bus::match_t m{bus, matchRule, trigger};
+    sdbusplus::bus::match_t m{bus, matchRule().c_str(), trigger};
     auto m2 = std::move(m);  // ensure match is move-safe.
 
     waitForIt(triggered);
@@ -83,7 +84,7 @@
     };
     BoolHolder b;
 
-    sdbusplus::bus::match_t m{bus, matchRule,
+    sdbusplus::bus::match_t m{bus, matchRule().c_str(),
                               std::bind(std::mem_fn(&BoolHolder::callback),
                                         &b, std::placeholders::_1)};
     auto m2 = std::move(m);  // ensure match is move-safe.