191cdbe46SBenjamin Kietzman // Copyright (c) Benjamin Kietzman (github.com/bkietz)
291cdbe46SBenjamin Kietzman //
391cdbe46SBenjamin Kietzman // Distributed under the Boost Software License, Version 1.0. (See accompanying
491cdbe46SBenjamin Kietzman // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
591cdbe46SBenjamin Kietzman
6fc79e461SBenjamin Kietzman #ifndef DBUS_MESSAGE_HPP
7fc79e461SBenjamin Kietzman #define DBUS_MESSAGE_HPP
8fc79e461SBenjamin Kietzman
9fc79e461SBenjamin Kietzman #include <dbus/dbus.h>
100de54404SBenjamin Kietzman #include <dbus/element.hpp>
1116d80fe9SBenjamin Kietzman #include <dbus/endpoint.hpp>
12d977442cSBenjamin Kietzman #include <dbus/impl/message_iterator.hpp>
13da3eeb6aSEd Tanous #include <iostream>
14b6e8327aSEd Tanous #include <vector>
15da3eeb6aSEd Tanous #include <boost/intrusive_ptr.hpp>
160aef8864SEd Tanous #include <boost/mpl/for_each.hpp>
1777e62c83SEd Tanous #include <boost/utility/enable_if.hpp>
180de54404SBenjamin Kietzman
intrusive_ptr_add_ref(DBusMessage * m)19da3eeb6aSEd Tanous inline void intrusive_ptr_add_ref(DBusMessage* m) { dbus_message_ref(m); }
20510d9aa6SBenjamin Kietzman
intrusive_ptr_release(DBusMessage * m)21da3eeb6aSEd Tanous inline void intrusive_ptr_release(DBusMessage* m) { dbus_message_unref(m); }
220de54404SBenjamin Kietzman
230de54404SBenjamin Kietzman namespace dbus {
24fc79e461SBenjamin Kietzman
25da3eeb6aSEd Tanous class message {
2677e62c83SEd Tanous private:
27510d9aa6SBenjamin Kietzman boost::intrusive_ptr<DBusMessage> message_;
280de54404SBenjamin Kietzman
29da3eeb6aSEd Tanous public:
300de54404SBenjamin Kietzman /// Create a method call message
new_call(const endpoint & destination)31e62be329SEd Tanous static message new_call(const endpoint& destination) {
32e62be329SEd Tanous auto x = message(dbus_message_new_method_call(
33e62be329SEd Tanous destination.get_process_name().c_str(), destination.get_path().c_str(),
34e62be329SEd Tanous destination.get_interface().c_str(), destination.get_member().c_str()));
35e62be329SEd Tanous dbus_message_unref(x.message_.get());
36e62be329SEd Tanous return x;
37e62be329SEd Tanous }
38e62be329SEd Tanous
39e62be329SEd Tanous /// Create a method call message
new_call(const endpoint & destination,const string & method_name)40da3eeb6aSEd Tanous static message new_call(const endpoint& destination,
41da3eeb6aSEd Tanous const string& method_name) {
4277e62c83SEd Tanous auto x = message(dbus_message_new_method_call(
43da3eeb6aSEd Tanous destination.get_process_name().c_str(), destination.get_path().c_str(),
4477e62c83SEd Tanous destination.get_interface().c_str(), method_name.c_str()));
4577e62c83SEd Tanous dbus_message_unref(x.message_.get());
4677e62c83SEd Tanous return x;
47da3eeb6aSEd Tanous }
480de54404SBenjamin Kietzman
490de54404SBenjamin Kietzman /// Create a method return message
new_return(message & call)50da3eeb6aSEd Tanous static message new_return(message& call) {
5177e62c83SEd Tanous auto x = message(dbus_message_new_method_return(call));
5277e62c83SEd Tanous dbus_message_unref(x.message_.get());
5377e62c83SEd Tanous return x;
54da3eeb6aSEd Tanous }
550de54404SBenjamin Kietzman
560de54404SBenjamin Kietzman /// Create an error message
new_error(message & call,const string & error_name,const string & error_message)57da3eeb6aSEd Tanous static message new_error(message& call, const string& error_name,
58da3eeb6aSEd Tanous const string& error_message) {
5977e62c83SEd Tanous auto x = message(dbus_message_new_error(call, error_name.c_str(),
6077e62c83SEd Tanous error_message.c_str()));
6177e62c83SEd Tanous dbus_message_unref(x.message_.get());
6277e62c83SEd Tanous return x;
63da3eeb6aSEd Tanous }
640de54404SBenjamin Kietzman
650de54404SBenjamin Kietzman /// Create a signal message
new_signal(const endpoint & origin,const string & signal_name)66da3eeb6aSEd Tanous static message new_signal(const endpoint& origin, const string& signal_name) {
6777e62c83SEd Tanous auto x = message(dbus_message_new_signal(origin.get_path().c_str(),
68da3eeb6aSEd Tanous origin.get_interface().c_str(),
6977e62c83SEd Tanous signal_name.c_str()));
7077e62c83SEd Tanous dbus_message_unref(x.message_.get());
7177e62c83SEd Tanous return x;
72da3eeb6aSEd Tanous }
730de54404SBenjamin Kietzman
7477e62c83SEd Tanous message() = delete;
750de54404SBenjamin Kietzman
message(DBusMessage * m)7677e62c83SEd Tanous message(DBusMessage* m) : message_(m) {}
77e6b71ae1SBenjamin Kietzman
operator DBusMessage*()78da3eeb6aSEd Tanous operator DBusMessage*() { return message_.get(); }
790de54404SBenjamin Kietzman
operator const DBusMessage*() const80da3eeb6aSEd Tanous operator const DBusMessage*() const { return message_.get(); }
810de54404SBenjamin Kietzman
get_path() const82da3eeb6aSEd Tanous string get_path() const {
838f81b71dSBenjamin Kietzman return sanitize(dbus_message_get_path(message_.get()));
84e6b71ae1SBenjamin Kietzman }
85e6b71ae1SBenjamin Kietzman
get_interface() const86da3eeb6aSEd Tanous string get_interface() const {
878f81b71dSBenjamin Kietzman return sanitize(dbus_message_get_interface(message_.get()));
88e6b71ae1SBenjamin Kietzman }
89e6b71ae1SBenjamin Kietzman
get_member() const90da3eeb6aSEd Tanous string get_member() const {
918f81b71dSBenjamin Kietzman return sanitize(dbus_message_get_member(message_.get()));
928f81b71dSBenjamin Kietzman }
938f81b71dSBenjamin Kietzman
get_type() const94da3eeb6aSEd Tanous string get_type() const {
95da3eeb6aSEd Tanous return sanitize(
96da3eeb6aSEd Tanous dbus_message_type_to_string(dbus_message_get_type(message_.get())));
97e6b71ae1SBenjamin Kietzman }
98e6b71ae1SBenjamin Kietzman
get_signature() const99458a9c10SVernon Mauery string get_signature() const {
100458a9c10SVernon Mauery return sanitize(dbus_message_get_signature(message_.get()));
101458a9c10SVernon Mauery }
102458a9c10SVernon Mauery
get_sender() const103da3eeb6aSEd Tanous string get_sender() const {
1048f81b71dSBenjamin Kietzman return sanitize(dbus_message_get_sender(message_.get()));
1053b5db5bcSBenjamin Kietzman }
1063b5db5bcSBenjamin Kietzman
get_destination() const107da3eeb6aSEd Tanous string get_destination() const {
1088f81b71dSBenjamin Kietzman return sanitize(dbus_message_get_destination(message_.get()));
109e6b71ae1SBenjamin Kietzman }
110e6b71ae1SBenjamin Kietzman
get_serial()111da3eeb6aSEd Tanous uint32 get_serial() { return dbus_message_get_serial(message_.get()); }
1124317e4d9SBenjamin Kietzman
set_serial(uint32 serial)113da3eeb6aSEd Tanous message& set_serial(uint32 serial) {
1144317e4d9SBenjamin Kietzman dbus_message_set_serial(message_.get(), serial);
1154317e4d9SBenjamin Kietzman return *this;
1164317e4d9SBenjamin Kietzman }
1174317e4d9SBenjamin Kietzman
get_reply_serial()118da3eeb6aSEd Tanous uint32 get_reply_serial() {
1194317e4d9SBenjamin Kietzman return dbus_message_get_reply_serial(message_.get());
1204317e4d9SBenjamin Kietzman }
1214317e4d9SBenjamin Kietzman
set_reply_serial(uint32 reply_serial)122da3eeb6aSEd Tanous message& set_reply_serial(uint32 reply_serial) {
1234317e4d9SBenjamin Kietzman dbus_message_set_reply_serial(message_.get(), reply_serial);
1244317e4d9SBenjamin Kietzman return *this;
1254317e4d9SBenjamin Kietzman }
1264317e4d9SBenjamin Kietzman
127da3eeb6aSEd Tanous struct packer {
128d977442cSBenjamin Kietzman impl::message_iterator iter_;
packerdbus::message::packer129da3eeb6aSEd Tanous packer(message& m) { impl::message_iterator::init_append(m, iter_); }
packerdbus::message::packer13082a51ce2SEd Tanous packer(){};
1310d6f56d2SEd Tanous
1320d6f56d2SEd Tanous template <typename Element, typename... Args>
packdbus::message::packer133a04118e8SEd Tanous bool pack(const Element& e, const Args&... args) {
134a04118e8SEd Tanous if (this->pack(e) == false) {
135a04118e8SEd Tanous return false;
136a04118e8SEd Tanous } else {
137a04118e8SEd Tanous return pack(args...);
138a04118e8SEd Tanous }
139a04118e8SEd Tanous }
140a04118e8SEd Tanous
141a04118e8SEd Tanous template <typename Element>
packdbus::message::packer142*fee38731SEd Tanous typename std::enable_if<is_fixed_type<Element>::value, bool>::type pack(
143a04118e8SEd Tanous const Element& e) {
144a04118e8SEd Tanous return iter_.append_basic(element<Element>::code, &e);
145a04118e8SEd Tanous }
146a04118e8SEd Tanous
147a04118e8SEd Tanous template <typename Element>
packdbus::message::packer148*fee38731SEd Tanous typename std::enable_if<std::is_pointer<Element>::value, bool>::type pack(
149a8b4eac4SEd Tanous const Element e) {
150*fee38731SEd Tanous return pack(*e);
151a04118e8SEd Tanous }
152a04118e8SEd Tanous
153a8b4eac4SEd Tanous template <typename Container>
154a8b4eac4SEd Tanous typename std::enable_if<has_const_iterator<Container>::value &&
155a8b4eac4SEd Tanous !is_string_type<Container>::value,
156a8b4eac4SEd Tanous bool>::type
packdbus::message::packer157a8b4eac4SEd Tanous pack(const Container& c) {
158a8b4eac4SEd Tanous message::packer sub;
159a8b4eac4SEd Tanous
160a8b4eac4SEd Tanous static const constexpr auto signature =
161a8b4eac4SEd Tanous element_signature<Container>::code;
162a8b4eac4SEd Tanous if (iter_.open_container(signature[0], &signature[1], sub.iter_) ==
163a8b4eac4SEd Tanous false) {
164a8b4eac4SEd Tanous return false;
165a8b4eac4SEd Tanous }
166a8b4eac4SEd Tanous for (auto& element : c) {
167a8b4eac4SEd Tanous if (!sub.pack(element)) {
168a8b4eac4SEd Tanous return false;
169a8b4eac4SEd Tanous }
170a8b4eac4SEd Tanous }
171a04118e8SEd Tanous return iter_.close_container(sub.iter_);
172a04118e8SEd Tanous }
173a04118e8SEd Tanous
packdbus::message::packer174a04118e8SEd Tanous bool pack(const char* c) {
175a04118e8SEd Tanous return iter_.append_basic(element<string>::code, &c);
176a04118e8SEd Tanous }
177a04118e8SEd Tanous
178631fa83aSVernon Mauery // bool pack specialization
packdbus::message::packer179631fa83aSVernon Mauery bool pack(bool c) {
180631fa83aSVernon Mauery int v = c;
181631fa83aSVernon Mauery return iter_.append_basic(element<bool>::code, &v);
182631fa83aSVernon Mauery }
183631fa83aSVernon Mauery
184a04118e8SEd Tanous template <typename Key, typename Value>
packdbus::message::packer185a04118e8SEd Tanous bool pack(const std::pair<Key, Value> element) {
186a04118e8SEd Tanous message::packer dict_entry;
187a04118e8SEd Tanous if (iter_.open_container(DBUS_TYPE_DICT_ENTRY, NULL, dict_entry.iter_) ==
188a04118e8SEd Tanous false) {
189a04118e8SEd Tanous return false;
190a04118e8SEd Tanous }
191a04118e8SEd Tanous if (dict_entry.pack(element.first) == false) {
192a04118e8SEd Tanous return false;
193a04118e8SEd Tanous };
194a04118e8SEd Tanous if (dict_entry.pack(element.second) == false) {
195a04118e8SEd Tanous return false;
196a04118e8SEd Tanous };
197a04118e8SEd Tanous return iter_.close_container(dict_entry.iter_);
198a04118e8SEd Tanous }
199a04118e8SEd Tanous
packdbus::message::packer20070d534bfSFeist, James bool pack(const object_path& e) {
20170d534bfSFeist, James const char* c = e.value.c_str();
20270d534bfSFeist, James return iter_.append_basic(element<object_path>::code, &c);
20370d534bfSFeist, James }
20470d534bfSFeist, James
packdbus::message::packer205a04118e8SEd Tanous bool pack(const string& e) {
206a04118e8SEd Tanous const char* c = e.c_str();
207a04118e8SEd Tanous return pack(c);
208a04118e8SEd Tanous }
209a04118e8SEd Tanous
packdbus::message::packer210a04118e8SEd Tanous bool pack(const dbus_variant& v) {
211a04118e8SEd Tanous // Get the dbus typecode of the variant being packed
212a04118e8SEd Tanous const char* type = boost::apply_visitor(
213a04118e8SEd Tanous [&](auto val) {
214a04118e8SEd Tanous static const constexpr auto sig =
215a04118e8SEd Tanous element_signature<decltype(val)>::code;
216a04118e8SEd Tanous return &sig[0];
217a04118e8SEd Tanous },
218a04118e8SEd Tanous v);
219a04118e8SEd Tanous message::packer sub;
220a04118e8SEd Tanous iter_.open_container(element<dbus_variant>::code, type, sub.iter_);
221a04118e8SEd Tanous boost::apply_visitor([&](const auto& val) { sub.pack(val); }, v);
222a04118e8SEd Tanous iter_.close_container(sub.iter_);
223a04118e8SEd Tanous
224a04118e8SEd Tanous return true;
225f6c70586SEd Tanous }
226f6c70586SEd Tanous };
227f6c70586SEd Tanous
228f6c70586SEd Tanous template <typename... Args>
pack(const Args &...args)229a04118e8SEd Tanous bool pack(const Args&... args) {
230f6c70586SEd Tanous return packer(*this).pack(args...);
2310d6f56d2SEd Tanous }
2320d6f56d2SEd Tanous
233e62be329SEd Tanous // noop for template functions that have no arguments
pack()234e62be329SEd Tanous bool pack() { return true; }
235e62be329SEd Tanous
236da3eeb6aSEd Tanous struct unpacker {
237d977442cSBenjamin Kietzman impl::message_iterator iter_;
unpackerdbus::message::unpacker238da3eeb6aSEd Tanous unpacker(message& m) { impl::message_iterator::init(m, iter_); }
unpackerdbus::message::unpacker23982a51ce2SEd Tanous unpacker() {}
240b6e8327aSEd Tanous
241a04118e8SEd Tanous template <typename Element, typename... Args>
unpackdbus::message::unpacker242a04118e8SEd Tanous bool unpack(Element& e, Args&... args) {
243a04118e8SEd Tanous if (unpack(e) == false) {
244a04118e8SEd Tanous return false;
245a04118e8SEd Tanous }
246a04118e8SEd Tanous return unpack(args...);
247a8487f4dSBenjamin Kietzman }
2480de54404SBenjamin Kietzman
249a04118e8SEd Tanous // Basic type unpack
250a04118e8SEd Tanous template <typename Element>
unpackdbus::message::unpacker251*fee38731SEd Tanous typename std::enable_if<is_fixed_type<Element>::value, bool>::type unpack(
252a04118e8SEd Tanous Element& e) {
253a04118e8SEd Tanous if (iter_.get_arg_type() != element<Element>::code) {
254a04118e8SEd Tanous return false;
255a04118e8SEd Tanous }
256a04118e8SEd Tanous iter_.get_basic(&e);
257a04118e8SEd Tanous // ignoring return code here, as we might hit last element, and don't
258a04118e8SEd Tanous // really care because get_arg_type will return invalid if we call it
259a04118e8SEd Tanous // after we're over the struct boundary
260a04118e8SEd Tanous iter_.next();
261a04118e8SEd Tanous return true;
262a04118e8SEd Tanous }
263a04118e8SEd Tanous
264631fa83aSVernon Mauery // bool unpack specialization
unpackdbus::message::unpacker265631fa83aSVernon Mauery bool unpack(bool& s) {
266631fa83aSVernon Mauery if (iter_.get_arg_type() != element<bool>::code) {
267631fa83aSVernon Mauery return false;
268631fa83aSVernon Mauery }
269631fa83aSVernon Mauery int c;
270631fa83aSVernon Mauery iter_.get_basic(&c);
271631fa83aSVernon Mauery s = c;
272631fa83aSVernon Mauery iter_.next();
273631fa83aSVernon Mauery return true;
274631fa83aSVernon Mauery }
275631fa83aSVernon Mauery
276a04118e8SEd Tanous // std::string unpack specialization
unpackdbus::message::unpacker277a04118e8SEd Tanous bool unpack(string& s) {
278a04118e8SEd Tanous if (iter_.get_arg_type() != element<string>::code) {
279a04118e8SEd Tanous return false;
280a04118e8SEd Tanous }
281a04118e8SEd Tanous const char* c;
282a04118e8SEd Tanous iter_.get_basic(&c);
283a04118e8SEd Tanous s.assign(c);
284a04118e8SEd Tanous iter_.next();
285a04118e8SEd Tanous return true;
286a04118e8SEd Tanous }
287a04118e8SEd Tanous
288a04118e8SEd Tanous // object_path unpack specialization
unpackdbus::message::unpacker289a04118e8SEd Tanous bool unpack(object_path& s) {
290a04118e8SEd Tanous if (iter_.get_arg_type() != element<object_path>::code) {
291a04118e8SEd Tanous return false;
292a04118e8SEd Tanous }
293a04118e8SEd Tanous const char* c;
294a04118e8SEd Tanous iter_.get_basic(&c);
295a04118e8SEd Tanous s.value.assign(c);
296a04118e8SEd Tanous iter_.next();
297a04118e8SEd Tanous return true;
298a04118e8SEd Tanous }
299a04118e8SEd Tanous
300a04118e8SEd Tanous // object_path unpack specialization
unpackdbus::message::unpacker301a04118e8SEd Tanous bool unpack(signature& s) {
302a04118e8SEd Tanous if (iter_.get_arg_type() != element<signature>::code) {
303a04118e8SEd Tanous return false;
304a04118e8SEd Tanous }
305a04118e8SEd Tanous const char* c;
306a04118e8SEd Tanous iter_.get_basic(&c);
307a04118e8SEd Tanous s.value.assign(c);
308a04118e8SEd Tanous iter_.next();
309a04118e8SEd Tanous return true;
310a04118e8SEd Tanous }
311a04118e8SEd Tanous
312a04118e8SEd Tanous // variant unpack specialization
unpackdbus::message::unpacker313a04118e8SEd Tanous bool unpack(dbus_variant& v) {
314a04118e8SEd Tanous if (iter_.get_arg_type() != element<dbus_variant>::code) {
315a04118e8SEd Tanous return false;
316a04118e8SEd Tanous }
317a04118e8SEd Tanous message::unpacker sub;
318a04118e8SEd Tanous iter_.recurse(sub.iter_);
319a04118e8SEd Tanous
320a04118e8SEd Tanous char arg_type = sub.iter_.get_arg_type();
321a04118e8SEd Tanous
322a04118e8SEd Tanous boost::mpl::for_each<dbus_variant::types>([&](auto t) {
323a04118e8SEd Tanous if (arg_type == element<decltype(t)>::code) {
324a04118e8SEd Tanous decltype(t) val_to_fill;
325a04118e8SEd Tanous sub.unpack(val_to_fill);
326a04118e8SEd Tanous v = val_to_fill;
327a04118e8SEd Tanous }
328a04118e8SEd Tanous });
329a04118e8SEd Tanous
330a04118e8SEd Tanous iter_.next();
331a04118e8SEd Tanous return true;
332a04118e8SEd Tanous }
333a04118e8SEd Tanous
334a04118e8SEd Tanous // dict entry unpack specialization
335a04118e8SEd Tanous template <typename Key, typename Value>
unpackdbus::message::unpacker336a04118e8SEd Tanous bool unpack(std::pair<Key, Value>& v) {
337a04118e8SEd Tanous auto this_code = iter_.get_arg_type();
338a04118e8SEd Tanous // This can't use element<std::pair> because there is a difference between
339a04118e8SEd Tanous // the dbus type code 'e' and the dbus signature code for dict entries
340a04118e8SEd Tanous // '{'. Element_signature will return the full signature, and will never
341a04118e8SEd Tanous // return e, but we still want to type check it before recursing
342a04118e8SEd Tanous if (this_code != DBUS_TYPE_DICT_ENTRY) {
343a04118e8SEd Tanous return false;
344a04118e8SEd Tanous }
345a04118e8SEd Tanous message::unpacker sub;
346a04118e8SEd Tanous iter_.recurse(sub.iter_);
347a04118e8SEd Tanous if (!sub.unpack(v.first)) {
348a04118e8SEd Tanous return false;
349a04118e8SEd Tanous }
350a04118e8SEd Tanous if (!sub.unpack(v.second)) {
351a04118e8SEd Tanous return false;
352a04118e8SEd Tanous }
353a04118e8SEd Tanous
354a04118e8SEd Tanous iter_.next();
355a04118e8SEd Tanous return true;
356a04118e8SEd Tanous }
357a04118e8SEd Tanous
358*fee38731SEd Tanous template <typename T>
359*fee38731SEd Tanous struct has_emplace_method
360*fee38731SEd Tanous
361*fee38731SEd Tanous {
362*fee38731SEd Tanous struct dummy {};
363*fee38731SEd Tanous
364*fee38731SEd Tanous template <typename C, typename P>
365*fee38731SEd Tanous static auto test(P* p)
366*fee38731SEd Tanous -> decltype(std::declval<C>().emplace(*p), std::true_type());
367*fee38731SEd Tanous
368*fee38731SEd Tanous template <typename, typename>
369*fee38731SEd Tanous static std::false_type test(...);
370*fee38731SEd Tanous
371*fee38731SEd Tanous typedef decltype(test<T, dummy>(nullptr)) type;
372*fee38731SEd Tanous
373*fee38731SEd Tanous static constexpr bool value =
374*fee38731SEd Tanous std::is_same<std::true_type,
375*fee38731SEd Tanous decltype(test<T, dummy>(nullptr))>::value;
376*fee38731SEd Tanous };
377*fee38731SEd Tanous
378*fee38731SEd Tanous template <typename T>
379*fee38731SEd Tanous struct has_emplace_back_method
380*fee38731SEd Tanous
381*fee38731SEd Tanous {
382*fee38731SEd Tanous struct dummy {};
383*fee38731SEd Tanous
384*fee38731SEd Tanous template <typename C, typename P>
385*fee38731SEd Tanous static auto test(P* p)
386*fee38731SEd Tanous -> decltype(std::declval<C>().emplace_back(*p), std::true_type());
387*fee38731SEd Tanous
388*fee38731SEd Tanous template <typename, typename>
389*fee38731SEd Tanous static std::false_type test(...);
390*fee38731SEd Tanous
391*fee38731SEd Tanous typedef decltype(test<T, dummy>(nullptr)) type;
392*fee38731SEd Tanous
393*fee38731SEd Tanous static constexpr bool value =
394*fee38731SEd Tanous std::is_same<std::true_type,
395*fee38731SEd Tanous decltype(test<T, dummy>(nullptr))>::value;
396*fee38731SEd Tanous };
397*fee38731SEd Tanous
398a8b4eac4SEd Tanous template <typename Container>
399*fee38731SEd Tanous typename std::enable_if<has_emplace_back_method<Container>::value &&
400a8b4eac4SEd Tanous !is_string_type<Container>::value,
401a8b4eac4SEd Tanous bool>::type
unpackdbus::message::unpacker402a8b4eac4SEd Tanous unpack(Container& c) {
403a04118e8SEd Tanous auto top_level_arg_type = iter_.get_arg_type();
404a8b4eac4SEd Tanous constexpr auto type = element_signature<Container>::code[0];
405a8b4eac4SEd Tanous if (top_level_arg_type != type) {
406a04118e8SEd Tanous return false;
407a04118e8SEd Tanous }
408a04118e8SEd Tanous message::unpacker sub;
409a04118e8SEd Tanous
410a04118e8SEd Tanous iter_.recurse(sub.iter_);
411*fee38731SEd Tanous while (sub.iter_.get_arg_type() != DBUS_TYPE_INVALID) {
412a8b4eac4SEd Tanous c.emplace_back();
413a8b4eac4SEd Tanous if (!sub.unpack(c.back())) {
414a04118e8SEd Tanous return false;
415a04118e8SEd Tanous }
416*fee38731SEd Tanous }
417*fee38731SEd Tanous iter_.next();
418*fee38731SEd Tanous return true;
419*fee38731SEd Tanous }
420*fee38731SEd Tanous
421*fee38731SEd Tanous template <typename Container>
422*fee38731SEd Tanous typename std::enable_if<has_emplace_method<Container>::value &&
423*fee38731SEd Tanous !is_string_type<Container>::value,
424*fee38731SEd Tanous bool>::type
unpackdbus::message::unpacker425*fee38731SEd Tanous unpack(Container& c) {
426*fee38731SEd Tanous auto top_level_arg_type = iter_.get_arg_type();
427*fee38731SEd Tanous constexpr auto type = element_signature<Container>::code[0];
428*fee38731SEd Tanous if (top_level_arg_type != type) {
429*fee38731SEd Tanous return false;
430*fee38731SEd Tanous }
431*fee38731SEd Tanous message::unpacker sub;
432*fee38731SEd Tanous
433*fee38731SEd Tanous iter_.recurse(sub.iter_);
434*fee38731SEd Tanous while (sub.iter_.get_arg_type() != DBUS_TYPE_INVALID) {
435*fee38731SEd Tanous // TODO(ed) this is done as an unpack to a stack variable, then an
436*fee38731SEd Tanous // emplace move into the container (as the key isn't known until the
437*fee38731SEd Tanous // unpack is done) This could be made more efficient by unpacking only
438*fee38731SEd Tanous // the key type into a temporary, using find on the temporary, then
439*fee38731SEd Tanous // unpacking directly into the map type, instead of unpacking both key
440*fee38731SEd Tanous // and value.
441*fee38731SEd Tanous
442*fee38731SEd Tanous typename Container::value_type t;
443*fee38731SEd Tanous if (!sub.unpack(t)) {
444*fee38731SEd Tanous return false;
445*fee38731SEd Tanous }
446*fee38731SEd Tanous c.emplace(std::move(t));
447a04118e8SEd Tanous }
448a04118e8SEd Tanous iter_.next();
449a04118e8SEd Tanous return true;
4500d6f56d2SEd Tanous }
451f6c70586SEd Tanous };
452f6c70586SEd Tanous
453f6c70586SEd Tanous template <typename... Args>
unpack(Args &...args)454a04118e8SEd Tanous bool unpack(Args&... args) {
455f6c70586SEd Tanous return unpacker(*this).unpack(args...);
456f6c70586SEd Tanous }
4570d6f56d2SEd Tanous
4588f81b71dSBenjamin Kietzman private:
sanitize(const char * str)459da3eeb6aSEd Tanous static std::string sanitize(const char* str) {
4608f81b71dSBenjamin Kietzman return (str == NULL) ? "(null)" : str;
4618f81b71dSBenjamin Kietzman }
4620de54404SBenjamin Kietzman };
4630de54404SBenjamin Kietzman
operator <<(std::ostream & os,const message & m)464da3eeb6aSEd Tanous inline std::ostream& operator<<(std::ostream& os, const message& m) {
4658f81b71dSBenjamin Kietzman os << "type='" << m.get_type() << "',"
4668f81b71dSBenjamin Kietzman << "sender='" << m.get_sender() << "',"
4678f81b71dSBenjamin Kietzman << "interface='" << m.get_interface() << "',"
4688f81b71dSBenjamin Kietzman << "member='" << m.get_member() << "',"
4698f81b71dSBenjamin Kietzman << "path='" << m.get_path() << "',"
4708f81b71dSBenjamin Kietzman << "destination='" << m.get_destination() << "'";
4718f81b71dSBenjamin Kietzman return os;
4728f81b71dSBenjamin Kietzman }
4738f81b71dSBenjamin Kietzman
4740de54404SBenjamin Kietzman } // namespace dbus
4750de54404SBenjamin Kietzman
476e62be329SEd Tanous // primary template.
477e62be329SEd Tanous template <class T>
478e62be329SEd Tanous struct function_traits : function_traits<decltype(&T::operator())> {};
479e62be329SEd Tanous
480e62be329SEd Tanous // partial specialization for function type
481e62be329SEd Tanous template <class R, class... Args>
482e62be329SEd Tanous struct function_traits<R(Args...)> {
483e62be329SEd Tanous using result_type = R;
484e62be329SEd Tanous using argument_types = std::tuple<Args...>;
485e62be329SEd Tanous using decayed_arg_types = std::tuple<typename std::decay<Args>::type...>;
486e62be329SEd Tanous };
487e62be329SEd Tanous
488e62be329SEd Tanous // partial specialization for function pointer
489e62be329SEd Tanous template <class R, class... Args>
490e62be329SEd Tanous struct function_traits<R (*)(Args...)> {
491e62be329SEd Tanous using result_type = R;
492e62be329SEd Tanous using argument_types = std::tuple<Args...>;
493e62be329SEd Tanous using decayed_arg_types = std::tuple<typename std::decay<Args>::type...>;
494e62be329SEd Tanous };
495e62be329SEd Tanous
496e62be329SEd Tanous // partial specialization for std::function
497e62be329SEd Tanous template <class R, class... Args>
498e62be329SEd Tanous struct function_traits<std::function<R(Args...)>> {
499e62be329SEd Tanous using result_type = R;
500e62be329SEd Tanous using argument_types = std::tuple<Args...>;
501e62be329SEd Tanous using decayed_arg_types = std::tuple<typename std::decay<Args>::type...>;
502e62be329SEd Tanous };
503e62be329SEd Tanous
504e62be329SEd Tanous // partial specialization for pointer-to-member-function (i.e., operator()'s)
505e62be329SEd Tanous template <class T, class R, class... Args>
506e62be329SEd Tanous struct function_traits<R (T::*)(Args...)> {
507e62be329SEd Tanous using result_type = R;
508e62be329SEd Tanous using argument_types = std::tuple<Args...>;
509e62be329SEd Tanous using decayed_arg_types = std::tuple<typename std::decay<Args>::type...>;
510e62be329SEd Tanous };
511e62be329SEd Tanous
512e62be329SEd Tanous template <class T, class R, class... Args>
513e62be329SEd Tanous struct function_traits<R (T::*)(Args...) const> {
514e62be329SEd Tanous using result_type = R;
515e62be329SEd Tanous using argument_types = std::tuple<Args...>;
516e62be329SEd Tanous using decayed_arg_types = std::tuple<typename std::decay<Args>::type...>;
517e62be329SEd Tanous };
518e62be329SEd Tanous
519e62be329SEd Tanous template <class F, size_t... Is>
index_apply_impl(F f,std::index_sequence<Is...>)520e62be329SEd Tanous constexpr auto index_apply_impl(F f, std::index_sequence<Is...>) {
521e62be329SEd Tanous return f(std::integral_constant<size_t, Is>{}...);
522e62be329SEd Tanous }
523e62be329SEd Tanous
524e62be329SEd Tanous template <size_t N, class F>
index_apply(F f)525e62be329SEd Tanous constexpr auto index_apply(F f) {
526e62be329SEd Tanous return index_apply_impl(f, std::make_index_sequence<N>{});
527e62be329SEd Tanous }
528e62be329SEd Tanous
529e62be329SEd Tanous template <class Tuple, class F>
apply(F f,Tuple & t)530e62be329SEd Tanous constexpr auto apply(F f, Tuple& t) {
531e62be329SEd Tanous return index_apply<std::tuple_size<Tuple>{}>(
532e62be329SEd Tanous [&](auto... Is) { return f(std::get<Is>(t)...); });
533e62be329SEd Tanous }
534e62be329SEd Tanous
535e62be329SEd Tanous template <class Tuple>
unpack_into_tuple(Tuple & t,dbus::message & m)536e62be329SEd Tanous constexpr bool unpack_into_tuple(Tuple& t, dbus::message& m) {
537e62be329SEd Tanous return index_apply<std::tuple_size<Tuple>{}>(
538e62be329SEd Tanous [&](auto... Is) { return m.unpack(std::get<Is>(t)...); });
539e62be329SEd Tanous }
540e62be329SEd Tanous
541e62be329SEd Tanous // Specialization for empty tuples. No need to unpack if no arguments
unpack_into_tuple(std::tuple<> & t,dbus::message & m)542e62be329SEd Tanous constexpr bool unpack_into_tuple(std::tuple<>& t, dbus::message& m) {
543e62be329SEd Tanous return true;
544e62be329SEd Tanous }
545e62be329SEd Tanous
546e62be329SEd Tanous template <typename... Args>
pack_tuple_into_msg(std::tuple<Args...> & t,dbus::message & m)547e62be329SEd Tanous constexpr bool pack_tuple_into_msg(std::tuple<Args...>& t, dbus::message& m) {
548e62be329SEd Tanous return index_apply<std::tuple_size<std::tuple<Args...>>{}>(
549e62be329SEd Tanous [&](auto... Is) { return m.pack(std::get<Is>(t)...); });
550e62be329SEd Tanous }
551e62be329SEd Tanous
552e62be329SEd Tanous // Specialization for empty tuples. No need to pack if no arguments
pack_tuple_into_msg(std::tuple<> & t,dbus::message & m)553e62be329SEd Tanous constexpr bool pack_tuple_into_msg(std::tuple<>& t, dbus::message& m) {
554e62be329SEd Tanous return true;
555e62be329SEd Tanous }
556e62be329SEd Tanous
557e62be329SEd Tanous // Specialization for single types. Used when callbacks simply return one value
558e62be329SEd Tanous template <typename Element>
pack_tuple_into_msg(Element & t,dbus::message & m)559e62be329SEd Tanous constexpr bool pack_tuple_into_msg(Element& t, dbus::message& m) {
560e62be329SEd Tanous return m.pack(t);
561e62be329SEd Tanous }
562e62be329SEd Tanous
563d977442cSBenjamin Kietzman #include <dbus/impl/message_iterator.ipp>
564fc79e461SBenjamin Kietzman
565fc79e461SBenjamin Kietzman #endif // DBUS_MESSAGE_HPP
566