sdbus++: async: server: generate signal emit fns

Populate enough of the generator to define the basic class structure
and generate bindings for emitting signals.

Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: If62c323f460fc8c73a3aca495e5b89cd84bab32a
diff --git a/tools/meson.build b/tools/meson.build
index 8570394..8e1e631 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -28,6 +28,9 @@
   'sdbusplus/templates/property.server.cpp.mako',
   'sdbusplus/templates/property.server.vtable.cpp.mako',
   'sdbusplus/templates/signal.md.mako',
+  'sdbusplus/templates/signal.aserver.emit.hpp.mako',
+  'sdbusplus/templates/signal.aserver.typeid.hpp.mako',
+  'sdbusplus/templates/signal.aserver.vtable.hpp.mako',
   'sdbusplus/templates/signal.prototype.hpp.mako',
   'sdbusplus/templates/signal.server.vtable.cpp.mako',
 )
diff --git a/tools/sdbusplus/templates/interface.aserver.hpp.mako b/tools/sdbusplus/templates/interface.aserver.hpp.mako
index e69de29..1ec817a 100644
--- a/tools/sdbusplus/templates/interface.aserver.hpp.mako
+++ b/tools/sdbusplus/templates/interface.aserver.hpp.mako
@@ -0,0 +1,95 @@
+#pragma once
+#include <sdbusplus/async/server.hpp>
+#include <sdbusplus/server/interface.hpp>
+
+#include <type_traits>
+
+% for h in interface.cpp_includes():
+#include <${h}>
+% endfor
+#include <${interface.headerFile()}>
+
+namespace sdbusplus::aserver::${interface.cppNamespace()}
+{
+
+namespace details
+{
+// forward declaration
+template <typename Instance, typename Server>
+class ${interface.classname};
+} // namespace details
+
+template <typename Instance, typename Server = void>
+struct ${interface.classname} :
+    public std::conditional_t<
+        std::is_void_v<Server>,
+        sdbusplus::async::server_t<Instance, details::${interface.classname}>,
+        details::${interface.classname}<Instance, Server>>
+{
+    template <typename... Args>
+    ${interface.classname}(Args&&... args) :
+        std::conditional_t<
+            std::is_void_v<Server>,
+            sdbusplus::async::server_t<Instance, details::${interface.classname}>,
+            details::${interface.classname}<Instance, Server>>(std::forward<Args>(args)...)
+    {}
+};
+
+namespace details
+{
+
+template <typename Instance, typename Server>
+class ${interface.classname} :
+    public sdbusplus::common::${interface.cppNamespacedClass()},
+    protected sdbusplus::async::server::details::server_context_friend
+{
+  public:
+    explicit ${interface.classname}(const char* path) :
+        _${interface.joinedName("_", "interface")}(
+            _context(), path, interface, _vtable, this)
+    {}
+
+% for s in interface.signals:
+${s.render(loader, "signal.aserver.emit.hpp.mako", signal=s, interface=interface)}
+% endfor
+
+    /** @brief Emit interface added */
+    void emit_added()
+    {
+        _${interface.joinedName("_", "interface")}.emit_added();
+    }
+
+    /** @brief Emit interface removed */
+    void emit_removed()
+    {
+        _${interface.joinedName("_", "interface")}.emit_removed();
+    }
+
+  private:
+    /** @return the async context */
+    sdbusplus::async::context& _context()
+    {
+        return sdbusplus::async::server::details::server_context_friend::
+            context<Server>();
+    }
+
+    sdbusplus::server::interface_t
+        _${interface.joinedName("_", "interface")};
+
+% for s in interface.signals:
+${s.render(loader, "signal.aserver.typeid.hpp.mako", signal=s, interface=interface)}\
+% endfor
+
+    static constexpr sdbusplus::vtable_t _vtable[] = {
+        vtable::start(),
+
+% for s in interface.signals:
+${s.render(loader, "signal.aserver.vtable.hpp.mako", signal=s, interface=interface)}\
+% endfor
+
+        vtable::end(),
+    };
+};
+
+} // namespace details
+} // namespace sdbusplus::aserver::${interface.cppNamespace()}
diff --git a/tools/sdbusplus/templates/signal.aserver.emit.hpp.mako b/tools/sdbusplus/templates/signal.aserver.emit.hpp.mako
new file mode 100644
index 0000000..797c428
--- /dev/null
+++ b/tools/sdbusplus/templates/signal.aserver.emit.hpp.mako
@@ -0,0 +1,39 @@
+<%
+    def parameters():
+        return ",\n            ".\
+            join([ parameter(p) for p in signal.properties ])
+
+    def parameter(p):
+        r = "%s %s%s" % \
+            (p.cppTypeParam(interface.name), p.camelCase, default_value(p))
+        return r
+
+    def parameters_as_list():
+        return ", ".join([ p.camelCase for p in signal.properties ])
+
+    def default_value(p):
+        if p.defaultValue != None:
+            return " = " + str(p.defaultValue)
+        else:
+            return ""
+%>\
+    /** @brief Send signal '${signal.name}'
+     *
+     *  ${ signal.description.strip() }
+% if len(signal.properties) != 0:
+     *
+    % for p in signal.properties:
+     *  @param[in] ${p.camelCase} - ${p.description.strip()}
+    % endfor
+% endif
+     *
+     */
+    void ${signal.camelCase}(${parameters()})
+    {
+        auto m = _${interface.joinedName("_", "interface")}
+                     .new_signal(\
+"${signal.name}");
+
+        m.append(${parameters_as_list()});
+        m.signal_send();
+    }
diff --git a/tools/sdbusplus/templates/signal.aserver.typeid.hpp.mako b/tools/sdbusplus/templates/signal.aserver.typeid.hpp.mako
new file mode 100644
index 0000000..4f24175
--- /dev/null
+++ b/tools/sdbusplus/templates/signal.aserver.typeid.hpp.mako
@@ -0,0 +1,3 @@
+    static constexpr auto _signal_typeid_${signal.snake_case} =
+        utility::tuple_to_array(message::types::type_id<\
+${ ", ".join( [ p.cppTypeParam(interface.name, full=True) for p in signal.properties ]) }>());
diff --git a/tools/sdbusplus/templates/signal.aserver.vtable.hpp.mako b/tools/sdbusplus/templates/signal.aserver.vtable.hpp.mako
new file mode 100644
index 0000000..f17b10b
--- /dev/null
+++ b/tools/sdbusplus/templates/signal.aserver.vtable.hpp.mako
@@ -0,0 +1,3 @@
+        vtable::signal(
+            "${signal.name}",
+            _signal_typeid_${signal.snake_case}.data()),