Add event framework

Introduce the concept of events, where the existing Dbus signal
match event is one of many possible event classes.

Change-Id: I9b0c6ca12daaa109f8ceb537a5fb0cc6b5f7181b
Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com>
diff --git a/events.hpp b/events.hpp
index e2a87e3..30fb24f 100644
--- a/events.hpp
+++ b/events.hpp
@@ -22,6 +22,55 @@
 using Filter = holder::CallableHolder<
     T, bool, sdbusplus::message::message&, Manager&>;
 
+/** @struct Event
+ *  @brief Event object interface.
+ */
+struct Event
+{
+    enum class Type
+    {
+        DBUS_SIGNAL,
+    };
+
+    virtual ~Event() = default;
+    Event(const Event&) = default;
+    Event& operator=(const Event&) = default;
+    Event(Event&&) = default;
+    Event& operator=(Event&&) = default;
+    explicit Event(Type t) : type(t) {}
+
+    Type type;
+};
+
+using EventBasePtr = std::shared_ptr<Event>;
+
+/** @struct DbusSignal
+ *  @brief DBus signal event.
+ *
+ *  DBus signal events are an association of a match signature
+ *  and filtering function object.
+ */
+struct DbusSignal final :
+    public Event,
+    public std::tuple<const char *, FilterBasePtr>
+{
+    virtual ~DbusSignal() = default;
+    DbusSignal(const DbusSignal&) = default;
+    DbusSignal & operator=(const DbusSignal&) = delete;
+    DbusSignal(DbusSignal&&) = default;
+    DbusSignal& operator=(DbusSignal&&) = default;
+
+    /** @brief Import from signature and filter constructor.
+     *
+     *  @param[in] sig - The DBus match signature.
+     *  @param[in] filter - A DBus signal match callback filtering function.
+     */
+    DbusSignal(const char *sig, FilterBasePtr filter) :
+        Event(Type::DBUS_SIGNAL),
+        std::tuple<const char *, FilterBasePtr>(
+                sig, std::move(filter)) {}
+};
+
 /** @brief make_filter
  *
  *  Adapt a filter function object.
diff --git a/generated.mako.cpp b/generated.mako.cpp
index 862b3b2..2dccf82 100644
--- a/generated.mako.cpp
+++ b/generated.mako.cpp
@@ -38,6 +38,7 @@
         // ${e['description']}
     % endif
         std::make_tuple(
+            std::make_shared<details::DbusSignal>(
         % for i, s in enumerate(e['signature'].items()):
             % if i + 1 == len(e['signature']):
             ${'"{0}=\'{1}\'"'.format(*s)},
@@ -46,16 +47,16 @@
             % endif
         % endfor
             % if e['filter'].get('args'):
-            details::make_filter(filters::${e['filter']['type']}(
+                details::make_filter(filters::${e['filter']['type']}(
                 % for i, a in enumerate(e['filter']['args']):
                     % if i + 1 == len(e['filter']['args']):
-                "${a['value']}")),
+                "${a['value']}"))),
                     % else:
                 "${a['value']}",
                     % endif
                 % endfor
             % else:
-            details::make_filter(filters::${e['filter']['type']}),
+                details::make_filter(filters::${e['filter']['type']})),
             % endif
             % if e['action'].get('args'):
             std::vector<details::ActionBasePtr>({details::make_action(actions::${e['action']['type']}(
diff --git a/manager.cpp b/manager.cpp
index cf3c59c..07d3d31 100644
--- a/manager.cpp
+++ b/manager.cpp
@@ -61,6 +61,11 @@
     _manager(sdbusplus::server::manager::manager(_bus, root))
 {
     for (auto &x: _events) {
+        auto pEvent = std::get<0>(x);
+        if (pEvent->type !=
+                details::Event::Type::DBUS_SIGNAL)
+            continue;
+
         // Create a callback context for each event.
         _sigargs.emplace_back(
                 std::make_unique<SigArg>(
@@ -69,10 +74,12 @@
                         &x)));
         // Register our callback and the context for
         // each event.
+        auto &dbusEvent = static_cast<details::DbusSignal &>(
+                *pEvent);
         _matches.emplace_back(
                 sdbusplus::server::match::match(
                     _bus,
-                    std::get<0>(x),
+                    std::get<0>(dbusEvent),
                     details::_signal,
                     _sigargs.back().get()));
     }
@@ -144,8 +151,9 @@
 
 void Manager::signal(sdbusplus::message::message &msg, auto &args)
 {
-    auto &filter = *std::get<1>(args);
-    auto &actions = std::get<2>(args);
+    auto &event = std::get<0>(args);
+    auto &actions = std::get<1>(args);
+    auto &filter = *std::get<1>(static_cast<details::DbusSignal &>(*event));
 
     if(filter(msg, *this)) {
         for (auto &action: actions)
diff --git a/manager.hpp b/manager.hpp
index 5c694b5..c905b8b 100644
--- a/manager.hpp
+++ b/manager.hpp
@@ -94,22 +94,21 @@
     /** @brief Drop an object from DBus. */
     void destroyObject(const char *);
 
-    using Event = std::tuple<
-        const char *,
-        details::FilterBasePtr,
+    using EventInfo = std::tuple<
+        details::EventBasePtr,
         std::vector<details::ActionBasePtr>>;
     using SigArgs = std::vector<
         std::unique_ptr<
             std::tuple<
                 Manager *,
-                const Event *>>>;
+                const EventInfo *>>>;
     using SigArg = SigArgs::value_type::element_type;
 
     private:
     using HolderPtr = std::unique_ptr<details::holder::Base>;
     using InterfaceComposite = std::map<std::string, HolderPtr>;
     using ObjectReferences = std::map<std::string, InterfaceComposite>;
-    using Events = std::vector<Event>;
+    using Events = std::vector<EventInfo>;
     using MakerType = HolderPtr(*)(
             sdbusplus::bus::bus &, const char *);
     using Makers = std::map<std::string, MakerType>;