xref: /openbmc/boost-dbus/include/dbus/message.hpp (revision fee38731bccba22b4157cc47afbf6434fec1eb6d)
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