sdbus++: async: server: generate method-call fn
Add binding generation for method-call functions.
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: I34ac44ae0cdb43a18b96a4ddc5e67df4971da939
diff --git a/example/calculator-aserver.cpp b/example/calculator-aserver.cpp
index 149da86..6dc8579 100644
--- a/example/calculator-aserver.cpp
+++ b/example/calculator-aserver.cpp
@@ -28,6 +28,27 @@
return false;
}
+ auto method_call(multiply_t, auto x, auto y)
+ {
+ auto r = x * y;
+ last_result(r);
+ return r;
+ }
+
+ auto method_call(divide_t, auto x, auto y)
+ -> sdbusplus::async::task<divide_t::return_type>
+ {
+ auto r = x / y;
+ last_result(r);
+ co_return r;
+ }
+
+ auto method_call(clear_t) -> sdbusplus::async::task<>
+ {
+ last_result(0);
+ co_return;
+ }
+
private:
auto startup() -> sdbusplus::async::task<>
{
@@ -36,7 +57,7 @@
status(State::Error);
- while (1)
+ while (!ctx.stop_requested())
{
using namespace std::literals;
co_await sdbusplus::async::sleep_for(ctx, 10s);
diff --git a/include/sdbusplus/async/server.hpp b/include/sdbusplus/async/server.hpp
index 9710d5f..43d023b 100644
--- a/include/sdbusplus/async/server.hpp
+++ b/include/sdbusplus/async/server.hpp
@@ -93,6 +93,24 @@
concept has_set_property = has_set_property_nomsg<Tag, Instance, Arg> ||
has_set_property_msg<Tag, Instance, Arg>;
+/* Determine if a type has a method call. */
+template <typename Tag, typename Instance, typename... Args>
+concept has_method_nomsg = requires(Instance& i, Args&&... a) {
+ i.method_call(Tag{}, std::forward<Args>(a)...);
+ };
+
+/* Determine if a type has a method call that requires a msg. */
+template <typename Tag, typename Instance, typename... Args>
+concept has_method_msg =
+ requires(Instance& i, sdbusplus::message_t& m, Args&&... a) {
+ i.method_call(Tag{}, m, std::forward<Args>(a)...);
+ };
+
+/* Determine if a type has any method call. */
+template <typename Tag, typename Instance, typename... Args>
+concept has_method = has_method_nomsg<Tag, Instance, Args...> ||
+ has_method_msg<Tag, Instance, Args...>;
+
} // namespace server::details
} // namespace sdbusplus::async
diff --git a/tools/meson.build b/tools/meson.build
index 1538289..d290b5f 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -19,8 +19,12 @@
'sdbusplus/templates/interface.md.mako',
'sdbusplus/templates/interface.server.cpp.mako',
'sdbusplus/templates/interface.server.hpp.mako',
- 'sdbusplus/templates/method.md.mako',
+ 'sdbusplus/templates/method.aserver.callback.hpp.mako',
+ 'sdbusplus/templates/method.aserver.tag.hpp.mako',
+ 'sdbusplus/templates/method.aserver.typeid.hpp.mako',
+ 'sdbusplus/templates/method.aserver.vtable.hpp.mako',
'sdbusplus/templates/method.client.hpp.mako',
+ 'sdbusplus/templates/method.md.mako',
'sdbusplus/templates/method.prototype.hpp.mako',
'sdbusplus/templates/method.server.vtable.cpp.mako',
'sdbusplus/templates/property.md.mako',
diff --git a/tools/sdbusplus/templates/interface.aserver.hpp.mako b/tools/sdbusplus/templates/interface.aserver.hpp.mako
index f94ba3b..0c10273 100644
--- a/tools/sdbusplus/templates/interface.aserver.hpp.mako
+++ b/tools/sdbusplus/templates/interface.aserver.hpp.mako
@@ -73,6 +73,11 @@
${p.render(loader, "property.aserver.tag.hpp.mako", property=p, interface=interface)}\
% endfor
+ /* Method tags. */
+% for m in interface.methods:
+${m.render(loader, "method.aserver.tag.hpp.mako", method=m, interface=interface)}\
+% endfor
+
% for p in interface.properties:
${p.render(loader, "property.aserver.get.hpp.mako", property=p, interface=interface)}
% endfor
@@ -98,6 +103,9 @@
% for p in interface.properties:
${p.render(loader, "property.aserver.typeid.hpp.mako", property=p, interface=interface)}\
% endfor
+% for m in interface.methods:
+${m.render(loader, "method.aserver.typeid.hpp.mako", method=m, interface=interface)}\
+% endfor
% for s in interface.signals:
${s.render(loader, "signal.aserver.typeid.hpp.mako", signal=s, interface=interface)}\
% endfor
@@ -106,12 +114,19 @@
${p.render(loader, "property.aserver.callback.hpp.mako", property=p, interface=interface)}
% endfor
+% for m in interface.methods:
+${m.render(loader, "method.aserver.callback.hpp.mako", method=m, interface=interface)}\
+% endfor
+
static constexpr sdbusplus::vtable_t _vtable[] = {
vtable::start(),
% for p in interface.properties:
${p.render(loader, "property.aserver.vtable.hpp.mako", property=p, interface=interface)}\
% endfor
+% for m in interface.methods:
+${m.render(loader, "method.aserver.vtable.hpp.mako", method=m, interface=interface)}\
+% endfor
% for s in interface.signals:
${s.render(loader, "signal.aserver.vtable.hpp.mako", signal=s, interface=interface)}\
% endfor
diff --git a/tools/sdbusplus/templates/method.aserver.callback.hpp.mako b/tools/sdbusplus/templates/method.aserver.callback.hpp.mako
new file mode 100644
index 0000000..d2493d0
--- /dev/null
+++ b/tools/sdbusplus/templates/method.aserver.callback.hpp.mako
@@ -0,0 +1,243 @@
+<%
+m_name = method.snake_case
+m_tag = method.snake_case + "_t"
+m_param = method.parameters_as_list()
+m_pmove = method.parameters_as_list(lambda p: f"std::move({p.camelCase})")
+m_pargs = method.parameters_as_list(lambda p: method.parameter(interface, p))
+m_ptypes = method.parameter_types_as_list(interface)
+m_return = method.cpp_return_type(interface)
+i_name = interface.classname
+m_param_count = len(method.parameters)
+m_return_count = len(method.returns)
+%>\
+ static int _callback_m_${m_name}(sd_bus_message* msg, void* context,
+ sd_bus_error* error [[maybe_unused]])
+ requires (server_details::has_method<
+ ${m_tag}, Instance\
+% if m_param_count:
+, ${m_ptypes}\
+% endif
+>)
+ {
+ auto self = static_cast<${i_name}*>(context);
+ auto self_i = static_cast<Instance*>(self);
+
+ try
+ {
+ auto m = sdbusplus::message_t{msg};
+% if m_param_count:
+ auto [${m_param}] = m.unpack<${m_ptypes}>();
+% endif
+
+ constexpr auto has_method_msg =
+ server_details::has_method_msg<
+ ${m_tag}, Instance\
+% if m_param_count:
+, ${m_ptypes}\
+% endif
+>;
+
+ if constexpr (has_method_msg)
+ {
+ constexpr auto is_async = std::is_same_v<
+ sdbusplus::async::task<${m_return}>,
+ decltype(self_i->method_call(${m_tag}{}, m\
+% if m_param_count:
+,
+ ${m_pmove}\
+%endif
+))>;
+
+ if constexpr (!is_async)
+ {
+ auto r = m.new_method_return();
+% if m_return_count == 0:
+ \
+% elif m_return_count == 1:
+ r.append(\
+% else:
+ std::apply(
+ [&](auto&&... v) { (r.append(std::move(v)), ...); },
+ \
+% endif
+self_i->method_call(${m_tag}{}, m\
+% if m_param_count:
+,
+ ${m_pmove}\
+%endif
+% if m_return_count != 0:
+)\
+% endif
+);
+ r.method_return();
+ }
+ else
+ {
+ auto fn = [](auto self, auto self_i,
+ sdbusplus::message_t m\
+% if m_param_count:
+,
+ ${m_pargs}\
+% endif
+)
+ -> sdbusplus::async::task<>
+ {
+ try
+ {
+
+ auto r = m.new_method_return();
+% if m_return_count == 0:
+ \
+% elif m_return_count == 1:
+ r.append(\
+% else:
+ std::apply(
+ [&](auto&&... v) { (r.append(std::move(v)), ...); },
+ \
+% endif
+co_await self_i->method_call(
+ ${m_tag}{}, m\
+% if m_param_count:
+, ${m_pmove}\
+% endif
+% if m_return_count != 0:
+)\
+% endif
+);
+
+ r.method_return();
+ co_return;
+ }
+% for e in method.errors:
+ catch(const ${interface.errorNamespacedClass(e)}& e)
+ {
+ m.new_method_error(e).method_return();
+ co_return;
+ }
+ % endfor
+ catch(const std::exception&)
+ {
+ self->_context().get_bus().set_current_exception(
+ std::current_exception());
+ co_return;
+ }
+ };
+
+ self->_context().spawn(
+ std::move(fn(self, self_i, m\
+% if m_param_count:
+, ${m_pmove}\
+% endif
+)));
+ }
+ }
+ else
+ {
+ constexpr auto is_async [[maybe_unused]] = std::is_same_v<
+ sdbusplus::async::task<${m_return}>,
+ decltype(self_i->method_call(${m_tag}{}\
+% if m_param_count:
+,
+ ${m_pmove}\
+% endif:
+))>;
+
+ if constexpr (!is_async)
+ {
+ auto r = m.new_method_return();
+% if m_return_count == 0:
+ \
+% elif m_return_count == 1:
+ r.append(\
+% else:
+ std::apply(
+ [&](auto&&... v) { (r.append(std::move(v)), ...); },
+ \
+% endif
+self_i->method_call(${m_tag}{}\
+% if m_param_count:
+,
+ ${m_pmove}\
+%endif
+% if m_return_count != 0:
+)\
+% endif
+);
+ r.method_return();
+ }
+ else
+ {
+ auto fn = [](auto self, auto self_i,
+ sdbusplus::message_t m\
+% if m_param_count:
+,
+ ${m_pargs}\
+% endif
+)
+ -> sdbusplus::async::task<>
+ {
+ try
+ {
+
+ auto r = m.new_method_return();
+% if m_return_count == 0:
+ \
+% elif m_return_count == 1:
+ r.append(\
+% else:
+ std::apply(
+ [&](auto&&... v) { (r.append(std::move(v)), ...); },
+ \
+% endif
+co_await self_i->method_call(
+ ${m_tag}{}\
+% if m_param_count:
+, ${m_pmove}\
+% endif
+% if m_return_count != 0:
+)\
+% endif
+);
+
+ r.method_return();
+ co_return;
+ }
+% for e in method.errors:
+ catch(const ${interface.errorNamespacedClass(e)}& e)
+ {
+ m.new_method_error(e).method_return();
+ co_return;
+ }
+ % endfor
+ catch(const std::exception&)
+ {
+ self->_context().get_bus().set_current_exception(
+ std::current_exception());
+ co_return;
+ }
+ };
+
+ self->_context().spawn(
+ std::move(fn(self, self_i, m\
+% if m_param_count:
+, ${m_pmove}\
+% endif
+)));
+ }
+ }
+ }
+% for e in method.errors:
+ catch(const ${interface.errorNamespacedClass(e)}& e)
+ {
+ return sd_bus_error_set(error, e.name(), e.description());
+ }
+% endfor
+ catch(const std::exception&)
+ {
+ self->_context().get_bus().set_current_exception(
+ std::current_exception());
+ return -EINVAL;
+ }
+
+ return 1;
+ }
diff --git a/tools/sdbusplus/templates/method.aserver.tag.hpp.mako b/tools/sdbusplus/templates/method.aserver.tag.hpp.mako
new file mode 100644
index 0000000..7976b28
--- /dev/null
+++ b/tools/sdbusplus/templates/method.aserver.tag.hpp.mako
@@ -0,0 +1,10 @@
+<%
+m_tag = method.snake_case + "_t"
+m_param = method.parameter_types_as_list(interface)
+m_return = method.cpp_return_type(interface)
+%>\
+ struct ${m_tag}
+ {
+ using value_types = std::tuple<${m_param}>;
+ using return_type = ${m_return};
+ };
diff --git a/tools/sdbusplus/templates/method.aserver.typeid.hpp.mako b/tools/sdbusplus/templates/method.aserver.typeid.hpp.mako
new file mode 100644
index 0000000..b9b360d
--- /dev/null
+++ b/tools/sdbusplus/templates/method.aserver.typeid.hpp.mako
@@ -0,0 +1,17 @@
+ static constexpr auto _method_typeid_p_${method.snake_case} =
+ utility::tuple_to_array(\
+% if len(method.parameters) == 0:
+std::make_tuple('\0')\
+% else:
+message::types::type_id<${method.parameter_types_as_list(interface)}>()\
+% endif
+);
+
+ static constexpr auto _method_typeid_r_${method.snake_case} =
+ utility::tuple_to_array(\
+% if len(method.returns) == 0:
+std::make_tuple('\0')\
+% else:
+message::types::type_id<${method.returns_as_list(interface)}>()\
+% endif
+);
diff --git a/tools/sdbusplus/templates/method.aserver.vtable.hpp.mako b/tools/sdbusplus/templates/method.aserver.vtable.hpp.mako
new file mode 100644
index 0000000..e511e06
--- /dev/null
+++ b/tools/sdbusplus/templates/method.aserver.vtable.hpp.mako
@@ -0,0 +1,9 @@
+ vtable::method("${method.name}",
+ _method_typeid_p_${method.snake_case}.data(),
+ _method_typeid_r_${method.snake_case}.data(),
+ _callback_m_${method.snake_case}\
+% if method.cpp_flags:
+,
+ ${method.cpp_flags}\
+% endif
+),