eldbus-cxx: Implementation of eldbus C++ API

Summary:
Applications can:

  void method_callback(void* data, const Eldbus_Service_Interface* iface,
                       const Eldbus_Message* message);
  struct { ... } data_struct;

  Eldbus_Method methods[] =
   {
     "method1", ELDBUS_ARGS("b", "bool"), ELDBUS_ARGS("b", "bool"), ELDBUS_METHOD_FLAG_HAS_DATA
     , (Eldbus_Method_Cb)&method_callback, &data_struct
   };

   And method_callback will be called with data parameter pointing to data_struct global object.

Also, Eldbus-cxx supports registering an interface passing a lambda or
function object as method. For example:

  edb::service_interface iface = edb::service_interface_register
    (c, path, interface
     , es::method("SendStringAndBool"
                  , [expected_string, expected_bool] (std::string const& n, bool b
                                                      , bool* out)
                  {
                    std::cout << "Running SendStringAndBool" << std::endl;
                    ck_assert(n == expected_string);
                    ck_assert(b == expected_bool);
                    *out = b;
                    return n;
                  }
                  , es::ins<std::string, bool>("string", "bool")
                  , es::outs<std::string, bool>("string", "bool")
                  )
    );

When a request for "SendStringAndBool" with the proper signature is
called, executes the lambda and replies with the return value and
its bool* out parameter value.

Reviewers: cedric, woohyun, raster

CC: savio, cedric

Differential Revision: https://phab.enlightenment.org/D1052
efl-1.11
Felipe Magno de Almeida 9 years ago committed by Carsten Haitzler (Rasterman)
parent ddac21534f
commit 30df128be5
  1. 2
      src/Makefile.am
  2. 2
      src/Makefile_Eet_Cxx.am
  3. 3
      src/Makefile_Eina_Cxx.am
  4. 47
      src/Makefile_Eldbus_Cxx.am
  5. 7
      src/bindings/eet_cxx/Eet.hh
  6. 10
      src/bindings/eina_cxx/eina_fold.hh
  7. 30
      src/bindings/eina_cxx/eina_integer_sequence.hh
  8. 12
      src/bindings/eina_cxx/eina_tuple.hh
  9. 38
      src/bindings/eina_cxx/eina_tuple_unwrap.hh
  10. 13
      src/bindings/eldbus_cxx/Eldbus.hh
  11. 150
      src/bindings/eldbus_cxx/eldbus_basic.hh
  12. 22
      src/bindings/eldbus_cxx/eldbus_error.hh
  13. 73
      src/bindings/eldbus_cxx/eldbus_freedesktop.hh
  14. 41
      src/bindings/eldbus_cxx/eldbus_integer_sequence.hh
  15. 283
      src/bindings/eldbus_cxx/eldbus_message.hh
  16. 56
      src/bindings/eldbus_cxx/eldbus_message_arguments.hh
  17. 117
      src/bindings/eldbus_cxx/eldbus_proxy_call.hh
  18. 30
      src/bindings/eldbus_cxx/eldbus_raw_tuple.hh
  19. 379
      src/bindings/eldbus_cxx/eldbus_service.hh
  20. 194
      src/bindings/eldbus_cxx/eldbus_signature_traits.hh
  21. 46
      src/lib/eldbus/eldbus_service.c
  22. 4
      src/lib/eldbus/eldbus_service.h
  23. 106
      src/tests/eldbus_cxx/eldbus_cxx_suite.cc
  24. 458
      src/tests/eldbus_cxx/eldbus_cxx_test_eldbus_client.cc
  25. 32
      src/tests/eldbus_cxx/eldbus_cxx_test_eldbus_connect.cc

@ -32,6 +32,7 @@ include Makefile_Evil.am
include Makefile_Escape.am
include Makefile_Eina.am
include Makefile_Eina_Cxx.am
include Makefile_Eo.am
include Makefile_Eet.am
include Makefile_Eolian.am
@ -76,6 +77,7 @@ include Makefile_Evas_Cxx.am
endif
include Makefile_Eina_Cxx.am
include Makefile_Eldbus_Cxx.am
include Makefile_Eolian_Cxx.am
include Makefile_Eet_Cxx.am
include Makefile_Eo_Cxx.am

@ -8,9 +8,7 @@ dist_installed_eetcxxmainheaders_DATA = bindings/eet_cxx/Eet.hh
installed_eetcxxheadersdir = $(includedir)/eet-cxx-@VMAJ@/eet-cxx
dist_installed_eetcxxheaders_DATA = \
bindings/eet_cxx/eet_composite.hh \
bindings/eet_cxx/eet_fold.hh \
bindings/eet_cxx/eet_register.hh \
bindings/eet_cxx/eet_tuple.hh \
bindings/eet_cxx/eet_type.hh
### Unit tests

@ -11,6 +11,7 @@ dist_installed_einacxxheaders_DATA = \
bindings/eina_cxx/eina_accessor.hh \
bindings/eina_cxx/eina_clone_allocators.hh \
bindings/eina_cxx/eina_error.hh \
bindings/eina_cxx/eina_fold.hh \
bindings/eina_cxx/eina_inarray.hh \
bindings/eina_cxx/eina_inlist.hh \
bindings/eina_cxx/eina_integer_sequence.hh \
@ -24,6 +25,8 @@ bindings/eina_cxx/eina_range_types.hh \
bindings/eina_cxx/eina_ref.hh \
bindings/eina_cxx/eina_stringshare.hh \
bindings/eina_cxx/eina_thread.hh \
bindings/eina_cxx/eina_tuple.hh \
bindings/eina_cxx/eina_tuple_unwrap.hh \
bindings/eina_cxx/eina_type_traits.hh \
bindings/eina_cxx/eina_value.hh

@ -0,0 +1,47 @@
### Library
installed_eldbuscxxmainheadersdir = $(includedir)/eldbus_cxx-@VMAJ@
dist_installed_eldbuscxxmainheaders_DATA = \
bindings/eldbus_cxx/eldbus_basic.hh \
bindings/eldbus_cxx/eldbus_error.hh \
bindings/eldbus_cxx/eldbus_freedesktop.hh \
bindings/eldbus_cxx/Eldbus.hh \
bindings/eldbus_cxx/eldbus_integer_sequence.hh \
bindings/eldbus_cxx/eldbus_message_arguments.hh \
bindings/eldbus_cxx/eldbus_message.hh \
bindings/eldbus_cxx/eldbus_proxy_call.hh \
bindings/eldbus_cxx/eldbus_raw_tuple.hh \
bindings/eldbus_cxx/eldbus_service.hh \
bindings/eldbus_cxx/eldbus_signature_traits.hh
### Unit tests
if EFL_ENABLE_TESTS
if HAVE_CXX11
check_PROGRAMS += tests/eldbus_cxx/eldbus_cxx_suite
TESTS += tests/eldbus_cxx/eldbus_cxx_suite
tests_eldbus_cxx_eldbus_cxx_suite_SOURCES = \
tests/eldbus_cxx/eldbus_cxx_suite.cc \
tests/eldbus_cxx/eldbus_cxx_test_eldbus_connect.cc \
tests/eldbus_cxx/eldbus_cxx_test_eldbus_client.cc
tests_eldbus_cxx_eldbus_cxx_suite_CPPFLAGS = \
-I$(top_builddir)/src/bindings/eina_cxx \
-I$(top_srcdir)/src/bindings/eina_cxx \
-I$(top_builddir)/src/bindings/ecore_cxx \
-I$(top_srcdir)/src/bindings/ecore_cxx \
-I$(top_builddir)/src/bindings/eldbus_cxx \
-I$(top_srcdir)/src/bindings/eldbus_cxx \
-I$(top_builddir)/src/lib/efl \
@CHECK_CFLAGS@ \
@ELDBUS_CFLAGS@ \
-DTESTS_BUILD_DIR=\"$(top_builddir)/src/tests/eldbus\"
tests_eldbus_cxx_eldbus_cxx_suite_LDADD = @CHECK_LIBS@ @USE_ELDBUS_LIBS@
tests_eldbus_cxx_eldbus_cxx_suite_DEPENDENCIES = @USE_ELDBUS_INTERNAL_LIBS@
endif
endif

@ -4,9 +4,10 @@
#include <Eet.h>
#include <eet_type.hh>
#include <eet_fold.hh>
#include <eet_register.hh>
#include <eina_fold.hh>
#include <type_traits>
#include <cassert>
#include <stdexcept>
@ -36,10 +37,10 @@ struct descriptor_type
struct push_back
{
template <typename A, typename B>
struct apply : _mpl::push_back<A, typename _detail::member_type<typename B::member_type>::type> {};
struct apply : eina::_mpl::push_back<A, typename _detail::member_type<typename B::member_type>::type> {};
};
typedef typename _mpl::fold< std::tuple<Args...>, push_back
typedef typename eina::_mpl::fold< std::tuple<Args...>, push_back
, descriptor<T> >::type type;
};

@ -1,9 +1,9 @@
#ifndef EFL_EET_FOLD_HH_
#define EFL_EET_FOLD_HH_
#ifndef EFL_EINA_FOLD_HH_
#define EFL_EINA_FOLD_HH_
#include <eet_tuple.hh>
#include <eina_tuple.hh>
namespace efl { namespace eet {
namespace efl { namespace eina {
namespace _mpl {
@ -11,7 +11,7 @@ template <typename T, typename F, typename A0, bool B = std::is_same<T, std::tup
struct fold_impl
{
typedef typename F::template apply<A0, typename std::tuple_element<0, T>::type>::type result;
typedef typename fold_impl<typename pop_front<T>::type
typedef typename fold_impl<typename _mpl::pop_front<T>::type
, F, result
>::type
type;

@ -70,6 +70,36 @@ using index_sequence = integer_sequence<std::size_t, I...>;
template <std::size_t I>
using make_index_sequence = make_integer_sequence<std::size_t, I>;
template <typename T, typename U>
struct pop_integer_sequence_t;
template <typename T>
struct pop_integer_sequence_t<integer_sequence<T>, integer_sequence<T> >
{
typedef integer_sequence<T> type;
};
template <typename T, T S0, T... S>
struct pop_integer_sequence_t<integer_sequence<T>, integer_sequence<T, S0, S...> >
{
typedef integer_sequence<T, S...> type;
};
template <typename T, T S0, T... S>
struct pop_integer_sequence_t<integer_sequence<T, S0, S...>, integer_sequence<T> >
{
typedef integer_sequence<T> type;
};
template <typename T, T S, T... Ss1, T... Ss2>
struct pop_integer_sequence_t<integer_sequence<T, S, Ss1...>, integer_sequence<T, S, Ss2...> >
: pop_integer_sequence_t<integer_sequence<T, Ss1...>, integer_sequence<T, Ss2...> >
{
};
template <typename T, typename U>
using pop_integer_sequence = typename pop_integer_sequence_t<T, U>::type;
/**
* @}
*/

@ -1,9 +1,7 @@
#ifndef EFL_EET_EET_TUPLE_HH_
#define EFL_EET_EET_TUPLE_HH_
#ifndef EFL_EINA_EINA_TUPLE_HH_
#define EFL_EINA_EINA_TUPLE_HH_
namespace efl { namespace eet {
namespace _mpl {
namespace efl { namespace eina { namespace _mpl {
template <typename A, typename... Args>
struct push_back;
@ -32,8 +30,6 @@ struct pop_front<C<T, Args...> >
typedef C<Args...> type;
};
}
} }
} } }
#endif

@ -0,0 +1,38 @@
#ifndef EINA_CXX_EINA_TUPLE_UNWRAP_HH
#define EINA_CXX_EINA_TUPLE_UNWRAP_HH
#include <eina_integer_sequence.hh>
namespace efl { namespace eina {
template <typename Callable, typename T, std::size_t... S>
auto call_tuple_unwrap(Callable const& callable, T const& tuple
, eina::index_sequence<S...>)
-> decltype(callable(std::get<S>(tuple)...))
{
return callable(std::get<S>(tuple)...);
}
template <typename Callable, typename T, std::size_t... S
, typename... Args>
auto call_tuple_unwrap_prefix(Callable const& callable, T const& tuple
, eina::index_sequence<S...>
, Args&&... args)
-> decltype(callable(std::move(args)..., std::get<S>(tuple)...))
{
return callable(std::move(args)..., std::get<S>(tuple)...);
}
template <typename Callable, typename T, std::size_t... S
, typename... Args>
auto call_tuple_unwrap_suffix(Callable const& callable, T const& tuple
, eina::index_sequence<S...>
, Args&&... args)
-> decltype(callable(std::get<S>(tuple)..., std::move(args)...))
{
return callable(std::get<S>(tuple)..., std::move(args)...);
}
} }
#endif

@ -0,0 +1,13 @@
#ifndef EFL_ELDBUS_HH_
#define EFL_ELDBUS_HH_
#include <Eina.hh>
#include <Eldbus.h>
#include <eldbus_basic.hh>
#include <eldbus_proxy_call.hh>
#include <eldbus_message.hh>
#include <eldbus_service.hh>
#include <eina_integer_sequence.hh>
#endif

@ -0,0 +1,150 @@
#ifndef ELDBUS_CXX_ELDBUS_BASIC_HH
#define ELDBUS_CXX_ELDBUS_BASIC_HH
#include <Eina.hh>
#include <Eldbus.h>
#include <eldbus_proxy_call.hh>
namespace efl { namespace eldbus {
struct unknown_t {};
struct session_t {};
struct system_t {};
struct start_t {};
struct address_t {};
unknown_t const unknown = unknown_t();
session_t const session = session_t();
system_t const system = system_t();
start_t const start = start_t();
address_t const address = address_t();
struct eldbus_init
{
eldbus_init()
{
::eldbus_init();
}
~eldbus_init()
{
::eldbus_shutdown();
}
};
struct proxy
{
typedef Eldbus_Proxy* native_handle_type;
typedef Eldbus_Proxy const* const_native_handle_type;
proxy(native_handle_type native)
: _proxy(native) {}
template <typename R, typename Callback, typename... Args>
void call(const char* method, double timeout, Callback&& callback, Args... args) const
{
eldbus::_detail::proxy_call<R>(_proxy, method, timeout, std::move(callback), args...);
}
template <typename Callback, typename... Args>
void call(const char* method, double timeout, Callback&& callback, Args... args) const
{
eldbus::_detail::proxy_call<void>(_proxy, method, timeout, std::move(callback), args...);
}
native_handle_type native_handle() { return _proxy; }
const_native_handle_type native_handle() const { return _proxy; }
private:
native_handle_type _proxy;
};
struct object
{
typedef Eldbus_Object* native_handle_type;
typedef Eldbus_Object const* const_native_handle_type;
object(native_handle_type o)
: _object(o) {}
proxy get_proxy(const char* interface_) const
{
Eldbus_Proxy* p = eldbus_proxy_get
(const_cast<object*>(this)->native_handle(), interface_);
if(!p)
{
eina::error_code ec = eina::get_error_code();
assert(!!ec);
throw eina::system_error(ec, "eldbus");
}
return proxy(p);
}
native_handle_type native_handle() { return _object; }
const_native_handle_type const_native_handle() { return _object; }
private:
native_handle_type _object;
};
struct connection
{
typedef Eldbus_Connection* native_handle_type;
typedef Eldbus_Connection const* const_native_handle_type;
explicit connection(native_handle_type connection)
: _connection(connection) {}
~connection()
{
eldbus_connection_unref(_connection);
}
connection(unknown_t)
: _connection(eldbus_connection_get(ELDBUS_CONNECTION_TYPE_UNKNOWN))
{
_check_connection();
}
connection(session_t)
: _connection(eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION))
{
_check_connection();
}
connection(system_t)
: _connection(eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SYSTEM))
{
_check_connection();
}
connection(address_t)
: _connection(eldbus_connection_get(ELDBUS_CONNECTION_TYPE_ADDRESS))
{
_check_connection();
}
object get_object(const char* bus, const char* path) const
{
Eldbus_Object* o = eldbus_object_get
(const_cast<connection*>(this)->native_handle(), bus, path);
if(!o)
{
eina::error_code ec = eina::get_error_code();
assert(!!ec);
throw eina::system_error(ec, "eldbus");
}
return object(o);
}
native_handle_type native_handle() { return _connection; }
const_native_handle_type native_handle() const { return _connection; }
private:
void _check_connection()
{
if(!_connection)
{
eina::error_code ec = eina::get_error_code();
assert(!!ec);
throw eina::system_error(ec, "eldbus");
}
}
native_handle_type _connection;
};
} }
#endif

@ -0,0 +1,22 @@
#ifndef ELDBUS_ERROR_HH
#define ELDBUS_ERROR_HH
#include <Eina.hh>
namespace efl { namespace eldbus {
inline Eina_Error call_error_code()
{
static Eina_Error error = eina_error_msg_static_register("Error while making eldbus rpc call");
return error;
}
inline Eina_Error signature_mismatch_error_code()
{
static Eina_Error error = eina_error_msg_static_register("Mismatch function signature and signature specification");
return error;
}
} }
#endif

@ -0,0 +1,73 @@
#ifndef EFL_ELDBUS_CXX_ELDBUS_FREEDESKTOP_HH
#define EFL_ELDBUS_CXX_ELDBUS_FREEDESKTOP_HH
#include <eldbus_message.hh>
#include <eldbus_service.hh>
#include <eldbus_basic.hh>
#include <eldbus_raw_tuple.hh>
namespace efl { namespace eldbus { namespace _detail {
template <typename Callback, typename... Ins>
void _callback_wrapper(void* data, Eldbus_Message const* message, Eldbus_Pending* pending)
{
std::cout << "_callback_wrapper" << std::endl;
Callback* callback(static_cast<Callback*>(data));
const char* errname, *errmsg;
if (eldbus_message_error_get(message, &errname, &errmsg))
{
std::cout << "error " << errname << " " << errmsg << std::endl;
std::tuple<Ins...> tuple;
eldbus::const_message msg( ::eldbus_message_ref(const_cast<Eldbus_Message*>(message)));
eina::error_code ec (eldbus::call_error_code(), eina::eina_error_category());
eina::call_tuple_unwrap_prefix
(*callback, tuple, eina::make_index_sequence<sizeof...(Ins)>()
, ec, msg, pending);
}
typename raw_tuple<std::tuple<Ins...> >::type tuple;
if(sizeof...(Ins))
{
if(!_detail::_init_raw_tuple<0u, std::tuple<Ins...> >
(eldbus_message_iter_get(message)
, tuple, std::integral_constant<bool, (sizeof...(Ins) == 0)>()))
{
std::cout << "error init raw tuple" << std::endl;
std::tuple<Ins...> tuple;
eldbus::const_message msg( ::eldbus_message_ref(const_cast<Eldbus_Message*>(message)));
eina::error_code ec(eldbus::signature_mismatch_error_code(), eina::eina_error_category());
eina::call_tuple_unwrap_prefix
(*callback, tuple, eina::make_index_sequence<sizeof...(Ins)>()
, ec, msg, pending);
}
}
std::cout << "OK go" << std::endl;
eina::error_code ec;
eldbus::const_message msg( ::eldbus_message_ref(const_cast<Eldbus_Message*>(message)));
eina::call_tuple_unwrap_prefix
(*callback, tuple, eina::make_index_sequence<sizeof...(Ins)>()
, ec, msg, pending);
}
template <typename F>
void _free_cb(void* data, const void*)
{
delete static_cast<F*>(data);
}
}
template <typename... Ins, typename F>
pending name_request(connection& c, const char* bus, unsigned int flags, F&& function)
{
F* f = new F(std::move(function));
pending r = ::eldbus_name_request(c.native_handle(), bus, flags
, &_detail::_callback_wrapper<F, Ins...>, f);
eldbus_pending_free_cb_add(r.native_handle(), &_detail::_free_cb<F>, f);
return r;
}
} }
#endif

@ -0,0 +1,41 @@
#ifndef ELDBUS_CXX_ELDBUS_INTEGER_SEQUENCE_HH
#define ELDBUS_CXX_ELDBUS_INTEGER_SEQUENCE_HH
namespace efl { namespace eldbus { namespace _detail {
template <typename T, T... Ints>
struct integer_sequence
{
typedef T value_type;
static constexpr std::size_t size() { return sizeof...(Ints); }
typedef integer_sequence<T, Ints...> type;
};
template<class S1, class S2> struct concat;
template<typename T, T... I1, T... I2>
struct concat<integer_sequence<T, I1...>, integer_sequence<T, I2...> >
: integer_sequence<T, I1..., (sizeof...(I1)+I2)...> {};
template<class S1, class S2>
using Concat = typename concat<S1, S2>::type;
template<typename T, T N> struct gen_seq;
template<typename T, T N> using make_integer_sequence = typename gen_seq<T, N>::type;
template<typename T, T N>
struct gen_seq : Concat<make_integer_sequence<T, N/2>
, make_integer_sequence<T, N - N/2>>{};
template<> struct gen_seq<std::size_t, 0> : integer_sequence<std::size_t>{};
template<> struct gen_seq<std::size_t, 1> : integer_sequence<std::size_t, 0>{};
template <std::size_t... I>
using index_sequence = integer_sequence<std::size_t, I...>;
template <std::size_t I>
using make_index_sequence = make_integer_sequence<std::size_t, I>;
} } }
#endif

@ -0,0 +1,283 @@
#ifndef ELDBUS_CXX_ELDBUS_MESSAGE_HH
#define ELDBUS_CXX_ELDBUS_MESSAGE_HH
#include <Eldbus.h>
#include <eldbus_signature_traits.hh>
namespace efl { namespace eldbus {
struct message_value
{
message_value() : _iterator(0) {}
message_value( ::Eldbus_Message_Iter* iterator) : _iterator(iterator) {}
template <typename T>
T get() const
{
assert(!!_iterator);
std::cout << "trying to read " << _detail::signature_traits<T>::sig
<< " has " << eldbus_message_iter_signature_get(_iterator) << std::endl;
T object;
char* c = eldbus_message_iter_signature_get(_iterator);
if(c[0] != _detail::signature_traits<T>::sig)
throw std::runtime_error("");
eldbus_message_iter_arguments_get(_iterator, c, &object);
return object;
}
friend inline bool operator==(message_value const& lhs, message_value const& rhs)
{
return
lhs._iterator == rhs._iterator
|| (!lhs._iterator && rhs._iterator && std::strlen(eldbus_message_iter_signature_get(rhs._iterator)) == 0)
|| (!rhs._iterator && lhs._iterator && std::strlen(eldbus_message_iter_signature_get(lhs._iterator)) == 0)
;
}
private:
friend struct message_iterator;
::Eldbus_Message_Iter* _iterator;
};
inline bool operator!=(message_value const& lhs, message_value const& rhs)
{
return !(lhs == rhs);
}
struct message_iterator
{
typedef message_value value_type;
typedef value_type& reference;
typedef value_type const& const_reference;
typedef value_type* pointer;
typedef value_type const* const_pointer;
typedef std::ptrdiff_t difference_type;
typedef std::size_t size_type;
typedef std::input_iterator_tag iterator_category;
message_iterator()
{
}
message_iterator(Eldbus_Message_Iter* iterator)
: value(iterator)
{}
reference operator*() const
{
return const_cast<reference>(value);
}
pointer operator->() const
{
return const_cast<pointer>(&value);
}
message_iterator& operator++()
{
if(!eldbus_message_iter_next(value._iterator))
{
value._iterator = 0;
}
return *this;
}
message_iterator operator++() const
{
message_iterator tmp(*this);
++*this;
return tmp;
}
friend inline bool operator==(message_iterator const& lhs, message_iterator const& rhs)
{
return lhs.value == rhs.value;
}
private:
message_value value;
};
inline bool operator!=(message_iterator const& lhs, message_iterator const& rhs)
{
return !(lhs == rhs);
}
struct reply_t {};
struct error_t {};
struct method_call_t {};
reply_t const reply = {};
error_t const error = {};
method_call_t const method_call = {};
struct const_message
{
explicit const_message(Eldbus_Message const* message) : _message(message)
{
}
const_message(const_message const& other, reply_t)
: _message( ::eldbus_message_method_return_new(other.native_handle()))
{
}
const_message(const_message const& other, const char* error_name, const char* error_msg, error_t)
: _message( ::eldbus_message_error_new(other.native_handle(), error_name, error_msg))
{
}
const_message(const char* destination, const char* path, const char* iface
, const char* method, method_call_t)
: _message( ::eldbus_message_method_call_new(destination, path, iface, method))
{
}
const_message(const_message const& other)
: _message( ::eldbus_message_ref(const_cast<Eldbus_Message*>(other.native_handle())))
{
}
~const_message()
{
eldbus_message_unref(const_cast<Eldbus_Message*>(native_handle()));
}
const char* path_get() const
{
return ::eldbus_message_path_get(_message);
}
const char* interface_get() const
{
return ::eldbus_message_interface_get(_message);
}
const char* member_get() const
{
return ::eldbus_message_member_get(_message);
}
const char* destination_get() const
{
return ::eldbus_message_destination_get(_message);
}
const char* sender_get() const
{
return ::eldbus_message_sender_get(_message);
}
const char* signature_get() const
{
return ::eldbus_message_signature_get(_message);
}
bool operator!() const
{
bool b (*this);
return !b;
}
explicit operator bool() const
{
const char* name, * text;
return !eldbus_message_error_get(_message, &name, &text);
}
std::pair<const char*, const char*> error_get() const
{
const char* name, * text;
eldbus_message_error_get(_message, &name, &text);
return {name, text};
}
typedef message_iterator const_iterator;
typedef const_iterator iterator;
typedef Eldbus_Message const* native_handle_type;
typedef Eldbus_Message const* const_native_handle_type;
const_native_handle_type native_handle() const { return _message; }
const_native_handle_type const_native_handle() const { return _message; }
const_iterator begin() const
{
return const_iterator( ::eldbus_message_iter_get(_message));
}
const_iterator end() const
{
return const_iterator();
}
private:
Eldbus_Message const* _message;
};
struct message : const_message
{
typedef const_message base_type;
explicit message(Eldbus_Message* message) : const_message(message)
{
}
message(const_message const& other, reply_t r)
: const_message(other, r)
{
}
message(const_message const& other, const char* error_name, const char* error_msg, error_t e)
: const_message(other, error_name, error_msg, e)
{
}
message(const char* destination, const char* path, const char* iface
, const char* method, method_call_t m)
: const_message(destination, path, iface, method, m)
{
}
message(message const& other)
: const_message(static_cast<base_type const&>(other))
{
}
typedef Eldbus_Message* native_handle_type;
native_handle_type native_handle() { return const_cast<native_handle_type>(const_message::native_handle()); }
};
struct const_pending
{
const_pending() : _pending(0) {}
const_pending(Eldbus_Pending const* pending) : _pending(pending) {}
void* data_get(const char* key) const
{
return ::eldbus_pending_data_get(_pending, key);
}
const char* destination_get() const
{
return ::eldbus_pending_destination_get(_pending);
}
const char* path_get() const
{
return ::eldbus_pending_path_get(_pending);
}
const char* interface_get() const
{
return ::eldbus_pending_interface_get(_pending);
}
const char* method_get() const
{
return ::eldbus_pending_method_get(_pending);
}
typedef Eldbus_Pending const* native_handle_type;
typedef Eldbus_Pending const* const_native_handle_type;
native_handle_type native_handle() const { return _pending; }
const_native_handle_type const_native_handle() const { return _pending; }
private:
const_native_handle_type _pending;
};
struct pending : const_pending
{
pending() : const_pending(0) {}
pending(Eldbus_Pending* pending) : const_pending(pending) {}
void data_set(const char* key, const char* data)
{
::eldbus_pending_data_set(native_handle(), key, data);
}
void* data_del(const char* key)
{
return ::eldbus_pending_data_del(native_handle(), key);
}
void cancel()
{
::eldbus_pending_cancel(native_handle());
}
typedef Eldbus_Pending* native_handle_type;
native_handle_type native_handle()
{
return const_cast<native_handle_type>(const_pending::native_handle());
}
};
} }
#endif

@ -0,0 +1,56 @@
#ifndef ELDBUS_CXX_ELDBUS_MESSAGE_ARGUMENTS_HH
#define ELDBUS_CXX_ELDBUS_MESSAGE_ARGUMENTS_HH
#include <Eldbus.h>
#include <tuple>
#include <iostream>
namespace efl { namespace eldbus { namespace _detail {
template <std::size_t I, typename Seq, typename Tuple>
bool _init_raw_tuple(Eldbus_Message_Iter*, Tuple const&, std::true_type)
{
return true;
}
template <std::size_t I, typename Seq, typename Tuple>
bool _init_raw_tuple(Eldbus_Message_Iter* iterator, Tuple const& tuple, std::false_type)
{
typedef signature_traits<typename std::tuple_element<I, Seq>::type> traits;
typedef typename traits::value_type element_type;
char* c = eldbus_message_iter_signature_get(iterator);
if(c[0] != signature_traits<element_type>::sig)
{
return false;
}
eldbus_message_iter_get_and_next(iterator, *c, &std::get<I>(tuple));
return _init_raw_tuple<I+1, Seq>
(iterator, tuple, std::integral_constant<bool, (I+1 == std::tuple_size<Tuple>::value)>());
}
template <std::size_t I, typename Tuple>
bool _append_tuple(Eldbus_Message*, Tuple const&, std::true_type)
{
return true;
}
template <std::size_t I, typename Tuple>
bool _append_tuple(Eldbus_Message* message, Tuple const& tuple, std::false_type)
{
typedef signature_traits<typename std::tuple_element<I, Tuple>::type> traits;
char signature[2] = {traits::sig, 0};
if(!eldbus_message_arguments_append(message, signature, traits::to_raw(std::get<I>(tuple))))
return false;
return _append_tuple<I+1>
(message, tuple, std::integral_constant<bool, (I+1 == std::tuple_size<Tuple>::value)>());
}
} } }
#endif

@ -0,0 +1,117 @@
#ifndef ELDBUS_PROXY_CALL_HH
#define ELDBUS_PROXY_CALL_HH
#include <Eina.hh>
#include <eldbus_error.hh>
#include <eldbus_signature_traits.hh>
#include <eldbus_message_arguments.hh>
#include <eldbus_message.hh>
#include <eldbus_raw_tuple.hh>
#include <eina_integer_sequence.hh>
#include <eina_tuple_unwrap.hh>
#include <tuple>
#include <iostream>
namespace efl { namespace eldbus { namespace _detail {
template <typename T> struct tag {};
template <typename Seq, typename Callback, std::size_t... I>
void _on_call_impl(void* data, Eldbus_Message const* message, Eldbus_Pending* pending)
{
std::unique_ptr<Callback> callback(static_cast<Callback*>(data));
const char* errname, *errmsg;
if (eldbus_message_error_get(message, &errname, &errmsg))
{
Seq tuple;
::eldbus_message_ref(const_cast<Eldbus_Message*>(message));
eldbus::const_message msg(message);
eina::error_code ec (eldbus::call_error_code(), eina::eina_error_category());
eina::call_tuple_unwrap_prefix
(*callback, tuple, eina::make_index_sequence<std::tuple_size<Seq>::value>()
, ec, msg, pending);
}
typename raw_tuple<Seq>::type tuple;
if(std::tuple_size<Seq>::value)
{
if(!_detail::_init_raw_tuple<0u, Seq>
(eldbus_message_iter_get(message)
, tuple, std::integral_constant<bool, (std::tuple_size<Seq>::value == 0)>()))
{
Seq tuple;
::eldbus_message_ref(const_cast<Eldbus_Message*>(message));
eldbus::const_message msg(message);
eina::error_code ec(eldbus::signature_mismatch_error_code(), eina::eina_error_category());
eina::call_tuple_unwrap_prefix
(*callback, tuple, eina::make_index_sequence<std::tuple_size<Seq>::value>()
, ec, msg, pending);
}
}
eina::error_code ec;
::eldbus_message_ref(const_cast<Eldbus_Message*>(message));
eldbus::const_message msg(message);
eina::call_tuple_unwrap_prefix
(*callback, tuple, eina::make_index_sequence<std::tuple_size<Seq>::value>()
, ec, msg, pending);
}
template <typename Seq, typename Callback>
void _on_call(void* data, Eldbus_Message const* message, Eldbus_Pending* pending)
{
_detail::_on_call_impl<Seq, Callback>(data, message, pending);
}
template <typename R, typename Callback, typename... Args>
void proxy_call_impl2(Eldbus_Proxy* proxy, const char* method, double timeout
, Callback&& callback, Args const&... args)
{
typedef std::tuple<Args...> tuple_args;
char signature[signature_size<tuple_args>::value +1];
_detail::init_signature_array<Args...>
(signature, eina::make_index_sequence<signature_size<tuple_args>::value +1>());
Callback* c = new Callback(std::move(callback));
eldbus_proxy_call(proxy, method, &_on_call<R, Callback>, c, timeout, signature
, _detail::to_raw(args)...);
}
template <typename R, typename Callback, typename... Args>
void proxy_call_impl(tag<R>, Eldbus_Proxy* proxy, const char* method, double timeout
, Callback&& callback, Args const&... args)
{
typedef std::tuple<R> reply_tuple;
_detail::proxy_call_impl2<reply_tuple>(proxy, method, timeout, std::move(callback), args...);
}
template <typename... R, typename Callback, typename... Args>
void proxy_call_impl(tag<std::tuple<R...> >, Eldbus_Proxy* proxy, const char* method, double timeout
, Callback&& callback, Args const&... args)
{
typedef std::tuple<R...> reply_tuple;
_detail::proxy_call_impl2<reply_tuple>(proxy, method, timeout, std::move(callback), args...);
}
template <typename Callback, typename... Args>
void proxy_call_impl(tag<void>, Eldbus_Proxy* proxy, const char* method, double timeout
, Callback&& callback, Args const&... args)
{
typedef std::tuple<> reply_tuple;
_detail::proxy_call_impl2<reply_tuple>(proxy, method, timeout, std::move(callback), args...);
}
template <typename R, typename Callback, typename... Args>
void proxy_call(Eldbus_Proxy* proxy, const char* method, double timeout
, Callback&& callback, Args const&... args)
{
return proxy_call_impl(tag<R>(), proxy, method, timeout, std::move(callback), args...);
}
} } }
#endif

@ -0,0 +1,30 @@
#ifndef EFL_ELDBUS_CXX_ELDBUS_RAW_TUPLE_HH
#define EFL_ELDBUS_CXX_ELDBUS_RAW_TUPLE_HH
#include <eldbus_signature_traits.hh>
#include <eina_fold.hh>
#include <eina_tuple.hh>
namespace efl { namespace eldbus { namespace _detail {
template <typename T>
struct raw_tuple;
template <typename... T>
struct raw_tuple<std::tuple<T...> >
{
struct push_back
{
template <typename L, typename R>
struct apply
: eina::_mpl::push_back<L, typename signature_traits<R>::raw_type> {};
};
typedef typename eina::_mpl::fold< std::tuple<T...>, push_back
, std::tuple<> >::type type;
};
} } }
#endif

@ -0,0 +1,379 @@
#ifndef ELDBUS_CXX_ELDBUS_SERVICE_HH
#define ELDBUS_CXX_ELDBUS_SERVICE_HH
#include <array>
namespace efl { namespace eldbus {
struct service_interface
{
service_interface(Eldbus_Service_Interface const* iface)
: _iface(iface)
{}
typedef Eldbus_Service_Interface* native_handle_type;
typedef Eldbus_Service_Interface const* const_native_handle_type;
const_native_handle_type native_handle() { return _iface; }
const_native_handle_type native_handle() const { return _iface; }
private:
const_native_handle_type _iface;
};
namespace service {
template <typename F, typename Ins, typename Outs>
struct method_specification
{
const char* name;
F f;
typedef F function_type;
typedef Ins ins_type;
typedef Outs outs_type;
ins_type ins;
outs_type outs;
};
namespace _detail {
template <typename T>
struct const_char_type
{
typedef const char* type;
};
}
template <typename... Args>
struct ins
{
ins(typename _detail::const_char_type<Args>::type... names) : _names({names...}) {}
static constexpr std::size_t size() { return sizeof...(Args); }
typedef std::tuple<Args...> types;
std::array<const char*, sizeof...(Args)> _names;
};
template <typename... Args>
struct outs
{
outs(typename _detail::const_char_type<Args>::type... names) : _names({names...}) {}
static constexpr std::size_t size() { return sizeof...(Args); }
typedef std::tuple<Args...> types;
std::array<const char*, sizeof...(Args)> _names;
};
void foo(int);
template <typename F, typename Ins, typename Outs>
method_specification<F, Ins, Outs>
method(const char* name, F f, Ins ins, Outs outs)
{
return method_specification<F, Ins, Outs>
{name, f, ins, outs}
;
}
template <typename F, typename... Outs>
method_specification<F, service::ins<>, service::outs<Outs...> >
method(const char* name, F f, service::outs<Outs...> outs)
{
return method_specification<F, service::ins<>, service::outs<Outs...> >
{name, f, service::ins<>(), outs}
;
}
template <typename F, typename... Ins>
method_specification<F, service::ins<Ins...>, service::outs<> >
method(const char* name, F f, service::ins<Ins...> ins)
{
return method_specification<F, service::ins<Ins...>, service::outs<> >
{name, f, ins, service::outs<>()}
;
}
}
template <std::size_t I, std::size_t N, template <typename...> class params
, typename ... Args>
int _fill_method_impl(std::array<Eldbus_Arg_Info, N>& array
, params<Args...> const&
, std::true_type)
{
array[I] = Eldbus_Arg_Info {0, 0};
return 0;
}
template <std::size_t I, std::size_t N, template <typename...> class params
, typename ... Args>
int _fill_method_impl(std::array<Eldbus_Arg_Info, N>& array
, params<Args...> const& directional_methods
, std::false_type)
{
typedef std::tuple<Args...> params_type;
static const char sig[2]
= {_detail::signature_traits
<
typename std::tuple_element<I, params_type>::type
>::sig
, '\0'
};
array[I] = {sig
, directional_methods._names[I]
};
return 0;
}
template <std::size_t I, std::size_t N, template <typename...> class params
, typename ... Args>
int _fill_method(std::array<Eldbus_Arg_Info, N>& array
, params<Args...> const& directional_methods)
{
_fill_method_impl<I>(array, directional_methods
, std::integral_constant<bool, N-1 == I>());
return 0;
}
template <typename... T>
void _foo(T...) {}
template <std::size_t N, template <typename...> class params, typename ... Args
, std::size_t... Seq>
void _fill_methods_impl(std::array<Eldbus_Arg_Info, N>& array
, params<Args...> const& directional_methods
, eina::index_sequence<Seq...>
)
{
eldbus::_foo(eldbus::_fill_method<Seq>(array, directional_methods) ...);
}
template <std::size_t N, template <typename...> class params, typename ... Args>
void _fill_methods(std::array<Eldbus_Arg_Info, N>& array
, params<Args...> const& directional_methods)
{
eldbus::_fill_methods_impl(array, directional_methods
, eina::make_index_sequence<N>());
}
template <typename Tuple, std::size_t I>
void _create_methods_specification(Tuple const&
, std::array<Eldbus_Method, std::tuple_size<Tuple>::value+1>& methods
, std::integral_constant<std::size_t, I>
, std::true_type)
{
methods[I] = Eldbus_Method {0, 0, 0, 0, 0, 0};
};
template <std::size_t, typename T>
T get_in(Eldbus_Message const* msg)
{
typename _detail::signature_traits<T>::raw_type object;
const char sig[2] = {_detail::signature_traits<T>::sig, 0};
if (!eldbus_message_arguments_get(msg, sig, &object))
{
printf("eldbus_message_arguments_get() error\n");
throw std::runtime_error("");
}
else
{
return object;
}
}
template <typename Callable, typename... Ins, typename... Outs
, std::size_t... IndexIns, std::size_t... IndexOuts
, std::size_t... IndexOuts2>
Eldbus_Message* _method_callback_call
(Callable const& callable, service::ins<Ins...> const&, service::outs<Outs...> const&
, eina::index_sequence<IndexIns...>, eina::index_sequence<IndexOuts...>
, eina::index_sequence<IndexOuts2...>
, Eldbus_Service_Interface const* iface, Eldbus_Message const* message
, typename std::enable_if
<!std::is_void
<decltype(callable
(*static_cast<eldbus::message*>(nullptr)
, *static_cast<eldbus::service_interface*>(nullptr)
, std::get<IndexIns>(std::tuple<Ins...>())...
, &std::get<IndexOuts2>
(*static_cast<std::tuple<Outs...>*>(nullptr))...
)
)>::value, int>::type)
{
typedef std::tuple<Ins...> tuple_ins;
typename _detail::raw_tuple<tuple_ins>::type tuple_ins_raw;
_detail::_init_raw_tuple<0u, tuple_ins>
(eldbus_message_iter_get(message), tuple_ins_raw
, std::integral_constant<bool, (std::tuple_size<tuple_ins>::value == 0u)>());
std::tuple<Outs...> tuple_outs;
eldbus::const_message msg( ::eldbus_message_ref(const_cast<Eldbus_Message*>(message)));
eldbus::service_interface siface(iface);
// If you have an error here, then you probably got your ins<...>
// and/or outs<...> different from the arguments of your callable
//typedef _detail::signature_traits<result_type> traits;
std::get<0u>(tuple_outs) =
callable(msg, siface, std::get<IndexIns>(tuple_ins_raw)..., &std::get<IndexOuts2>(tuple_outs)...);
Eldbus_Message *reply = eldbus_message_method_return_new(message);
_detail::_append_tuple<0u>(reply, tuple_outs, std::false_type());
return reply;
}
template <typename Callable, typename... Ins, typename... Outs
, std::size_t... IndexIns, std::size_t... IndexOuts
, std::size_t... IndexOuts2>
Eldbus_Message* _method_callback_call
(Callable const& callable, service::ins<Ins...> const&, service::outs<Outs...> const&
, eina::index_sequence<IndexIns...>, eina::index_sequence<IndexOuts...>
, eina::index_sequence<IndexOuts2...>
, Eldbus_Service_Interface const* iface, Eldbus_Message const* message
, long)
{
typedef std::tuple<Ins...> tuple_ins;
typename _detail::raw_tuple<tuple_ins>::type tuple_ins_raw;
_detail::_init_raw_tuple<0u, tuple_ins>
(eldbus_message_iter_get(message), tuple_ins_raw
, std::integral_constant<bool, (std::tuple_size<tuple_ins>::value == 0u)>());
typedef std::tuple<Outs...> tuple_outs_type;
tuple_outs_type tuple_outs;
eldbus::const_message msg( ::eldbus_message_ref(const_cast<Eldbus_Message*>(message)));
eldbus::service_interface siface(iface);
// If you have an error here, then you probably got your ins<...>
// and/or outs<...> different from the arguments of your callable
callable(msg, siface, std::get<IndexIns>(tuple_ins_raw)..., &std::get<IndexOuts>(tuple_outs)...);
Eldbus_Message *reply = eldbus_message_method_return_new(message);
_detail::_append_tuple<0u>
(reply, tuple_outs
, std::integral_constant<bool, std::tuple_size<tuple_outs_type>::value == 0u>());
return reply;
}
template <typename Callable, typename Ins, typename Outs>
Eldbus_Message* _method_callback(void* data, Eldbus_Service_Interface const* iface, Eldbus_Message const* msg)
{
std::tuple<Callable, Ins, Outs>*
tuple = static_cast<std::tuple<Callable, Ins, Outs>*>(data);
return _method_callback_call(std::get<0u>(*tuple), std::get<1u>(*tuple), std::get<2u>(*tuple)
, eina::make_index_sequence
<std::tuple_size<typename Ins::types>::value>()