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/example/calculator-aserver.cpp b/example/calculator-aserver.cpp
new file mode 100644
index 0000000..220cda1
--- /dev/null
+++ b/example/calculator-aserver.cpp
@@ -0,0 +1,42 @@
+#include <net/poettering/Calculator/aserver.hpp>
+#include <sdbusplus/async.hpp>
+
+class Calculator :
+ public sdbusplus::aserver::net::poettering::Calculator<Calculator>
+{
+ public:
+ explicit Calculator(sdbusplus::async::context& ctx) :
+ sdbusplus::aserver::net::poettering::Calculator<Calculator>(
+ ctx, "/net/poettering/calculator"),
+ manager(ctx, "/")
+ {
+ ctx.spawn(startup());
+ }
+
+ private:
+ auto startup() -> sdbusplus::async::task<>
+ {
+ ctx.get_bus().request_name("net.poettering.Calculator");
+
+ while (1)
+ {
+ using namespace std::literals;
+ co_await sdbusplus::async::sleep_for(ctx, 10s);
+
+ cleared(42);
+ }
+ co_return;
+ }
+
+ sdbusplus::server::manager_t manager;
+};
+
+int main()
+{
+ sdbusplus::async::context ctx;
+ [[maybe_unused]] Calculator c(ctx);
+
+ ctx.run();
+
+ return 0;
+}
diff --git a/example/meson.build b/example/meson.build
index 75b265c..c7ebf61 100644
--- a/example/meson.build
+++ b/example/meson.build
@@ -65,6 +65,15 @@
)
executable(
+ 'calculator-aserver',
+ 'calculator-aserver.cpp',
+ generated_sources,
+ implicit_include_directories: false,
+ include_directories: include_directories('gen'),
+ dependencies: sdbusplus_dep,
+)
+
+executable(
'calculator-client',
'calculator-client.cpp',
generated_sources,
diff --git a/include/sdbusplus/async/server.hpp b/include/sdbusplus/async/server.hpp
new file mode 100644
index 0000000..b7dfbdc
--- /dev/null
+++ b/include/sdbusplus/async/server.hpp
@@ -0,0 +1,55 @@
+#pragma once
+
+#include <sdbusplus/async/context.hpp>
+#include <sdbusplus/server/manager.hpp>
+#include <sdbusplus/vtable.hpp>
+
+namespace sdbusplus::async
+{
+
+namespace server
+{
+
+namespace details
+{
+struct server_context_friend;
+}
+
+template <typename Instance, template <typename, typename> typename... Types>
+class server :
+ public sdbusplus::async::context_ref,
+ public Types<Instance, server<Instance, Types...>>...
+{
+ public:
+ using Self = server<Instance, Types...>;
+ friend details::server_context_friend;
+
+ server() = delete;
+ explicit server(sdbusplus::async::context& ctx, const char* path) :
+ context_ref(ctx), Types<Instance, Self>(path)...
+ {}
+};
+
+} // namespace server
+
+template <typename Instance, template <typename, typename> typename... Types>
+using server_t = server::server<Instance, Types...>;
+
+namespace server::details
+{
+/* Indirect so that the generated Types can access the server_t's context.
+ *
+ * If P2893 gets into C++26 we could eliminate this because we can set all
+ * the Types as friends directly.
+ */
+struct server_context_friend
+{
+ template <typename T>
+ sdbusplus::async::context& context()
+ {
+ return static_cast<T*>(this)->ctx;
+ }
+};
+} // namespace server::details
+
+} // namespace sdbusplus::async
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()),