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
This commit is contained in:
Felipe Magno de Almeida 2014-07-03 16:28:22 +09:00 committed by Carsten Haitzler (Rasterman)
parent ddac21534f
commit 30df128be5
25 changed files with 2121 additions and 34 deletions

View File

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

View File

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

View File

@ -11,6 +11,7 @@ dist_installed_einacxxheaders_DATA = \
bindings/eina_cxx/eina_accessor.hh \ bindings/eina_cxx/eina_accessor.hh \
bindings/eina_cxx/eina_clone_allocators.hh \ bindings/eina_cxx/eina_clone_allocators.hh \
bindings/eina_cxx/eina_error.hh \ bindings/eina_cxx/eina_error.hh \
bindings/eina_cxx/eina_fold.hh \
bindings/eina_cxx/eina_inarray.hh \ bindings/eina_cxx/eina_inarray.hh \
bindings/eina_cxx/eina_inlist.hh \ bindings/eina_cxx/eina_inlist.hh \
bindings/eina_cxx/eina_integer_sequence.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_ref.hh \
bindings/eina_cxx/eina_stringshare.hh \ bindings/eina_cxx/eina_stringshare.hh \
bindings/eina_cxx/eina_thread.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_type_traits.hh \
bindings/eina_cxx/eina_value.hh bindings/eina_cxx/eina_value.hh

View File

@ -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

View File

@ -4,9 +4,10 @@
#include <Eet.h> #include <Eet.h>
#include <eet_type.hh> #include <eet_type.hh>
#include <eet_fold.hh>
#include <eet_register.hh> #include <eet_register.hh>
#include <eina_fold.hh>
#include <type_traits> #include <type_traits>
#include <cassert> #include <cassert>
#include <stdexcept> #include <stdexcept>
@ -36,10 +37,10 @@ struct descriptor_type
struct push_back struct push_back
{ {
template <typename A, typename B> 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; , descriptor<T> >::type type;
}; };

View File

@ -1,9 +1,9 @@
#ifndef EFL_EET_FOLD_HH_ #ifndef EFL_EINA_FOLD_HH_
#define EFL_EET_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 { namespace _mpl {
@ -11,7 +11,7 @@ template <typename T, typename F, typename A0, bool B = std::is_same<T, std::tup
struct fold_impl struct fold_impl
{ {
typedef typename F::template apply<A0, typename std::tuple_element<0, T>::type>::type result; 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 , F, result
>::type >::type
type; type;

View File

@ -70,6 +70,36 @@ using index_sequence = integer_sequence<std::size_t, I...>;
template <std::size_t I> template <std::size_t I>
using make_index_sequence = make_integer_sequence<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;
/** /**
* @} * @}
*/ */

View File

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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>()
, eina::make_index_sequence
<std::tuple_size<typename Outs::types>::value>()
, eina::pop_integer_sequence
<eina::make_index_sequence<0u>
, eina::make_index_sequence
<std::tuple_size<typename Outs::types>::value>
>()
, iface, msg, 0);
}
template <typename Method>
void _create_methods_specification_impl(Method const& method, Eldbus_Method& eldbus_method, std::false_type)
{
std::array<Eldbus_Arg_Info, Method::ins_type::size()+1>*
in_params = new std::array<Eldbus_Arg_Info, Method::ins_type::size()+1>;
eldbus::_fill_methods(*in_params, method.ins);
std::array<Eldbus_Arg_Info, Method::outs_type::size()+1>*
out_params = new std::array<Eldbus_Arg_Info, Method::outs_type::size()+1>;
eldbus::_fill_methods(*out_params, method.outs);
eldbus_method = {method.name, &(*in_params)[0], &(*out_params)[0]
, reinterpret_cast<Eldbus_Method_Cb>
(static_cast<Eldbus_Method_Data_Cb>
(&_method_callback<typename Method::function_type
, typename Method::ins_type, typename Method::outs_type>))
, ELDBUS_METHOD_FLAG_HAS_DATA
, new std::tuple<typename Method::function_type
, typename Method::ins_type, typename Method::outs_type
>(std::move(method.f), method.ins, method.outs)};
}
template <typename Method>
void _create_methods_specification_impl(Method const& method, Eldbus_Method& eldbus_method, std::true_type)
{
std::array<Eldbus_Arg_Info, Method::ins_type::size()+1>*
in_params = new std::array<Eldbus_Arg_Info, Method::ins_type::size()+1>;
eldbus::_fill_methods(*in_params, method.ins);
std::array<Eldbus_Arg_Info, Method::outs_type::size()+1>*
out_params = new std::array<Eldbus_Arg_Info, Method::outs_type::size()+1>;
eldbus::_fill_methods(*out_params, method.outs);
eldbus_method = {method.name, &(*in_params)[0], &(*out_params)[0], method.f, 0, 0};
}
template <typename Tuple, std::size_t I>
void _create_methods_specification(Tuple const& tuple
, std::array<Eldbus_Method, std::tuple_size<Tuple>::value+1>& methods
, std::integral_constant<std::size_t, I>
, std::false_type)
{
typedef Eldbus_Message*(*function_type)(Eldbus_Service_Interface const*, Eldbus_Message const*);
typedef typename std::tuple_element<I, Tuple>::type method_type;
_create_methods_specification_impl(std::get<I>(tuple), methods[I]
, std::is_convertible<typename method_type::function_type
, function_type>());
return _create_methods_specification(tuple, methods
, std::integral_constant<std::size_t, I+1>()
, std::integral_constant<bool, I+1 == std::tuple_size<Tuple>::value>());
};
template <typename Tuple>
std::array<Eldbus_Method, std::tuple_size<Tuple>::value+1> _create_methods_specification
(Tuple const& tuple
)
{
typedef std::tuple_size<Tuple> tuple_size;
std::array<Eldbus_Method, tuple_size::value+1> array;
_create_methods_specification(tuple, array
, std::integral_constant<std::size_t, 0u>()
, std::integral_constant<bool, 0 == std::tuple_size<Tuple>::value>());
return array;
};
template <typename... Args>
service_interface service_interface_register(connection& c, const char* path
, const char* interface
, Args... args
)
{
std::array<Eldbus_Method, sizeof...(Args) + 1>* methods
= new std::array<Eldbus_Method, sizeof...(Args) + 1>
(
_create_methods_specification(std::make_tuple(args...))
);
Eldbus_Service_Interface_Desc description =
{
interface, &(*methods)[0], 0, 0, 0, 0
};
Eldbus_Service_Interface* iface
= ::eldbus_service_interface_register(c.native_handle(), path, &description);
return service_interface(iface);
}
} }
#endif

View File

@ -0,0 +1,194 @@
#ifndef ELDBUS_SIGNATURE_TRAITS_HH_
#define ELDBUS_SIGNATURE_TRAITS_HH_
#include <eina_fold.hh>
#include <eina_integer_sequence.hh>
namespace efl { namespace eldbus { namespace _detail {
template <typename T>
struct signature_traits;
template <>
struct signature_traits<bool>
{
typedef Eina_Bool raw_type;
typedef bool value_type;
typedef std::integral_constant<int, 1u> sig_size;
static int const sig = 'b';
static raw_type to_raw(value_type v) { return v ? EINA_TRUE : EINA_FALSE; }
};
template <>
struct signature_traits<char>
{
typedef char raw_type;
typedef raw_type value_type;
typedef std::integral_constant<int, 1u> sig_size;
static int const sig = 'y';
static raw_type to_raw(value_type v) { return v; }
};
template <>
struct signature_traits<int16_t>
{
typedef int16_t raw_type;
typedef raw_type value_type;
typedef std::integral_constant<int, 1u> sig_size;
static char const sig = 'n';
static raw_type to_raw(value_type v) { return v; }
};
template <>
struct signature_traits<uint16_t>
{
typedef uint16_t raw_type;
typedef raw_type value_type;
typedef std::integral_constant<int, 1u> sig_size;
static char const sig = 'q';
static raw_type to_raw(value_type i) { return i; }
};
template <>
struct signature_traits<int32_t>
{
typedef int32_t raw_type;
typedef raw_type value_type;
typedef std::integral_constant<int, 1u> sig_size;
static char const sig = 'i';
static raw_type to_raw(value_type i) { return i; }
};
template <>
struct signature_traits<uint32_t>
{
typedef uint32_t raw_type;
typedef raw_type value_type;
typedef std::integral_constant<int, 1u> sig_size;
static char const sig = 'u';
static raw_type to_raw(value_type i) { return i; }
};
template <>
struct signature_traits<int64_t>
{
typedef int64_t raw_type;
typedef raw_type value_type;
typedef std::integral_constant<int, 1u> sig_size;
static char const sig = 'x';
static raw_type to_raw(value_type i) { return i; }
};
template <>
struct signature_traits<uint64_t>
{
typedef uint64_t raw_type;
typedef raw_type value_type;
typedef std::integral_constant<int, 1u> sig_size;
static char const sig = 't';
static raw_type to_raw(value_type i) { return i; }
};
template <>
struct signature_traits<double>
{
typedef double raw_type;
typedef raw_type value_type;
typedef std::integral_constant<int, 1u> sig_size;
static char const sig = 'd';
static raw_type to_raw(value_type i) { return i; }
};
template <>
struct signature_traits<std::string>
{
typedef const char* raw_type;
typedef std::string value_type;
typedef std::integral_constant<int, 1u> sig_size;
static char const sig = 's';
static raw_type to_raw(std::string const& s) { return s.c_str(); }
};
template <typename T>
struct signature_traits<T const> : signature_traits<T>
{
};
template <typename T>
typename signature_traits<T>::raw_type to_raw(T const& object)
{
return signature_traits<T>::to_raw(object);
}
constexpr std::size_t add(std::size_t N)
{
return N;
}
constexpr std::size_t add(std::size_t L, std::size_t R)
{
return L + R;
}
template <typename... T>
constexpr std::size_t add(std::size_t L, std::size_t R, T ... O)
{
return L + R + add(O...);
}
template <typename T, typename U>
struct signature_size_impl;
template <typename T, std::size_t... S>
struct signature_size_impl<T, eina::index_sequence<S...> >
: std::integral_constant
<std::size_t
, _detail::add
(signature_traits<typename std::tuple_element<S, T>::type>::sig_size::value...)>
{
};
template <typename T>
struct signature_size : signature_size_impl<T, eina::make_index_sequence<std::tuple_size<T>::value> >
{
};
template <typename ... T>
void call_all(T...) {}
template <std::size_t I, typename Tuple, std::size_t N
, typename = typename std::enable_if<I != N-1>::type>
int init_signature(char (&signature)[N])
{
signature[I] = signature_traits<typename std::tuple_element<I, Tuple>::type>::sig;
return 0;
}
template <std::size_t I, typename Tuple>
int init_signature(char (&signature)[I+1])
{
signature[I] = 0;
return 0;
}
template <typename... Args, std::size_t... S, std::size_t N>
void init_signature_array(char (&signature)[N], eina::index_sequence<S...>)
{
call_all(_detail::init_signature<S, std::tuple<Args...> >(signature)...);
}
} } }
#endif

View File

@ -395,7 +395,7 @@ cb_introspect(const Eldbus_Service_Interface *_iface, const Eldbus_Message *mess
} }
static const Eldbus_Method introspect = { static const Eldbus_Method introspect = {
"Introspect", NULL, ELDBUS_ARGS({ "s", "xml" }), cb_introspect, 0 "Introspect", NULL, ELDBUS_ARGS({ "s", "xml" }), cb_introspect, 0, 0
}; };
static void static void
@ -435,15 +435,15 @@ _default_interfaces_free(void)
static const Eldbus_Method _property_methods[] = { static const Eldbus_Method _property_methods[] = {
{ {
"Get", ELDBUS_ARGS({"s", "interface"}, {"s", "property"}), "Get", ELDBUS_ARGS({"s", "interface"}, {"s", "property"}),
ELDBUS_ARGS({"v", "value"}), _cb_property_get, 0 ELDBUS_ARGS({"v", "value"}), _cb_property_get, 0, NULL
}, },
{ {
"Set", ELDBUS_ARGS({"s", "interface"}, {"s", "property"}, {"v", "value"}), "Set", ELDBUS_ARGS({"s", "interface"}, {"s", "property"}, {"v", "value"}),
NULL, _cb_property_set, 0 NULL, _cb_property_set, 0, NULL
}, },
{ {
"GetAll", ELDBUS_ARGS({"s", "interface"}), ELDBUS_ARGS({"a{sv}", "props"}), "GetAll", ELDBUS_ARGS({"s", "interface"}), ELDBUS_ARGS({"a{sv}", "props"}),
_cb_property_getall, 0 _cb_property_getall, 0, NULL
} }
}; };
@ -570,7 +570,7 @@ _cb_managed_objects(const Eldbus_Service_Interface *iface, const Eldbus_Message
static Eldbus_Method get_managed_objects = { static Eldbus_Method get_managed_objects = {
"GetManagedObjects", NULL, ELDBUS_ARGS({"a{oa{sa{sv}}}", "objects"}), "GetManagedObjects", NULL, ELDBUS_ARGS({"a{oa{sa{sv}}}", "objects"}),
_cb_managed_objects, 0 _cb_managed_objects, 0, NULL
}; };
static const Eldbus_Signal _object_manager_signals[] = { static const Eldbus_Signal _object_manager_signals[] = {
@ -1282,6 +1282,20 @@ _object_unregister(DBusConnection *conn EINA_UNUSED, void *user_data)
_object_free(obj); _object_free(obj);
} }
static Eldbus_Message*
_eldbus_method_call(Eldbus_Method const* method, Eldbus_Service_Interface* iface, Eldbus_Message* msg)
{
if(method->flags & ELDBUS_METHOD_FLAG_HAS_DATA)
{
Eldbus_Method_Data_Cb cb = (Eldbus_Method_Data_Cb)method->cb;
return cb(method->data, iface, msg);
}
else
{
return method->cb(iface, msg);
}
}
static DBusHandlerResult static DBusHandlerResult
_object_handler(DBusConnection *dbus_conn EINA_UNUSED, DBusMessage *msg, void *user_data) _object_handler(DBusConnection *dbus_conn EINA_UNUSED, DBusMessage *msg, void *user_data)
{ {
@ -1331,19 +1345,19 @@ _object_handler(DBusConnection *dbus_conn EINA_UNUSED, DBusMessage *msg, void *u
if (!_have_signature(method->in, eldbus_msg)) if (!_have_signature(method->in, eldbus_msg))
reply = eldbus_message_error_new(eldbus_msg, DBUS_ERROR_INVALID_SIGNATURE, reply = eldbus_message_error_new(eldbus_msg, DBUS_ERROR_INVALID_SIGNATURE,
"See introspectable to know the expected signature"); "See introspectable to know the expected signature");
else else
{ {
if (iface->obj) if (iface->obj)
reply = method->cb(iface, eldbus_msg); reply = _eldbus_method_call(method, iface, eldbus_msg);
else else
{ {
/* if iface does have obj it is some of FreeDesktop interfaces: /* if iface does have obj it is some of FreeDesktop interfaces:
Introspectable, Properties or ObjectManager */ Introspectable, Properties or ObjectManager */
iface->obj = obj; iface->obj = obj;
reply = method->cb(iface, eldbus_msg); reply = _eldbus_method_call(method, iface, eldbus_msg);
iface->obj = NULL; iface->obj = NULL;
} }
} }
eldbus_message_unref(eldbus_msg); eldbus_message_unref(eldbus_msg);

View File

@ -9,6 +9,7 @@
*/ */
#define ELDBUS_METHOD_FLAG_DEPRECATED 1 #define ELDBUS_METHOD_FLAG_DEPRECATED 1
#define ELDBUS_METHOD_FLAG_NOREPLY (1 << 1) #define ELDBUS_METHOD_FLAG_NOREPLY (1 << 1)
#define ELDBUS_METHOD_FLAG_HAS_DATA (1 << 2) // @since 1.1
#define ELDBUS_SIGNAL_FLAG_DEPRECATED 1 #define ELDBUS_SIGNAL_FLAG_DEPRECATED 1
@ -32,6 +33,8 @@ typedef struct _Eldbus_Arg_Info
typedef struct _Eldbus_Service_Interface Eldbus_Service_Interface; typedef struct _Eldbus_Service_Interface Eldbus_Service_Interface;
typedef Eldbus_Message * (*Eldbus_Method_Cb)(const Eldbus_Service_Interface *iface, const Eldbus_Message *message); typedef Eldbus_Message * (*Eldbus_Method_Cb)(const Eldbus_Service_Interface *iface, const Eldbus_Message *message);
typedef Eldbus_Message * (*Eldbus_Method_Data_Cb)(void* data, const Eldbus_Service_Interface *iface, const Eldbus_Message *message); // @since 1.11
/** /**
* Callback function to append property value to message. * Callback function to append property value to message.
* *
@ -69,6 +72,7 @@ typedef struct _Eldbus_Method
const Eldbus_Arg_Info *out; const Eldbus_Arg_Info *out;
Eldbus_Method_Cb cb; Eldbus_Method_Cb cb;
unsigned int flags; unsigned int flags;
void* data; // @since 1.11
} Eldbus_Method; } Eldbus_Method;
typedef struct _Eldbus_Signal typedef struct _Eldbus_Signal

View File

@ -0,0 +1,106 @@
#include <Eina.h>
#include "Eldbus.hh"
#include <cassert>
#include <algorithm>
#include <check.h>
void eldbus_test_connection(TCase* tc);
void eldbus_test_client(TCase* tc);
typedef struct _Eldbus_Test_Case Eldbus_Test_Case;
struct _Eldbus_Test_Case
{
const char *test_case;
void (*build)(TCase *tc);
};
static const Eldbus_Test_Case etc[] = {
{ "connection", eldbus_test_connection },
{ "client", eldbus_test_client },
{ NULL, NULL }
};
static void
_list_tests(void)
{
const Eldbus_Test_Case *itr = etc;
fputs("Available Test Cases:\n", stderr);
for (; itr->test_case; itr++)
fprintf(stderr, "\t%s\n", itr->test_case);
}
static Eina_Bool
_use_test(int argc, const char **argv, const char *test_case)
{
if (argc < 1)
return 1;
for (; argc > 0; argc--, argv++)
if (strcmp(test_case, *argv) == 0)
return 1;
return 0;
}
Suite *
eldbus_build_suite(int argc, const char **argv)
{
TCase *tc;
Suite *s;
int i;
s = suite_create("Eldbus");
for (i = 0; etc[i].test_case; ++i)
{
if (!_use_test(argc, argv, etc[i].test_case))
continue;
tc = tcase_create(etc[i].test_case);
tcase_set_timeout(tc, 0);
etc[i].build(tc);
suite_add_tcase(s, tc);
}
return s;
}
int main(int argc, char* argv[])
{
Suite *s;
SRunner *sr;
int i, failed_count;
for (i = 1; i < argc; i++)
if ((strcmp(argv[i], "-h") == 0) ||
(strcmp(argv[i], "--help") == 0))
{
fprintf(stderr, "Usage:\n\t%s [test_case1 .. [test_caseN]]\n",
argv[0]);
_list_tests();
return 0;
}
else if ((strcmp(argv[i], "-l") == 0) ||
(strcmp(argv[i], "--list") == 0))
{
_list_tests();
return 0;
}
putenv(const_cast<char*>("EFL_RUN_IN_TREE=1"));
s = eldbus_build_suite(argc - 1, (const char **)argv + 1);
sr = srunner_create(s);
srunner_set_xml(sr, TESTS_BUILD_DIR "/check-results.xml");
srunner_run_all(sr, CK_ENV);
failed_count = srunner_ntests_failed(sr);
srunner_free(sr);
return (failed_count == 0) ? 0 : 255;
}

View File

@ -0,0 +1,458 @@
#include "Eldbus.hh"
#include "Ecore.hh"
#include <eldbus_freedesktop.hh>
#include <algorithm>
#include <iostream>
#include <check.h>
const char bus[] = "org.Enlightenment";
const char path[] = "/org/enlightenment";
const char interface[] = "org.enlightenment.Test";
static void
on_name_request(std::error_code const& ec, efl::eldbus::const_message
, efl::eldbus::pending, unsigned int reply)
{
if(!ec)
{
if(reply != ELDBUS_NAME_REQUEST_REPLY_PRIMARY_OWNER)
{
printf("error name already in use\n");
return;
}
}
}
START_TEST(eldbus_cxx_client)
{
namespace edb = efl::eldbus;
efl::ecore::ecore_init ecore_init;
edb::eldbus_init init;
edb::connection c(edb::session);
namespace es = edb::service;
bool expected_bool = true;
char expected_byte = 0xAA;
uint32_t expected_uint32 = 0xFFFFFFFF;
int32_t expected_int32 = -1;
int16_t expected_int16 = -1;
double expected_double = 3.1415926;
std::string expected_string = "expected string";
edb::service_interface iface = edb::service_interface_register
(c, path, interface
, es::method("SendBool"
, [expected_bool] (edb::const_message, edb::service_interface, bool b)
{
ck_assert(b == expected_bool);
return b;
}
, es::ins<bool>("bool")
, es::outs<bool>("bool")
)
, es::method("SendByte"
, [expected_byte] (edb::const_message, edb::service_interface, char c)
{
ck_assert(c == expected_byte);
return c;
}
, es::ins<char>("byte")
, es::outs<char>("byte")
)
, es::method("SendUint32"
, [expected_uint32] (edb::const_message, edb::service_interface, uint32_t n)
{
ck_assert(n == expected_uint32);
return n;
}
, es::ins<uint32_t>("uint32")
, es::outs<uint32_t>("uint32")
)
, es::method("SendInt32"
, [expected_int32] (edb::const_message, edb::service_interface, int32_t n)
{
ck_assert(n == expected_int32);
return n;
}
, es::ins<int32_t>("int32")
, es::outs<int32_t>("int32")
)
, es::method("SendInt16"
, [expected_int16] (edb::const_message, edb::service_interface, int16_t n)
{
ck_assert(n == expected_int16);
return n;
}
, es::ins<int16_t>("int16")
, es::outs<int16_t>("int16")
)
, es::method("SendDouble"
, [expected_double] (edb::const_message, edb::service_interface, double n)
{
ck_assert(n == expected_double);
return n;
}
, es::ins<double>("double")
, es::outs<double>("double")
)
, es::method("SendString"
, [expected_string] (edb::const_message, edb::service_interface, std::string const& n)
{
std::cout << "SendString " << n.size() << " " << n << std::endl;
ck_assert(n == expected_string);
return n;
}
, es::ins<std::string>("string")
, es::outs<std::string>("string")
)
, es::method("GetVoid"
, [expected_bool] (edb::const_message, edb::service_interface, bool b)
{
ck_assert(b == expected_bool);
}
, es::ins<bool>("string")
)
, es::method("SendStringWithBool"
, [expected_string, expected_bool] (edb::const_message, edb::service_interface
, std::string const& n, bool b)
{
ck_assert(n == expected_string);
ck_assert(b == expected_bool);
return n;
}
, es::ins<std::string, bool>("string", "bool")
, es::outs<std::string>("string")
)
, es::method("SendStringAndBool"
, [expected_string, expected_bool] (edb::const_message, edb::service_interface
, 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")
)
, es::method("SendStringAndBoolWithoutReturn"
, [expected_string, expected_bool] (edb::const_message, edb::service_interface
, std::string const& s, bool b
, std::string* out_s, bool* out_b)
{
std::cout << "Running SendStringAndBool" << std::endl;
ck_assert(s == expected_string);
ck_assert(b == expected_bool);
*out_s = s;
*out_b = b;
}
, es::ins<std::string, bool>("string", "bool")
, es::outs<std::string, bool>("string", "bool")
)
);
using namespace std::placeholders;
edb::name_request<std::uint32_t>(c, bus, ELDBUS_NAME_REQUEST_FLAG_DO_NOT_QUEUE
, & ::on_name_request);
std::cout << "registered" << std::endl;
edb::object o = c.get_object(bus, path);
edb::proxy p = o.get_proxy(interface);
using namespace std::placeholders;
p.call<bool>
("SendBool"
, -1
, std::bind
([expected_bool] (std::error_code const& ec, edb::const_message const& /*msg*/, bool b)
{
if(!ec)
{
std::cout << "bool received " << b << std::endl;
ck_assert(b == expected_bool);
}
else
{
std::cout << "error " << ec.message() << std::endl;
const char *errname = "", *errmsg = "";
// eldbus_message_error_get(msg, &errname, &errmsg);
std::cout << "error " << errname << " " << errmsg << std::endl;
std::abort();
}
}
, _1, _2, _4)
, expected_bool
);
p.call<char>
("SendByte"
, -1
, std::bind
([expected_byte] (std::error_code const& ec, edb::const_message const& msg, char c)
{
if(!ec)
{
std::cout << "char received " << c << std::endl;
ck_assert(c == expected_byte);
}
else
{
std::cout << "error " << ec.message() << std::endl;
const char *errname, *errmsg;
std::tie(errname, errmsg) = msg.error_get();
std::cout << "error " << errname << " " << errmsg << std::endl;
std::abort();
}
}
, _1, _2, _4)
, expected_byte
);
p.call<uint32_t>
("SendUint32"
, -1
, std::bind
([expected_uint32] (std::error_code const& ec, edb::const_message const& msg, uint32_t i)
{
if(!ec)
{
std::cout << "uint32_t received " << i << std::endl;
ck_assert(i == expected_uint32);
}
else
{
std::cout << "error " << ec.message() << std::endl;
const char *errname, *errmsg;
std::tie(errname, errmsg) = msg.error_get();
std::cout << "error " << errname << " " << errmsg << std::endl;
std::abort();
}
}
, _1, _2, _4)
, expected_uint32
);
p.call<int32_t>
("SendInt32"
, -1
, std::bind
([expected_int32] (std::error_code const& ec, edb::const_message const& msg, int32_t i)
{
if(!ec)
{
std::cout << "int32_t received " << i << std::endl;
ck_assert(i == expected_int32);
}
else
{
std::cout << "error " << ec.message() << std::endl;
const char *errname, *errmsg;
std::tie(errname, errmsg) = msg.error_get();
std::cout << "error " << errname << " " << errmsg << std::endl;
std::abort();
}
}
, _1, _2, _4)
, expected_int32
);
p.call<int16_t>
("SendInt16"
, -1
, std::bind
([expected_int16] (std::error_code const& ec, edb::const_message const& msg, int16_t i)
{
if(!ec)
{
std::cout << "int16_t received " << i << std::endl;
ck_assert(i == expected_int16);
}
else
{
std::cout << "error " << ec.message() << std::endl;
const char *errname, *errmsg;
std::tie(errname, errmsg) = msg.error_get();
std::cout << "error " << errname << " " << errmsg << std::endl;
std::abort();
}
}
, _1, _2, _4)
, expected_int16
);
p.call<double>
("SendDouble"
, -1
, std::bind
([expected_double] (std::error_code const& ec, edb::const_message const& msg, double i)
{
if(!ec)
{
std::cout << "double received " << i << std::endl;
ck_assert(i == expected_double);
}
else
{
std::cout << "error " << ec.message() << std::endl;
const char *errname, *errmsg;
std::tie(errname, errmsg) = msg.error_get();
std::cout << "error " << errname << " " << errmsg << std::endl;
std::abort();
}
}
, _1, _2, _4)
, expected_double
);
p.call<std::string>
("SendString"
, -1
, std::bind
([expected_string] (std::error_code const& ec, edb::const_message const& msg, std::string i)
{
if(!ec)
{
std::cout << "string received " << i << std::endl;
ck_assert(i == expected_string);
}
else
{
std::cout << "error " << ec.message() << std::endl;
const char *errname, *errmsg;
std::tie(errname, errmsg) = msg.error_get();
std::cout << "error " << errname << " " << errmsg << std::endl;
std::abort();
}
}
, _1, _2, _4)
, expected_string
);
p.call<void>
("GetVoid"
, -1
, std::bind
([] (std::error_code const& ec, edb::const_message const& msg)
{
if(!ec)
{
std::cout << "GetVoid returned succesfully" << std::endl;
}
else
{
std::cout << "error " << ec.message() << std::endl;
const char *errname, *errmsg;
std::tie(errname, errmsg) = msg.error_get();
std::cout << "error " << errname << " " << errmsg << std::endl;
std::abort();
}
}
, _1, _2)
, expected_bool
);
p.call<std::string>
("SendStringWithBool"
, -1
, std::bind
([expected_string] (std::error_code const& ec, edb::const_message const& msg, std::string i)
{
if(!ec)
{
std::cout << "string received " << i << std::endl;
ck_assert(i == expected_string);
}
else
{
std::cout << "error " << ec.message() << std::endl;
const char *errname, *errmsg;
std::tie(errname, errmsg) = msg.error_get();
std::cout << "error " << errname << " " << errmsg << std::endl;
std::abort();
}
}
, _1, _2, _4)
, expected_string
, expected_bool
);
p.call<std::tuple<std::string, bool> >
("SendStringAndBool"
, -1
, std::bind
([expected_string, expected_bool]
(std::error_code const& ec, edb::const_message const& msg, std::string i, bool b)
{
if(!ec)
{
std::cout << "string received " << i << std::endl;
ck_assert(i == expected_string);
ck_assert(b == expected_bool);
}
else
{
std::cout << "error " << ec.message() << std::endl;
const char *errname, *errmsg;
std::tie(errname, errmsg) = msg.error_get();
std::cout << "error " << errname << " " << errmsg << std::endl;
std::abort();
}
}
, _1, _2, _4, _5)
, expected_string
, expected_bool
);
p.call<std::tuple<std::string, bool> >
("SendStringAndBoolWithoutReturn"
, -1
, std::bind
([expected_string, expected_bool]
(std::error_code const& ec, edb::const_message const& msg, std::string i, bool b)
{
if(!ec)
{
std::cout << "string received " << i << std::endl;
ck_assert(i == expected_string);
ck_assert(b == expected_bool);
::ecore_main_loop_quit();
}
else
{
std::cout << "error " << ec.message() << std::endl;
const char *errname, *errmsg;
std::tie(errname, errmsg) = msg.error_get();
std::cout << "error " << errname << " " << errmsg << std::endl;
std::abort();
}
}
, _1, _2, _4, _5)
, expected_string
, expected_bool
);
// eldbus_name_owner_changed_callback_add(c.native_handle(), bus, on_name_owner_changed,
// c.native_handle(), EINA_TRUE);
ecore_main_loop_begin();
std::cout << "out of loop" << std::endl;
}
END_TEST
void
eldbus_test_client(TCase* tc)
{
tcase_add_test(tc, eldbus_cxx_client);
}

View File

@ -0,0 +1,32 @@
#include "Eldbus.hh"
#include "Ecore.hh"
#include <algorithm>
#include <iostream>
#include <check.h>
START_TEST(eldbus_cxx_session_connection)
{
efl::eldbus::eldbus_init init;
efl::eldbus::connection c(efl::eldbus::session);
}
END_TEST
START_TEST(eldbus_cxx_system_connection)
{
efl::eldbus::eldbus_init init;
efl::eldbus::connection c(efl::eldbus::system);
}
END_TEST
void
eldbus_test_connection(TCase* tc)
{
tcase_add_test(tc, eldbus_cxx_session_connection);
tcase_add_test(tc, eldbus_cxx_system_connection);
}