sdbusplus::message::message Add sdbus interface injection

By default message will use the sdbus singleton that points to the real
library calls, however you can now pass in an interface pointer for
it to use instead.  This is handled automatically when the message
is created by the sdbusplus::bus::bus as it will pass in its own
interface upon creation (via a later CL).

Note: This was originally part of another patchset.
Change-Id: Iad49164f1a648e6d3af7d288a8953b5a5ab051bf
Signed-off-by: Patrick Venture <venture@google.com>
diff --git a/sdbusplus/bus.hpp.in b/sdbusplus/bus.hpp.in
index 57df1bf..4382834 100644
--- a/sdbusplus/bus.hpp.in
+++ b/sdbusplus/bus.hpp.in
@@ -400,7 +400,7 @@
 inline auto message::message::get_bus()
 {
     sd_bus* b = nullptr;
-    b = sd_bus_message_get_bus(_msg.get());
+    b = _intf->sd_bus_message_get_bus(_msg.get());
     return bus::bus(b);
 }
 
diff --git a/sdbusplus/message.hpp b/sdbusplus/message.hpp
index 31ca95d..fe00ee0 100644
--- a/sdbusplus/message.hpp
+++ b/sdbusplus/message.hpp
@@ -6,6 +6,9 @@
 #include <sdbusplus/message/append.hpp>
 #include <sdbusplus/message/read.hpp>
 #include <sdbusplus/message/native_types.hpp>
+#include <sdbusplus/sdbus.hpp>
+
+extern sdbusplus::SdBusImpl sdbus_impl;
 
 namespace sdbusplus
 {
@@ -26,6 +29,8 @@
 {
 
 /** @brief unique_ptr functor to release a msg reference. */
+// TODO(venture): Consider using template <SdBusInterfaceType> for this so that
+// it doesn't require creating a specific instance of it, unless that's ok --
 struct MsgDeleter
 {
     void operator()(msgp_t ptr) const
@@ -42,7 +47,7 @@
 /** @class message
  *  @brief Provides C++ bindings to the sd_bus_message_* class functions.
  */
-struct message
+class message
 {
     /* Define all of the basic class operations:
      *     Not allowed:
@@ -52,6 +57,7 @@
      *         - Move operations.
      *         - Destructor.
      */
+  public:
     message() = delete;
     message(const message&) = delete;
     message& operator=(const message&) = delete;
@@ -59,12 +65,17 @@
     message& operator=(message&&) = default;
     ~message() = default;
 
+    message(msgp_t m, sdbusplus::SdBusInterface* intf) :
+        _intf(std::move(intf)), _msg(_intf->sd_bus_message_ref(m))
+    {
+    }
+
     /** @brief Conversion constructor for 'msgp_t'.
      *
      *  Takes increment ref-count of the msg-pointer and release when
      *  destructed.
      */
-    explicit message(msgp_t m) : _msg(sd_bus_message_ref(m))
+    explicit message(msgp_t m) : message(m, &sdbus_impl)
     {
     }
 
@@ -72,7 +83,7 @@
      *
      *  Takes ownership of the msg-pointer and releases it when done.
      */
-    message(msgp_t m, std::false_type) : _msg(m)
+    message(msgp_t m, std::false_type) : _intf(&sdbus_impl), _msg(m)
     {
     }
 
@@ -95,7 +106,8 @@
      */
     template <typename... Args> void append(Args&&... args)
     {
-        sdbusplus::message::append(_msg.get(), std::forward<Args>(args)...);
+        sdbusplus::message::append(_intf, _msg.get(),
+                                   std::forward<Args>(args)...);
     }
 
     /** @brief Perform sd_bus_message_read, with automatic type deduction.
@@ -105,7 +117,8 @@
      */
     template <typename... Args> void read(Args&&... args)
     {
-        sdbusplus::message::read(_msg.get(), std::forward<Args>(args)...);
+        sdbusplus::message::read(_intf, _msg.get(),
+                                 std::forward<Args>(args)...);
     }
 
     /** @brief Get the dbus bus from the message. */
@@ -118,7 +131,7 @@
      */
     const char* get_signature()
     {
-        return sd_bus_message_get_signature(_msg.get(), true);
+        return _intf->sd_bus_message_get_signature(_msg.get(), true);
     }
 
     /** @brief Get the path of a message.
@@ -127,7 +140,7 @@
      */
     const char* get_path()
     {
-        return sd_bus_message_get_path(_msg.get());
+        return _intf->sd_bus_message_get_path(_msg.get());
     }
 
     /** @brief Get the interface of a message.
@@ -136,7 +149,7 @@
      */
     const char* get_interface()
     {
-        return sd_bus_message_get_interface(_msg.get());
+        return _intf->sd_bus_message_get_interface(_msg.get());
     }
 
     /** @brief Get the member of a message.
@@ -145,7 +158,7 @@
      */
     const char* get_member()
     {
-        return sd_bus_message_get_member(_msg.get());
+        return _intf->sd_bus_message_get_member(_msg.get());
     }
 
     /** @brief Get the destination of a message.
@@ -154,7 +167,7 @@
      */
     const char* get_destination()
     {
-        return sd_bus_message_get_destination(_msg.get());
+        return _intf->sd_bus_message_get_destination(_msg.get());
     }
 
     /** @brief Get the sender of a message.
@@ -163,7 +176,7 @@
      */
     const char* get_sender()
     {
-        return sd_bus_message_get_sender(_msg.get());
+        return _intf->sd_bus_message_get_sender(_msg.get());
     }
 
     /** @brief Check if message is a method error.
@@ -172,7 +185,7 @@
      */
     bool is_method_error()
     {
-        return sd_bus_message_is_method_error(_msg.get(), nullptr);
+        return _intf->sd_bus_message_is_method_error(_msg.get(), nullptr);
     }
 
     /** @brief Get the transaction cookie of a message.
@@ -182,7 +195,7 @@
     auto get_cookie()
     {
         uint64_t cookie;
-        sd_bus_message_get_cookie(_msg.get(), &cookie);
+        _intf->sd_bus_message_get_cookie(_msg.get(), &cookie);
         return cookie;
     }
 
@@ -195,7 +208,8 @@
      */
     bool is_method_call(const char* interface, const char* method)
     {
-        return sd_bus_message_is_method_call(_msg.get(), interface, method);
+        return _intf->sd_bus_message_is_method_call(_msg.get(), interface,
+                                                    method);
     }
 
     /** @brief Check if message is a signal for an interface/member.
@@ -205,7 +219,7 @@
      */
     bool is_signal(const char* interface, const char* member)
     {
-        return sd_bus_message_is_signal(_msg.get(), interface, member);
+        return _intf->sd_bus_message_is_signal(_msg.get(), interface, member);
     }
 
     /** @brief Create a 'method_return' type message from an existing message.
@@ -215,7 +229,7 @@
     message new_method_return()
     {
         msgp_t reply = nullptr;
-        sd_bus_message_new_method_return(this->get(), &reply);
+        _intf->sd_bus_message_new_method_return(this->get(), &reply);
 
         return message(reply, std::false_type());
     }
@@ -223,8 +237,8 @@
     /** @brief Perform a 'method-return' response call. */
     void method_return()
     {
-        auto b = sd_bus_message_get_bus(this->get());
-        sd_bus_send(b, this->get(), nullptr);
+        auto b = _intf->sd_bus_message_get_bus(this->get());
+        _intf->sd_bus_send(b, this->get(), nullptr);
     }
 
     /** @brief Perform a 'signal-send' call. */
@@ -241,6 +255,7 @@
     {
         return _msg.get();
     }
+    sdbusplus::SdBusInterface* _intf;
     details::msg _msg;
 };
 
diff --git a/sdbusplus/message/append.hpp b/sdbusplus/message/append.hpp
index daf901b..b8f6b5e 100644
--- a/sdbusplus/message/append.hpp
+++ b/sdbusplus/message/append.hpp
@@ -4,6 +4,7 @@
 
 #include <systemd/sd-bus.h>
 #include <sdbusplus/message/types.hpp>
+#include <sdbusplus/sdbus.hpp>
 #include <sdbusplus/utility/container_traits.hpp>
 #include <sdbusplus/utility/tuple_to_array.hpp>
 #include <sdbusplus/utility/type_traits.hpp>
@@ -19,7 +20,7 @@
  *  (This is an empty no-op function that is useful in some cases for
  *   variadic template reasons.)
  */
-inline void append(sd_bus_message* m){};
+inline void append(sdbusplus::SdBusInterface* intf, sd_bus_message* m){};
 /** @brief Append data into an sdbus message.
  *
  *  @param[in] msg - The message to append to.
@@ -31,7 +32,8 @@
  *  appropriate type parameters.  It may also do conversions, where needed,
  *  to convert C++ types into C representations (eg. string, vector).
  */
-template <typename... Args> void append(sd_bus_message* m, Args&&... args);
+template <typename... Args>
+void append(sdbusplus::SdBusInterface* intf, sd_bus_message* m, Args&&... args);
 
 namespace details
 {
@@ -138,7 +140,7 @@
      */
     template <typename T,
               typename = std::enable_if_t<std::is_same<S, Td<T>>::value>>
-    static void op(sd_bus_message* m, T&& t)
+    static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m, T&& t)
     {
         // For this default implementation, we need to ensure that only
         // basic types are used.
@@ -147,8 +149,8 @@
                       "Non-basic types are not allowed.");
 
         constexpr auto dbusType = std::get<0>(types::type_id<T>());
-        sd_bus_message_append_basic(m, dbusType,
-                                    address_of(std::forward<T>(t)));
+        intf->sd_bus_message_append_basic(m, dbusType,
+                                          address_of(std::forward<T>(t)));
     }
 };
 
@@ -158,31 +160,34 @@
 /** @brief Specialization of append_single for std::strings. */
 template <> struct append_single<std::string>
 {
-    template <typename T> static void op(sd_bus_message* m, T&& s)
+    template <typename T>
+    static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m, T&& s)
     {
         constexpr auto dbusType = std::get<0>(types::type_id<T>());
-        sd_bus_message_append_basic(m, dbusType, s.c_str());
+        intf->sd_bus_message_append_basic(m, dbusType, s.c_str());
     }
 };
 
 /** @brief Specialization of append_single for details::string_wrapper. */
 template <typename T> struct append_single<details::string_wrapper<T>>
 {
-    template <typename S> static void op(sd_bus_message* m, S&& s)
+    template <typename S>
+    static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m, S&& s)
     {
         constexpr auto dbusType = std::get<0>(types::type_id<S>());
-        sd_bus_message_append_basic(m, dbusType, s.str.c_str());
+        intf->sd_bus_message_append_basic(m, dbusType, s.str.c_str());
     }
 };
 
 /** @brief Specialization of append_single for bool. */
 template <> struct append_single<bool>
 {
-    template <typename T> static void op(sd_bus_message* m, T&& b)
+    template <typename T>
+    static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m, T&& b)
     {
         constexpr auto dbusType = std::get<0>(types::type_id<T>());
         int i = b;
-        sd_bus_message_append_basic(m, dbusType, &i);
+        intf->sd_bus_message_append_basic(m, dbusType, &i);
     }
 };
 
@@ -191,32 +196,34 @@
 template <typename T>
 struct append_single<T, std::enable_if_t<utility::has_const_iterator<T>::value>>
 {
-    template <typename S> static void op(sd_bus_message* m, S&& s)
+    template <typename S>
+    static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m, S&& s)
     {
         constexpr auto dbusType = utility::tuple_to_array(types::type_id<T>());
 
-        sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
-                                      dbusType.data() + 1);
+        intf->sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
+                                            dbusType.data() + 1);
         for (auto& i : s)
         {
-            sdbusplus::message::append(m, i);
+            sdbusplus::message::append(intf, m, i);
         }
-        sd_bus_message_close_container(m);
+        intf->sd_bus_message_close_container(m);
     }
 };
 
 /** @brief Specialization of append_single for std::pairs. */
 template <typename T1, typename T2> struct append_single<std::pair<T1, T2>>
 {
-    template <typename S> static void op(sd_bus_message* m, S&& s)
+    template <typename S>
+    static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m, S&& s)
     {
         constexpr auto dbusType = utility::tuple_to_array(
             std::tuple_cat(types::type_id_nonull<T1>(), types::type_id<T2>()));
 
-        sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
-                                      dbusType.data());
-        sdbusplus::message::append(m, s.first, s.second);
-        sd_bus_message_close_container(m);
+        intf->sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
+                                            dbusType.data());
+        sdbusplus::message::append(intf, m, s.first, s.second);
+        intf->sd_bus_message_close_container(m);
     }
 };
 
@@ -224,21 +231,24 @@
 template <typename... Args> struct append_single<std::tuple<Args...>>
 {
     template <typename S, std::size_t... I>
-    static void _op(sd_bus_message* m, S&& s,
+    static void _op(sdbusplus::SdBusInterface* intf, sd_bus_message* m, S&& s,
                     std::integer_sequence<std::size_t, I...>)
     {
-        sdbusplus::message::append(m, std::get<I>(s)...);
+        sdbusplus::message::append(intf, m, std::get<I>(s)...);
     }
 
-    template <typename S> static void op(sd_bus_message* m, S&& s)
+    template <typename S>
+    static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m, S&& s)
     {
         constexpr auto dbusType = utility::tuple_to_array(std::tuple_cat(
             types::type_id_nonull<Args...>(),
             std::make_tuple('\0') /* null terminator for C-string */));
 
-        sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, dbusType.data());
-        _op(m, std::forward<S>(s), std::make_index_sequence<sizeof...(Args)>());
-        sd_bus_message_close_container(m);
+        intf->sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
+                                            dbusType.data());
+        _op(intf, m, std::forward<S>(s),
+            std::make_index_sequence<sizeof...(Args)>());
+        intf->sd_bus_message_close_container(m);
     }
 };
 
@@ -246,38 +256,53 @@
 template <typename... Args> struct append_single<variant<Args...>>
 {
     template <typename S, typename = std::enable_if_t<0 < sizeof...(Args)>>
-    static void op(sd_bus_message* m, S&& s)
+    static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m, S&& s)
     {
-        auto apply = [m](auto&& arg) {
+        auto apply = [intf, m](auto&& arg) {
             constexpr auto dbusType =
                 utility::tuple_to_array(types::type_id<decltype(arg)>());
 
-            sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
-                                          dbusType.data());
-            sdbusplus::message::append(m, arg);
-            sd_bus_message_close_container(m);
+            intf->sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
+                                                dbusType.data());
+            sdbusplus::message::append(intf, m, arg);
+            intf->sd_bus_message_close_container(m);
         };
 
         std::remove_reference_t<S>::visit(s, apply);
     }
 };
 
-/** @brief Append a tuple of content into the sd_bus_message.
- *
- *  @tparam Tuple - The tuple type to append.
- *  @param[in] t - The tuple value to append.
- *  @tparam I - The indexes of the tuple type Tuple.
- *  @param[in] [unnamed] - unused index_sequence for type deduction of I.
- */
-template <typename Tuple, size_t... I>
-void append_tuple(sd_bus_message* m, Tuple&& t, std::index_sequence<I...>)
+template <typename T>
+static void tuple_item_append(sdbusplus::SdBusInterface* intf,
+                              sd_bus_message* m, T&& t)
 {
-    auto dbusTypes =
-        utility::tuple_to_array(types::type_id<decltype(std::get<I>(t))...>());
-
-    sd_bus_message_append(m, dbusTypes.data(), std::get<I>(t)...);
+    sdbusplus::message::append(intf, m, t);
 }
 
+template <int Index> struct AppendHelper
+{
+    template <typename... Fields>
+    static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m,
+                   std::tuple<Fields...> field_tuple)
+    {
+        auto field = std::get<Index - 1>(field_tuple);
+
+        AppendHelper<Index - 1>::op(intf, m, std::move(field_tuple));
+
+        tuple_item_append(intf, m, field);
+    }
+};
+
+template <> struct AppendHelper<1>
+{
+    template <typename... Fields>
+    static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m,
+                   std::tuple<Fields...> field_tuple)
+    {
+        tuple_item_append(intf, m, std::get<0>(field_tuple));
+    }
+};
+
 /** @brief Append a tuple of 2 or more entries into the sd_bus_message.
  *
  *  @tparam Tuple - The tuple type to append.
@@ -288,10 +313,14 @@
  */
 template <typename Tuple>
 std::enable_if_t<2 <= std::tuple_size<Tuple>::value>
-    append_tuple(sd_bus_message* m, Tuple&& t)
+    append_tuple(sdbusplus::SdBusInterface* intf, sd_bus_message* m, Tuple&& t)
 {
-    append_tuple(m, std::move(t),
-                 std::make_index_sequence<std::tuple_size<Tuple>::value>());
+    // This was called because the tuple had at least 2 items in it.
+
+    AppendHelper<std::tuple_size<Tuple>::value>::op(intf, m, std::move(t));
+
+    //    append_tuple(intf, m, std::move(t),
+    //                 std::make_index_sequence<std::tuple_size<Tuple>::value>());
 }
 
 /** @brief Append a tuple of exactly 1 entry into the sd_bus_message.
@@ -306,10 +335,11 @@
  */
 template <typename Tuple>
 std::enable_if_t<1 == std::tuple_size<Tuple>::value>
-    append_tuple(sd_bus_message* m, Tuple&& t)
+    append_tuple(sdbusplus::SdBusInterface* intf, sd_bus_message* m, Tuple&& t)
 {
     using itemType = decltype(std::get<0>(t));
-    append_single_t<itemType>::op(m, std::forward<itemType>(std::get<0>(t)));
+    append_single_t<itemType>::op(intf, m,
+                                  std::forward<itemType>(std::get<0>(t)));
 }
 
 /** @brief Append a tuple of 0 entries - no-op.
@@ -318,7 +348,7 @@
  */
 template <typename Tuple>
 std::enable_if_t<0 == std::tuple_size<Tuple>::value> inline append_tuple(
-    sd_bus_message* m, Tuple&& t)
+    sdbusplus::SdBusInterface* intf, sd_bus_message* m, Tuple&& t)
 {
 }
 
@@ -331,7 +361,8 @@
 template <typename Tuple, typename Arg>
 std::enable_if_t<
     can_append_multiple<types::details::type_id_downcast_t<Arg>>::value>
-    append_grouping(sd_bus_message* m, Tuple&& t, Arg&& arg);
+    append_grouping(sdbusplus::SdBusInterface* intf, sd_bus_message* m,
+                    Tuple&& t, Arg&& arg);
 /** @brief Group a sequence of C++ types for appending into an sd_bus_message.
  *  @tparam Tuple - A tuple of previously analyzed types.
  *  @tparam Arg - The argument to analyze for grouping.
@@ -341,7 +372,8 @@
 template <typename Tuple, typename Arg>
 std::enable_if_t<
     !can_append_multiple<types::details::type_id_downcast_t<Arg>>::value>
-    append_grouping(sd_bus_message* m, Tuple&& t, Arg&& arg);
+    append_grouping(sdbusplus::SdBusInterface* intf, sd_bus_message* m,
+                    Tuple&& t, Arg&& arg);
 /** @brief Group a sequence of C++ types for appending into an sd_bus_message.
  *  @tparam Tuple - A tuple of previously analyzed types.
  *  @tparam Arg - The argument to analyze for grouping.
@@ -352,7 +384,8 @@
 template <typename Tuple, typename Arg, typename... Rest>
 std::enable_if_t<
     can_append_multiple<types::details::type_id_downcast_t<Arg>>::value>
-    append_grouping(sd_bus_message* m, Tuple&& t, Arg&& arg, Rest&&... rest);
+    append_grouping(sdbusplus::SdBusInterface* intf, sd_bus_message* m,
+                    Tuple&& t, Arg&& arg, Rest&&... rest);
 /** @brief Group a sequence of C++ types for appending into an sd_bus_message.
  *  @tparam Tuple - A tuple of previously analyzed types.
  *  @tparam Arg - The argument to analyze for grouping.
@@ -363,17 +396,19 @@
 template <typename Tuple, typename Arg, typename... Rest>
 std::enable_if_t<
     !can_append_multiple<types::details::type_id_downcast_t<Arg>>::value>
-    append_grouping(sd_bus_message* m, Tuple&& t, Arg&& arg, Rest&&... rest);
+    append_grouping(sdbusplus::SdBusInterface* intf, sd_bus_message* m,
+                    Tuple&& t, Arg&& arg, Rest&&... rest);
 
 template <typename Tuple, typename Arg>
 std::enable_if_t<
     can_append_multiple<types::details::type_id_downcast_t<Arg>>::value>
-    append_grouping(sd_bus_message* m, Tuple&& t, Arg&& arg)
+    append_grouping(sdbusplus::SdBusInterface* intf, sd_bus_message* m,
+                    Tuple&& t, Arg&& arg)
 {
     // Last element of a sequence and can_append_multiple, so add it to
     // the tuple and call append_tuple.
 
-    append_tuple(m,
+    append_tuple(intf, m,
                  std::tuple_cat(std::forward<Tuple>(t),
                                 std::forward_as_tuple(std::forward<Arg>(arg))));
 }
@@ -381,26 +416,28 @@
 template <typename Tuple, typename Arg>
 std::enable_if_t<
     !can_append_multiple<types::details::type_id_downcast_t<Arg>>::value>
-    append_grouping(sd_bus_message* m, Tuple&& t, Arg&& arg)
+    append_grouping(sdbusplus::SdBusInterface* intf, sd_bus_message* m,
+                    Tuple&& t, Arg&& arg)
 {
     // Last element of a sequence but !can_append_multiple, so call
     // append_tuple on the previous elements and separately this single
     // element.
 
-    append_tuple(m, std::forward<Tuple>(t));
-    append_tuple(m, std::forward_as_tuple(std::forward<Arg>(arg)));
+    append_tuple(intf, m, std::forward<Tuple>(t));
+    append_tuple(intf, m, std::forward_as_tuple(std::forward<Arg>(arg)));
 }
 
 template <typename Tuple, typename Arg, typename... Rest>
 std::enable_if_t<
     can_append_multiple<types::details::type_id_downcast_t<Arg>>::value>
-    append_grouping(sd_bus_message* m, Tuple&& t, Arg&& arg, Rest&&... rest)
+    append_grouping(sdbusplus::SdBusInterface* intf, sd_bus_message* m,
+                    Tuple&& t, Arg&& arg, Rest&&... rest)
 {
     // Not the last element of a sequence and can_append_multiple, so add it
     // to the tuple and keep grouping.
 
     append_grouping(
-        m,
+        intf, m,
         std::tuple_cat(std::forward<Tuple>(t),
                        std::forward_as_tuple(std::forward<Arg>(arg))),
         std::forward<Rest>(rest)...);
@@ -409,22 +446,25 @@
 template <typename Tuple, typename Arg, typename... Rest>
 std::enable_if_t<
     !can_append_multiple<types::details::type_id_downcast_t<Arg>>::value>
-    append_grouping(sd_bus_message* m, Tuple&& t, Arg&& arg, Rest&&... rest)
+    append_grouping(sdbusplus::SdBusInterface* intf, sd_bus_message* m,
+                    Tuple&& t, Arg&& arg, Rest&&... rest)
 {
     // Not the last element of a sequence but !can_append_multiple, so call
     // append_tuple on the previous elements and separately this single
     // element and then group the remaining elements.
 
-    append_tuple(m, std::forward<Tuple>(t));
-    append_tuple(m, std::forward_as_tuple(std::forward<Arg>(arg)));
-    append_grouping(m, std::make_tuple(), std::forward<Rest>(rest)...);
+    append_tuple(intf, m, std::forward<Tuple>(t));
+    append_tuple(intf, m, std::forward_as_tuple(std::forward<Arg>(arg)));
+    append_grouping(intf, m, std::make_tuple(), std::forward<Rest>(rest)...);
 }
 
 } // namespace details
 
-template <typename... Args> void append(sd_bus_message* m, Args&&... args)
+template <typename... Args>
+void append(sdbusplus::SdBusInterface* intf, sd_bus_message* m, Args&&... args)
 {
-    details::append_grouping(m, std::make_tuple(), std::forward<Args>(args)...);
+    details::append_grouping(intf, m, std::make_tuple(),
+                             std::forward<Args>(args)...);
 }
 
 } // namespace message
diff --git a/sdbusplus/message/read.hpp b/sdbusplus/message/read.hpp
index 66bcbad..b52267e 100644
--- a/sdbusplus/message/read.hpp
+++ b/sdbusplus/message/read.hpp
@@ -17,7 +17,7 @@
  *  (This is an empty no-op function that is useful in some cases for
  *   variadic template reasons.)
  */
-inline void read(sd_bus_message* m){};
+inline void read(sdbusplus::SdBusInterface* intf, sd_bus_message* m){};
 /** @brief Read data from an sdbus message.
  *
  *  @param[in] msg - The message to read from.
@@ -29,7 +29,8 @@
  *  appropriate type parameters.  It may also do conversions, where needed,
  *  to convert C++ types into C representations (eg. string, vector).
  */
-template <typename... Args> void read(sd_bus_message* m, Args&&... args);
+template <typename... Args>
+void read(sdbusplus::SdBusInterface* intf, sd_bus_message* m, Args&&... args);
 
 namespace details
 {
@@ -120,7 +121,7 @@
      */
     template <typename T,
               typename = std::enable_if_t<std::is_same<S, Td<T>>::value>>
-    static void op(sd_bus_message* m, T&& t)
+    static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m, T&& t)
     {
         // For this default implementation, we need to ensure that only
         // basic types are used.
@@ -129,7 +130,7 @@
                       "Non-basic types are not allowed.");
 
         constexpr auto dbusType = std::get<0>(types::type_id<T>());
-        sd_bus_message_read_basic(m, dbusType, &t);
+        intf->sd_bus_message_read_basic(m, dbusType, &t);
     }
 };
 
@@ -139,11 +140,12 @@
 /** @brief Specialization of read_single for std::strings. */
 template <> struct read_single<std::string>
 {
-    template <typename T> static void op(sd_bus_message* m, T&& s)
+    template <typename T>
+    static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m, T&& s)
     {
         constexpr auto dbusType = std::get<0>(types::type_id<T>());
         const char* str = nullptr;
-        sd_bus_message_read_basic(m, dbusType, &str);
+        intf->sd_bus_message_read_basic(m, dbusType, &str);
         s = str;
     }
 };
@@ -151,11 +153,12 @@
 /** @brief Specialization of read_single for details::string_wrapper. */
 template <typename T> struct read_single<details::string_wrapper<T>>
 {
-    template <typename S> static void op(sd_bus_message* m, S&& s)
+    template <typename S>
+    static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m, S&& s)
     {
         constexpr auto dbusType = std::get<0>(types::type_id<S>());
         const char* str = nullptr;
-        sd_bus_message_read_basic(m, dbusType, &str);
+        intf->sd_bus_message_read_basic(m, dbusType, &str);
         s.str = str;
     }
 };
@@ -163,11 +166,12 @@
 /** @brief Specialization of read_single for bools. */
 template <> struct read_single<bool>
 {
-    template <typename T> static void op(sd_bus_message* m, T&& b)
+    template <typename T>
+    static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m, T&& b)
     {
         constexpr auto dbusType = std::get<0>(types::type_id<T>());
         int i = 0;
-        sd_bus_message_read_basic(m, dbusType, &i);
+        intf->sd_bus_message_read_basic(m, dbusType, &i);
         b = (i != 0);
     }
 };
@@ -177,20 +181,21 @@
 struct read_single<T,
                    std::enable_if_t<utility::has_emplace_back_method<T>::value>>
 {
-    template <typename S> static void op(sd_bus_message* m, S&& s)
+    template <typename S>
+    static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m, S&& s)
     {
         constexpr auto dbusType = utility::tuple_to_array(types::type_id<T>());
-        sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY,
-                                       dbusType.data() + 1);
+        intf->sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY,
+                                             dbusType.data() + 1);
 
-        while (!sd_bus_message_at_end(m, false))
+        while (!intf->sd_bus_message_at_end(m, false))
         {
             types::details::type_id_downcast_t<typename T::value_type> t;
-            sdbusplus::message::read(m, t);
+            sdbusplus::message::read(intf, m, t);
             s.emplace_back(std::move(t));
         }
 
-        sd_bus_message_exit_container(m);
+        intf->sd_bus_message_exit_container(m);
     }
 };
 
@@ -198,35 +203,37 @@
 template <typename T>
 struct read_single<T, std::enable_if_t<utility::has_emplace_method<T>::value>>
 {
-    template <typename S> static void op(sd_bus_message* m, S&& s)
+    template <typename S>
+    static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m, S&& s)
     {
         constexpr auto dbusType = utility::tuple_to_array(types::type_id<T>());
-        sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY,
-                                       dbusType.data() + 1);
+        intf->sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY,
+                                             dbusType.data() + 1);
 
-        while (!sd_bus_message_at_end(m, false))
+        while (!intf->sd_bus_message_at_end(m, false))
         {
             types::details::type_id_downcast_t<typename T::value_type> t;
-            sdbusplus::message::read(m, t);
+            sdbusplus::message::read(intf, m, t);
             s.emplace(std::move(t));
         }
 
-        sd_bus_message_exit_container(m);
+        intf->sd_bus_message_exit_container(m);
     }
 };
 
 /** @brief Specialization of read_single for std::pairs. */
 template <typename T1, typename T2> struct read_single<std::pair<T1, T2>>
 {
-    template <typename S> static void op(sd_bus_message* m, S&& s)
+    template <typename S>
+    static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m, S&& s)
     {
         constexpr auto dbusType = utility::tuple_to_array(
             std::tuple_cat(types::type_id_nonull<T1>(), types::type_id<T2>()));
 
-        sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY,
-                                       dbusType.data());
-        sdbusplus::message::read(m, s.first, s.second);
-        sd_bus_message_exit_container(m);
+        intf->sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY,
+                                             dbusType.data());
+        sdbusplus::message::read(intf, m, s.first, s.second);
+        intf->sd_bus_message_exit_container(m);
     }
 };
 
@@ -234,21 +241,24 @@
 template <typename... Args> struct read_single<std::tuple<Args...>>
 {
     template <typename S, std::size_t... I>
-    static void _op(sd_bus_message* m, S&& s,
+    static void _op(sdbusplus::SdBusInterface* intf, sd_bus_message* m, S&& s,
                     std::integer_sequence<std::size_t, I...>)
     {
-        sdbusplus::message::read(m, std::get<I>(s)...);
+        sdbusplus::message::read(intf, m, std::get<I>(s)...);
     }
 
-    template <typename S> static void op(sd_bus_message* m, S&& s)
+    template <typename S>
+    static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m, S&& s)
     {
         constexpr auto dbusType = utility::tuple_to_array(std::tuple_cat(
             types::type_id_nonull<Args...>(),
             std::make_tuple('\0') /* null terminator for C-string */));
 
-        sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, dbusType.data());
-        _op(m, std::forward<S>(s), std::make_index_sequence<sizeof...(Args)>());
-        sd_bus_message_exit_container(m);
+        intf->sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT,
+                                             dbusType.data());
+        _op(intf, m, std::forward<S>(s),
+            std::make_index_sequence<sizeof...(Args)>());
+        intf->sd_bus_message_exit_container(m);
     }
 };
 
@@ -256,56 +266,73 @@
 template <typename... Args> struct read_single<variant<Args...>>
 {
     template <typename S, typename S1, typename... Args1>
-    static void read(sd_bus_message* m, S&& s)
+    static void read(sdbusplus::SdBusInterface* intf, sd_bus_message* m, S&& s)
     {
         constexpr auto dbusType = utility::tuple_to_array(types::type_id<S1>());
 
-        auto rc =
-            sd_bus_message_verify_type(m, SD_BUS_TYPE_VARIANT, dbusType.data());
+        auto rc = intf->sd_bus_message_verify_type(m, SD_BUS_TYPE_VARIANT,
+                                                   dbusType.data());
         if (0 >= rc)
         {
-            read<S, Args1...>(m, s);
+            read<S, Args1...>(intf, m, s);
             return;
         }
 
         std::remove_reference_t<S1> s1;
 
-        sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, dbusType.data());
-        sdbusplus::message::read(m, s1);
-        sd_bus_message_exit_container(m);
+        intf->sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT,
+                                             dbusType.data());
+        sdbusplus::message::read(intf, m, s1);
+        intf->sd_bus_message_exit_container(m);
 
         s = std::move(s1);
     }
 
-    template <typename S> static void read(sd_bus_message* m, S&& s)
+    template <typename S>
+    static void read(sdbusplus::SdBusInterface* intf, sd_bus_message* m, S&& s)
     {
-        sd_bus_message_skip(m, "v");
+        intf->sd_bus_message_skip(m, "v");
         s = std::remove_reference_t<S>{};
     }
 
     template <typename S, typename = std::enable_if_t<0 < sizeof...(Args)>>
-    static void op(sd_bus_message* m, S&& s)
+    static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m, S&& s)
     {
-        read<S, Args...>(m, s);
+        read<S, Args...>(intf, m, s);
     }
 };
 
-/** @brief Read a tuple of content from the sd_bus_message.
- *
- *  @tparam Tuple - The tuple type to read.
- *  @param[out] t - The tuple references to read.
- *  @tparam I - The indexes of the tuple type Tuple.
- *  @param[in] [unnamed] - unused index_sequence for type deduction of I.
- */
-template <typename Tuple, size_t... I>
-void read_tuple(sd_bus_message* m, Tuple&& t, std::index_sequence<I...>)
+template <typename T>
+static void tuple_item_read(sdbusplus::SdBusInterface* intf, sd_bus_message* m,
+                            T&& t)
 {
-    auto dbusTypes =
-        utility::tuple_to_array(types::type_id<decltype(std::get<I>(t))...>());
-
-    sd_bus_message_read(m, dbusTypes.data(), &std::get<I>(t)...);
+    sdbusplus::message::read(intf, m, t);
 }
 
+template <int Index> struct ReadHelper
+{
+    template <typename... Fields>
+    static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m,
+                   std::tuple<Fields...> field_tuple)
+    {
+        auto& field = std::get<Index - 1>(field_tuple);
+
+        ReadHelper<Index - 1>::op(intf, m, std::move(field_tuple));
+
+        tuple_item_read(intf, m, field);
+    }
+};
+
+template <> struct ReadHelper<1>
+{
+    template <typename... Fields>
+    static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m,
+                   std::tuple<Fields...> field_tuple)
+    {
+        tuple_item_read(intf, m, std::get<0>(field_tuple));
+    }
+};
+
 /** @brief Read a tuple of 2 or more entries from the sd_bus_message.
  *
  *  @tparam Tuple - The tuple type to read.
@@ -316,10 +343,11 @@
  */
 template <typename Tuple>
 std::enable_if_t<2 <= std::tuple_size<Tuple>::value>
-    read_tuple(sd_bus_message* m, Tuple&& t)
+    read_tuple(sdbusplus::SdBusInterface* intf, sd_bus_message* m, Tuple&& t)
 {
-    read_tuple(m, std::move(t),
-               std::make_index_sequence<std::tuple_size<Tuple>::value>());
+    ReadHelper<std::tuple_size<Tuple>::value>::op(intf, m, std::move(t));
+    // read_tuple(intf, m, std::move(t),
+    //           std::make_index_sequence<std::tuple_size<Tuple>::value>());
 }
 
 /** @brief Read a tuple of exactly 1 entry from the sd_bus_message.
@@ -334,10 +362,11 @@
  */
 template <typename Tuple>
 std::enable_if_t<1 == std::tuple_size<Tuple>::value>
-    read_tuple(sd_bus_message* m, Tuple&& t)
+    read_tuple(sdbusplus::SdBusInterface* intf, sd_bus_message* m, Tuple&& t)
 {
     using itemType = decltype(std::get<0>(t));
-    read_single_t<itemType>::op(m, std::forward<itemType>(std::get<0>(t)));
+    read_single_t<itemType>::op(intf, m,
+                                std::forward<itemType>(std::get<0>(t)));
 }
 
 /** @brief Read a tuple of 0 entries - no-op.
@@ -346,7 +375,7 @@
  */
 template <typename Tuple>
 std::enable_if_t<0 == std::tuple_size<Tuple>::value> inline read_tuple(
-    sd_bus_message* m, Tuple&& t)
+    sdbusplus::SdBusInterface* intf, sd_bus_message* m, Tuple&& t)
 {
 }
 
@@ -359,7 +388,8 @@
 template <typename Tuple, typename Arg>
 std::enable_if_t<
     can_read_multiple<types::details::type_id_downcast_t<Arg>>::value>
-    read_grouping(sd_bus_message* m, Tuple&& t, Arg&& arg);
+    read_grouping(sdbusplus::SdBusInterface* intf, sd_bus_message* m, Tuple&& t,
+                  Arg&& arg);
 /** @brief Group a sequence of C++ types for reading from an sd_bus_message.
  *  @tparam Tuple - A tuple of previously analyzed types.
  *  @tparam Arg - The argument to analyze for grouping.
@@ -369,7 +399,8 @@
 template <typename Tuple, typename Arg>
 std::enable_if_t<
     !can_read_multiple<types::details::type_id_downcast_t<Arg>>::value>
-    read_grouping(sd_bus_message* m, Tuple&& t, Arg&& arg);
+    read_grouping(sdbusplus::SdBusInterface* intf, sd_bus_message* m, Tuple&& t,
+                  Arg&& arg);
 /** @brief Group a sequence of C++ types for reading from an sd_bus_message.
  *  @tparam Tuple - A tuple of previously analyzed types.
  *  @tparam Arg - The argument to analyze for grouping.
@@ -380,7 +411,8 @@
 template <typename Tuple, typename Arg, typename... Rest>
 std::enable_if_t<
     can_read_multiple<types::details::type_id_downcast_t<Arg>>::value>
-    read_grouping(sd_bus_message* m, Tuple&& t, Arg&& arg, Rest&&... rest);
+    read_grouping(sdbusplus::SdBusInterface* intf, sd_bus_message* m, Tuple&& t,
+                  Arg&& arg, Rest&&... rest);
 /** @brief Group a sequence of C++ types for reading from an sd_bus_message.
  *  @tparam Tuple - A tuple of previously analyzed types.
  *  @tparam Arg - The argument to analyze for grouping.
@@ -391,17 +423,19 @@
 template <typename Tuple, typename Arg, typename... Rest>
 std::enable_if_t<
     !can_read_multiple<types::details::type_id_downcast_t<Arg>>::value>
-    read_grouping(sd_bus_message* m, Tuple&& t, Arg&& arg, Rest&&... rest);
+    read_grouping(sdbusplus::SdBusInterface* intf, sd_bus_message* m, Tuple&& t,
+                  Arg&& arg, Rest&&... rest);
 
 template <typename Tuple, typename Arg>
 std::enable_if_t<
     can_read_multiple<types::details::type_id_downcast_t<Arg>>::value>
-    read_grouping(sd_bus_message* m, Tuple&& t, Arg&& arg)
+    read_grouping(sdbusplus::SdBusInterface* intf, sd_bus_message* m, Tuple&& t,
+                  Arg&& arg)
 {
     // Last element of a sequence and can_read_multiple, so add it to
     // the tuple and call read_tuple.
 
-    read_tuple(m,
+    read_tuple(intf, m,
                std::tuple_cat(std::forward<Tuple>(t),
                               std::forward_as_tuple(std::forward<Arg>(arg))));
 }
@@ -409,25 +443,27 @@
 template <typename Tuple, typename Arg>
 std::enable_if_t<
     !can_read_multiple<types::details::type_id_downcast_t<Arg>>::value>
-    read_grouping(sd_bus_message* m, Tuple&& t, Arg&& arg)
+    read_grouping(sdbusplus::SdBusInterface* intf, sd_bus_message* m, Tuple&& t,
+                  Arg&& arg)
 {
     // Last element of a sequence but !can_read_multiple, so call
     // read_tuple on the previous elements and separately this single
     // element.
 
-    read_tuple(m, std::forward<Tuple>(t));
-    read_tuple(m, std::forward_as_tuple(std::forward<Arg>(arg)));
+    read_tuple(intf, m, std::forward<Tuple>(t));
+    read_tuple(intf, m, std::forward_as_tuple(std::forward<Arg>(arg)));
 }
 
 template <typename Tuple, typename Arg, typename... Rest>
 std::enable_if_t<
     can_read_multiple<types::details::type_id_downcast_t<Arg>>::value>
-    read_grouping(sd_bus_message* m, Tuple&& t, Arg&& arg, Rest&&... rest)
+    read_grouping(sdbusplus::SdBusInterface* intf, sd_bus_message* m, Tuple&& t,
+                  Arg&& arg, Rest&&... rest)
 {
     // Not the last element of a sequence and can_read_multiple, so add it
     // to the tuple and keep grouping.
 
-    read_grouping(m,
+    read_grouping(intf, m,
                   std::tuple_cat(std::forward<Tuple>(t),
                                  std::forward_as_tuple(std::forward<Arg>(arg))),
                   std::forward<Rest>(rest)...);
@@ -436,22 +472,25 @@
 template <typename Tuple, typename Arg, typename... Rest>
 std::enable_if_t<
     !can_read_multiple<types::details::type_id_downcast_t<Arg>>::value>
-    read_grouping(sd_bus_message* m, Tuple&& t, Arg&& arg, Rest&&... rest)
+    read_grouping(sdbusplus::SdBusInterface* intf, sd_bus_message* m, Tuple&& t,
+                  Arg&& arg, Rest&&... rest)
 {
     // Not the last element of a sequence but !can_read_multiple, so call
     // read_tuple on the previous elements and separately this single
     // element and then group the remaining elements.
 
-    read_tuple(m, std::forward<Tuple>(t));
-    read_tuple(m, std::forward_as_tuple(std::forward<Arg>(arg)));
-    read_grouping(m, std::make_tuple(), std::forward<Rest>(rest)...);
+    read_tuple(intf, m, std::forward<Tuple>(t));
+    read_tuple(intf, m, std::forward_as_tuple(std::forward<Arg>(arg)));
+    read_grouping(intf, m, std::make_tuple(), std::forward<Rest>(rest)...);
 }
 
 } // namespace details
 
-template <typename... Args> void read(sd_bus_message* m, Args&&... args)
+template <typename... Args>
+void read(sdbusplus::SdBusInterface* intf, sd_bus_message* m, Args&&... args)
 {
-    details::read_grouping(m, std::make_tuple(), std::forward<Args>(args)...);
+    details::read_grouping(intf, m, std::make_tuple(),
+                           std::forward<Args>(args)...);
 }
 
 } // namespace message
diff --git a/test/Makefile.am b/test/Makefile.am
index cb2ffb7..b331847 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -8,21 +8,21 @@
 
 check_PROGRAMS += bus_list_names
 bus_list_names_SOURCES = bus/list_names.cpp
-bus_list_names_LDADD = $(gtest_ldadd) $(SYSTEMD_LIBS)
+bus_list_names_LDADD = $(gtest_ldadd) $(SYSTEMD_LIBS) $(top_builddir)/sdbusplus/sdbus.o
 
 check_PROGRAMS += bus_match
 bus_match_SOURCES = bus/match.cpp
-bus_match_LDADD = $(gtest_ldadd) $(SYSTEMD_LIBS)
+bus_match_LDADD = $(gtest_ldadd) $(SYSTEMD_LIBS) $(top_builddir)/sdbusplus/sdbus.o
 
 check_PROGRAMS += message_append
 message_append_SOURCES = message/append.cpp
 message_append_CXXFLAGS = $(SYSTEMD_CFLAGS) $(PTHREAD_CFLAGS)
-message_append_LDADD = $(SYSTEMD_LIBS) $(PTHREAD_LIBS)
+message_append_LDADD = $(SYSTEMD_LIBS) $(PTHREAD_LIBS) $(top_builddir)/sdbusplus/sdbus.o
 
 check_PROGRAMS += message_read
 message_read_SOURCES = message/read.cpp
 message_read_CXXFLAGS = $(SYSTEMD_CFLAGS) $(PTHREAD_CFLAGS)
-message_read_LDADD = $(SYSTEMD_LIBS) $(PTHREAD_LIBS)
+message_read_LDADD = $(SYSTEMD_LIBS) $(PTHREAD_LIBS) $(top_builddir)/sdbusplus/sdbus.o
 
 check_PROGRAMS += message_native_types
 message_native_types_SOURCES = message/native_types.cpp