sdbus++: create server support functions
Reduce the complexity of the generated bindings by taking the
common patterns and moving them to support template functions.
This has the side-effect of a small space savings a library
of generated bindings.
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: I55d6de0aa8773a68f1a23b1301056ea3435dbbc9
diff --git a/include/sdbusplus/sdbuspp_support/server.hpp b/include/sdbusplus/sdbuspp_support/server.hpp
new file mode 100644
index 0000000..0044e0b
--- /dev/null
+++ b/include/sdbusplus/sdbuspp_support/server.hpp
@@ -0,0 +1,140 @@
+#pragma once
+#include <sdbusplus/message.hpp>
+#include <sdbusplus/server.hpp>
+
+#include <type_traits>
+
+/** This file contains support functions for sdbus++-generated server
+ * bindings, which result in space savings by having common definitions.
+ */
+
+namespace sdbusplus
+{
+namespace sdbuspp
+{
+
+/** Handle common parts of a get/set property callback.
+ *
+ * @param[in] msg The message to read to / write from.
+ * @param[in] intf The SdBusInterface type.
+ * @param[in] error The error object for any errors.
+ * @param[in] f The interface function for the get/set.
+ *
+ * This function will unpack a message's contents, redirect them to the
+ * function 'f', and then pack them into the response message.
+ */
+template <typename... Args, typename Return>
+bool property_callback(sd_bus_message* msg, sdbusplus::SdBusInterface* intf,
+ sd_bus_error* error, std::function<Return(Args&&...)> f)
+{
+ try
+ {
+ // Refcount the message.
+ auto m = message::message(msg, intf);
+
+ // Set up the transaction.
+ auto tbus = m.get_bus();
+ sdbusplus::server::transaction::Transaction t(tbus, m);
+ sdbusplus::server::transaction::set_id(
+ std::hash<sdbusplus::server::transaction::Transaction>{}(t));
+
+ // Read arguments from the message.
+ std::tuple<Args...> arg{};
+ std::apply([&](Args&... a) { (m.read(a), ...); }, arg);
+
+ // Call the function with the arguments.
+ if constexpr (!std::is_same_v<void, Return>)
+ {
+ // Pack results back into message.
+ m.append(std::apply(f, std::move(arg)));
+ }
+ else
+ {
+ // No return, just direct call.
+ std::apply(f, std::move(arg));
+ }
+ }
+ catch (sdbusplus::internal_exception_t& e)
+ {
+ return intf->sd_bus_error_set(error, e.name(), e.description());
+ }
+
+ return true;
+}
+
+/** Handle common parts of a method callback.
+ *
+ * @tparam multi_return Set to true if the function returns multiple results.
+ * Otherwise, this function is unable to differentiate
+ * between a tuple that should be returned as a tuple or
+ * a tuple that contains the multiple results and should
+ * be returned without the tuple wrapper.
+ *
+ * @param[in] msg The message to read to / write from.
+ * @param[in] intf The SdBusInterface type.
+ * @param[in] error The error object for any errors.
+ * @param[in] f The interface function for the get/set.
+ *
+ * @return a negative return-code on error.
+ *
+ * This function will unpack a message's contents, redirect them to the
+ * function 'f', and then pack them into the response message.
+ */
+template <bool multi_return = false, typename... Args, typename Return>
+int method_callback(sd_bus_message* msg, sdbusplus::SdBusInterface* intf,
+ sd_bus_error* error, std::function<Return(Args&&...)> f)
+{
+ try
+ {
+ // Refcount the message.
+ auto m = message::message(msg, intf);
+
+ // Set up the transaction.
+ auto tbus = m.get_bus();
+ sdbusplus::server::transaction::Transaction t(tbus, m);
+ sdbusplus::server::transaction::set_id(
+ std::hash<sdbusplus::server::transaction::Transaction>{}(t));
+
+ // Read arguments from the message.
+ std::tuple<Args...> arg{};
+ std::apply([&](Args&... a) { (m.read(a), ...); }, arg);
+
+ // Get the reply message.
+ auto reply = m.new_method_return();
+
+ // Call the function with the arguments.
+ if constexpr (std::is_same_v<void, Return>)
+ {
+ // No return value, direct call.
+ std::apply(f, std::move(arg));
+ }
+ else if constexpr (!multi_return)
+ {
+ // Single return value; call and append to reply message.
+ reply.append(std::apply(f, std::move(arg)));
+ }
+ else
+ {
+ // Multi return values; call and append to reply message.
+ // Step 1: call 'f' with args from message.
+ // - std::apply(f, std::move(arg))
+ // Step 2: append each return from f into the reply message one
+ // at a time.
+ // - Apply on return from 'f' into lambda that does an append.
+ std::apply([&](auto&&... v) { (reply.append(std::move(v)), ...); },
+ std::apply(f, std::move(arg)));
+ }
+
+ // Indicate reply complete.
+ reply.method_return();
+ }
+ catch (sdbusplus::internal_exception_t& e)
+ {
+ return intf->sd_bus_error_set(error, e.name(), e.description());
+ }
+
+ return 0;
+}
+
+} // namespace sdbuspp
+} // namespace sdbusplus
diff --git a/tools/sdbusplus/method.py b/tools/sdbusplus/method.py
index 3535612..7dbb421 100644
--- a/tools/sdbusplus/method.py
+++ b/tools/sdbusplus/method.py
@@ -47,10 +47,6 @@
[self.parameter(interface, p, defaultValue)
for p in self.parameters])
- def parameters_as_local(self, interface):
- return "{};\n ".join([self.parameter(interface, p)
- for p in self.parameters])
-
def or_cpp_flags(self, flags):
"""Return the corresponding ORed cpp flags."""
flags_dict = {"deprecated": "vtable::common_::deprecated",
diff --git a/tools/sdbusplus/templates/interface.server.cpp.mako b/tools/sdbusplus/templates/interface.server.cpp.mako
index 6a12968..ddb7537 100644
--- a/tools/sdbusplus/templates/interface.server.cpp.mako
+++ b/tools/sdbusplus/templates/interface.server.cpp.mako
@@ -2,6 +2,7 @@
#include <map>
#include <sdbusplus/exception.hpp>
#include <sdbusplus/sdbus.hpp>
+#include <sdbusplus/sdbuspp_support/server.hpp>
#include <sdbusplus/server.hpp>
#include <string>
#include <tuple>
diff --git a/tools/sdbusplus/templates/method.prototype.hpp.mako b/tools/sdbusplus/templates/method.prototype.hpp.mako
index 17c2019..640e74f 100644
--- a/tools/sdbusplus/templates/method.prototype.hpp.mako
+++ b/tools/sdbusplus/templates/method.prototype.hpp.mako
@@ -1,4 +1,6 @@
<%
+ def parameters_as_arg_list():
+ return ", ".join([ parameter(p, ref="&&") for p in method.parameters ])
def parameters_as_list(transform=lambda p: p.camelCase):
return ", ".join([ transform(p) for p in method.parameters ])
@@ -7,10 +9,17 @@
return ", ".join([ p.cppTypeParam(interface.name, full=True)
for p in method.parameters ])
- def returns_as_tuple_index(tuple, pre="", post=""):
- return ", ".join([ "%sstd::move(std::get<%d>(%s))%s" %\
- (pre,i,tuple,post) \
- for i in range(len(method.returns))])
+ def parameter(p, defaultValue=False, ref=""):
+ r = "%s%s %s" % (p.cppTypeParam(interface.name), ref, p.camelCase)
+ if defaultValue:
+ r += default_value(p)
+ return r
+
+ def default_value(p):
+ if p.defaultValue != None:
+ return " = " + str(p.defaultValue)
+ else:
+ return ""
def interface_name():
return interface.name.split('.').pop()
@@ -82,54 +91,34 @@
int ${interface_name()}::_callback_${ method.CamelCase }(
sd_bus_message* msg, void* context, sd_bus_error* error)
{
+ auto o = static_cast<${interface_name()}*>(context);
+
+ % if method.errors:
try
- {
- ### Need to add a ref to msg since we attached it to an
- ### sdbusplus::message.
- auto m = message::message(msg);
- {
- auto tbus = m.get_bus();
- sdbusplus::server::transaction::Transaction t(tbus, m);
- sdbusplus::server::transaction::set_id
- (std::hash<sdbusplus::server::transaction::Transaction>{}(t));
- }
-
- % if len(method.parameters) != 0:
- ${method.parameters_as_local(interface)}{};
-
- m.read(${parameters_as_list()});
% endif
-
- auto o = static_cast<${interface_name()}*>(context);
- % if len(method.returns) != 0:
- auto r = \
- %endif
- o->${ method.camelCase }(${parameters_as_list()});
-
- auto reply = m.new_method_return();
- % if len(method.returns) == 0:
- // No data to append on reply.
- % elif len(method.returns) == 1:
- reply.append(std::move(r));
- % else:
- reply.append(\
-${returns_as_tuple_index("r")});
- % endif
-
- reply.method_return();
- }
- catch(sdbusplus::internal_exception_t& e)
{
- return sd_bus_error_set(error, e.name(), e.description());
+ return sdbusplus::sdbuspp::method_callback\
+ % if len(method.returns) > 1:
+<true>\
+ % endif
+(
+ msg, o->_intf, error,
+ std::function(
+ [=](${parameters_as_arg_list()})
+ {
+ return o->${ method.camelCase }(
+ ${parameters_as_list()});
+ }
+ ));
}
% for e in method.errors:
catch(sdbusplus::${error_namespace(e)}::${error_name(e)}& e)
{
- return sd_bus_error_set(error, e.name(), e.description());
+ return o->_intf->sd_bus_error_set(error, e.name(), e.description());
}
% endfor
- return true;
+ return 0;
}
namespace details
diff --git a/tools/sdbusplus/templates/property.prototype.hpp.mako b/tools/sdbusplus/templates/property.prototype.hpp.mako
index 425dd63..e99eb7d 100644
--- a/tools/sdbusplus/templates/property.prototype.hpp.mako
+++ b/tools/sdbusplus/templates/property.prototype.hpp.mako
@@ -34,21 +34,18 @@
{
auto o = static_cast<${classname}*>(context);
+ % if property.errors:
try
+ % endif
{
- auto m = message::message(reply, o->_intf);
- {
- auto tbus = m.get_bus();
- sdbusplus::server::transaction::Transaction t(tbus, m);
- sdbusplus::server::transaction::set_id
- (std::hash<sdbusplus::server::transaction::Transaction>{}(t));
- }
-
- m.append(o->${property.camelCase}());
- }
- catch(sdbusplus::internal_exception_t& e)
- {
- return o->_intf->sd_bus_error_set(error, e.name(), e.description());
+ return sdbusplus::sdbuspp::property_callback(
+ reply, o->_intf, error,
+ std::function(
+ [=]()
+ {
+ return o->${property.camelCase}();
+ }
+ ));
}
% for e in property.errors:
catch(sdbusplus::${error_namespace(e)}::${error_name(e)}& e)
@@ -56,8 +53,6 @@
return o->_intf->sd_bus_error_set(error, e.name(), e.description());
}
% endfor
-
- return true;
}
auto ${classname}::${property.camelCase}(${property.cppTypeParam(interface.name)} value,
@@ -90,23 +85,18 @@
{
auto o = static_cast<${classname}*>(context);
+ % if property.errors:
try
+ % endif
{
- auto m = message::message(value, o->_intf);
- {
- auto tbus = m.get_bus();
- sdbusplus::server::transaction::Transaction t(tbus, m);
- sdbusplus::server::transaction::set_id
- (std::hash<sdbusplus::server::transaction::Transaction>{}(t));
- }
-
- ${property.cppTypeParam(interface.name)} v{};
- m.read(v);
- o->${property.camelCase}(v);
- }
- catch(sdbusplus::internal_exception_t& e)
- {
- return o->_intf->sd_bus_error_set(error, e.name(), e.description());
+ return sdbusplus::sdbuspp::property_callback(
+ value, o->_intf, error,
+ std::function(
+ [=](${property.cppTypeParam(interface.name)}&& arg)
+ {
+ o->${property.camelCase}(std::move(arg));
+ }
+ ));
}
% for e in property.errors:
catch(sdbusplus::${error_namespace(e)}::${error_name(e)}& e)