forked from enlightenment/efl
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/D1052efl-1.11
parent
ddac21534f
commit
30df128be5
25 changed files with 2121 additions and 34 deletions
@ -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 |
@ -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>() |
||||