From 30df128be5dd3d2cea4c976ed5d5c9b85a15aa77 Mon Sep 17 00:00:00 2001 From: Felipe Magno de Almeida Date: Thu, 3 Jul 2014 16:28:22 +0900 Subject: [PATCH] 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("string", "bool") , es::outs("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 --- src/Makefile.am | 2 + src/Makefile_Eet_Cxx.am | 2 - src/Makefile_Eina_Cxx.am | 3 + src/Makefile_Eldbus_Cxx.am | 47 ++ src/bindings/eet_cxx/Eet.hh | 7 +- .../eet_fold.hh => eina_cxx/eina_fold.hh} | 10 +- .../eina_cxx/eina_integer_sequence.hh | 30 ++ .../eet_tuple.hh => eina_cxx/eina_tuple.hh} | 12 +- src/bindings/eina_cxx/eina_tuple_unwrap.hh | 38 ++ src/bindings/eldbus_cxx/Eldbus.hh | 13 + src/bindings/eldbus_cxx/eldbus_basic.hh | 150 ++++++ src/bindings/eldbus_cxx/eldbus_error.hh | 22 + src/bindings/eldbus_cxx/eldbus_freedesktop.hh | 73 +++ .../eldbus_cxx/eldbus_integer_sequence.hh | 41 ++ src/bindings/eldbus_cxx/eldbus_message.hh | 283 +++++++++++ .../eldbus_cxx/eldbus_message_arguments.hh | 56 +++ src/bindings/eldbus_cxx/eldbus_proxy_call.hh | 117 +++++ src/bindings/eldbus_cxx/eldbus_raw_tuple.hh | 30 ++ src/bindings/eldbus_cxx/eldbus_service.hh | 379 +++++++++++++++ .../eldbus_cxx/eldbus_signature_traits.hh | 194 ++++++++ src/lib/eldbus/eldbus_service.c | 46 +- src/lib/eldbus/eldbus_service.h | 4 + src/tests/eldbus_cxx/eldbus_cxx_suite.cc | 106 ++++ .../eldbus_cxx_test_eldbus_client.cc | 458 ++++++++++++++++++ .../eldbus_cxx_test_eldbus_connect.cc | 32 ++ 25 files changed, 2121 insertions(+), 34 deletions(-) create mode 100644 src/Makefile_Eldbus_Cxx.am rename src/bindings/{eet_cxx/eet_fold.hh => eina_cxx/eina_fold.hh} (75%) rename src/bindings/{eet_cxx/eet_tuple.hh => eina_cxx/eina_tuple.hh} (84%) create mode 100644 src/bindings/eina_cxx/eina_tuple_unwrap.hh create mode 100644 src/bindings/eldbus_cxx/Eldbus.hh create mode 100644 src/bindings/eldbus_cxx/eldbus_basic.hh create mode 100644 src/bindings/eldbus_cxx/eldbus_error.hh create mode 100644 src/bindings/eldbus_cxx/eldbus_freedesktop.hh create mode 100644 src/bindings/eldbus_cxx/eldbus_integer_sequence.hh create mode 100644 src/bindings/eldbus_cxx/eldbus_message.hh create mode 100644 src/bindings/eldbus_cxx/eldbus_message_arguments.hh create mode 100644 src/bindings/eldbus_cxx/eldbus_proxy_call.hh create mode 100644 src/bindings/eldbus_cxx/eldbus_raw_tuple.hh create mode 100644 src/bindings/eldbus_cxx/eldbus_service.hh create mode 100644 src/bindings/eldbus_cxx/eldbus_signature_traits.hh create mode 100644 src/tests/eldbus_cxx/eldbus_cxx_suite.cc create mode 100644 src/tests/eldbus_cxx/eldbus_cxx_test_eldbus_client.cc create mode 100644 src/tests/eldbus_cxx/eldbus_cxx_test_eldbus_connect.cc diff --git a/src/Makefile.am b/src/Makefile.am index 62ea229695..9ba81321d3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -32,6 +32,7 @@ include Makefile_Evil.am include Makefile_Escape.am include Makefile_Eina.am +include Makefile_Eina_Cxx.am include Makefile_Eo.am include Makefile_Eet.am include Makefile_Eolian.am @@ -76,6 +77,7 @@ include Makefile_Evas_Cxx.am endif include Makefile_Eina_Cxx.am +include Makefile_Eldbus_Cxx.am include Makefile_Eolian_Cxx.am include Makefile_Eet_Cxx.am include Makefile_Eo_Cxx.am diff --git a/src/Makefile_Eet_Cxx.am b/src/Makefile_Eet_Cxx.am index d2d55925c9..2e1487da8e 100644 --- a/src/Makefile_Eet_Cxx.am +++ b/src/Makefile_Eet_Cxx.am @@ -8,9 +8,7 @@ dist_installed_eetcxxmainheaders_DATA = bindings/eet_cxx/Eet.hh installed_eetcxxheadersdir = $(includedir)/eet-cxx-@VMAJ@/eet-cxx dist_installed_eetcxxheaders_DATA = \ bindings/eet_cxx/eet_composite.hh \ -bindings/eet_cxx/eet_fold.hh \ bindings/eet_cxx/eet_register.hh \ -bindings/eet_cxx/eet_tuple.hh \ bindings/eet_cxx/eet_type.hh ### Unit tests diff --git a/src/Makefile_Eina_Cxx.am b/src/Makefile_Eina_Cxx.am index 2fd916ce22..cfac2478a6 100644 --- a/src/Makefile_Eina_Cxx.am +++ b/src/Makefile_Eina_Cxx.am @@ -11,6 +11,7 @@ dist_installed_einacxxheaders_DATA = \ bindings/eina_cxx/eina_accessor.hh \ bindings/eina_cxx/eina_clone_allocators.hh \ bindings/eina_cxx/eina_error.hh \ +bindings/eina_cxx/eina_fold.hh \ bindings/eina_cxx/eina_inarray.hh \ bindings/eina_cxx/eina_inlist.hh \ bindings/eina_cxx/eina_integer_sequence.hh \ @@ -24,6 +25,8 @@ bindings/eina_cxx/eina_range_types.hh \ bindings/eina_cxx/eina_ref.hh \ bindings/eina_cxx/eina_stringshare.hh \ bindings/eina_cxx/eina_thread.hh \ +bindings/eina_cxx/eina_tuple.hh \ +bindings/eina_cxx/eina_tuple_unwrap.hh \ bindings/eina_cxx/eina_type_traits.hh \ bindings/eina_cxx/eina_value.hh diff --git a/src/Makefile_Eldbus_Cxx.am b/src/Makefile_Eldbus_Cxx.am new file mode 100644 index 0000000000..17b094110e --- /dev/null +++ b/src/Makefile_Eldbus_Cxx.am @@ -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 diff --git a/src/bindings/eet_cxx/Eet.hh b/src/bindings/eet_cxx/Eet.hh index a350696c7a..0c329f5cdc 100644 --- a/src/bindings/eet_cxx/Eet.hh +++ b/src/bindings/eet_cxx/Eet.hh @@ -4,9 +4,10 @@ #include #include -#include #include +#include + #include #include #include @@ -36,10 +37,10 @@ struct descriptor_type struct push_back { template - struct apply : _mpl::push_back::type> {}; + struct apply : eina::_mpl::push_back::type> {}; }; - typedef typename _mpl::fold< std::tuple, push_back + typedef typename eina::_mpl::fold< std::tuple, push_back , descriptor >::type type; }; diff --git a/src/bindings/eet_cxx/eet_fold.hh b/src/bindings/eina_cxx/eina_fold.hh similarity index 75% rename from src/bindings/eet_cxx/eet_fold.hh rename to src/bindings/eina_cxx/eina_fold.hh index 7ff19aee1c..167e0df52c 100644 --- a/src/bindings/eet_cxx/eet_fold.hh +++ b/src/bindings/eina_cxx/eina_fold.hh @@ -1,9 +1,9 @@ -#ifndef EFL_EET_FOLD_HH_ -#define EFL_EET_FOLD_HH_ +#ifndef EFL_EINA_FOLD_HH_ +#define EFL_EINA_FOLD_HH_ -#include +#include -namespace efl { namespace eet { +namespace efl { namespace eina { namespace _mpl { @@ -11,7 +11,7 @@ template ::type>::type result; - typedef typename fold_impl::type + typedef typename fold_impl::type , F, result >::type type; diff --git a/src/bindings/eina_cxx/eina_integer_sequence.hh b/src/bindings/eina_cxx/eina_integer_sequence.hh index b1f98a0efa..854bb8f3d0 100644 --- a/src/bindings/eina_cxx/eina_integer_sequence.hh +++ b/src/bindings/eina_cxx/eina_integer_sequence.hh @@ -70,6 +70,36 @@ using index_sequence = integer_sequence; template using make_index_sequence = make_integer_sequence; +template +struct pop_integer_sequence_t; + +template +struct pop_integer_sequence_t, integer_sequence > +{ + typedef integer_sequence type; +}; + +template +struct pop_integer_sequence_t, integer_sequence > +{ + typedef integer_sequence type; +}; + +template +struct pop_integer_sequence_t, integer_sequence > +{ + typedef integer_sequence type; +}; + +template +struct pop_integer_sequence_t, integer_sequence > + : pop_integer_sequence_t, integer_sequence > +{ +}; + +template +using pop_integer_sequence = typename pop_integer_sequence_t::type; + /** * @} */ diff --git a/src/bindings/eet_cxx/eet_tuple.hh b/src/bindings/eina_cxx/eina_tuple.hh similarity index 84% rename from src/bindings/eet_cxx/eet_tuple.hh rename to src/bindings/eina_cxx/eina_tuple.hh index 2fbb3950b5..f0f22d9cae 100644 --- a/src/bindings/eet_cxx/eet_tuple.hh +++ b/src/bindings/eina_cxx/eina_tuple.hh @@ -1,9 +1,7 @@ -#ifndef EFL_EET_EET_TUPLE_HH_ -#define EFL_EET_EET_TUPLE_HH_ +#ifndef EFL_EINA_EINA_TUPLE_HH_ +#define EFL_EINA_EINA_TUPLE_HH_ -namespace efl { namespace eet { - -namespace _mpl { +namespace efl { namespace eina { namespace _mpl { template struct push_back; @@ -32,8 +30,6 @@ struct pop_front > typedef C type; }; -} - -} } +} } } #endif diff --git a/src/bindings/eina_cxx/eina_tuple_unwrap.hh b/src/bindings/eina_cxx/eina_tuple_unwrap.hh new file mode 100644 index 0000000000..379f492e92 --- /dev/null +++ b/src/bindings/eina_cxx/eina_tuple_unwrap.hh @@ -0,0 +1,38 @@ +#ifndef EINA_CXX_EINA_TUPLE_UNWRAP_HH +#define EINA_CXX_EINA_TUPLE_UNWRAP_HH + +#include + +namespace efl { namespace eina { + +template +auto call_tuple_unwrap(Callable const& callable, T const& tuple + , eina::index_sequence) + -> decltype(callable(std::get(tuple)...)) +{ + return callable(std::get(tuple)...); +} + +template +auto call_tuple_unwrap_prefix(Callable const& callable, T const& tuple + , eina::index_sequence + , Args&&... args) + -> decltype(callable(std::move(args)..., std::get(tuple)...)) +{ + return callable(std::move(args)..., std::get(tuple)...); +} + +template +auto call_tuple_unwrap_suffix(Callable const& callable, T const& tuple + , eina::index_sequence + , Args&&... args) + -> decltype(callable(std::get(tuple)..., std::move(args)...)) +{ + return callable(std::get(tuple)..., std::move(args)...); +} + +} } + +#endif diff --git a/src/bindings/eldbus_cxx/Eldbus.hh b/src/bindings/eldbus_cxx/Eldbus.hh new file mode 100644 index 0000000000..67cbaf6482 --- /dev/null +++ b/src/bindings/eldbus_cxx/Eldbus.hh @@ -0,0 +1,13 @@ +#ifndef EFL_ELDBUS_HH_ +#define EFL_ELDBUS_HH_ + +#include +#include + +#include +#include +#include +#include +#include + +#endif diff --git a/src/bindings/eldbus_cxx/eldbus_basic.hh b/src/bindings/eldbus_cxx/eldbus_basic.hh new file mode 100644 index 0000000000..12903daa0c --- /dev/null +++ b/src/bindings/eldbus_cxx/eldbus_basic.hh @@ -0,0 +1,150 @@ +#ifndef ELDBUS_CXX_ELDBUS_BASIC_HH +#define ELDBUS_CXX_ELDBUS_BASIC_HH + +#include +#include + +#include + +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 + void call(const char* method, double timeout, Callback&& callback, Args... args) const + { + eldbus::_detail::proxy_call(_proxy, method, timeout, std::move(callback), args...); + } + + template + void call(const char* method, double timeout, Callback&& callback, Args... args) const + { + eldbus::_detail::proxy_call(_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(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(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 diff --git a/src/bindings/eldbus_cxx/eldbus_error.hh b/src/bindings/eldbus_cxx/eldbus_error.hh new file mode 100644 index 0000000000..dad1d1b84a --- /dev/null +++ b/src/bindings/eldbus_cxx/eldbus_error.hh @@ -0,0 +1,22 @@ +#ifndef ELDBUS_ERROR_HH +#define ELDBUS_ERROR_HH + +#include + +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 diff --git a/src/bindings/eldbus_cxx/eldbus_freedesktop.hh b/src/bindings/eldbus_cxx/eldbus_freedesktop.hh new file mode 100644 index 0000000000..9e1c2086cd --- /dev/null +++ b/src/bindings/eldbus_cxx/eldbus_freedesktop.hh @@ -0,0 +1,73 @@ +#ifndef EFL_ELDBUS_CXX_ELDBUS_FREEDESKTOP_HH +#define EFL_ELDBUS_CXX_ELDBUS_FREEDESKTOP_HH + +#include +#include +#include +#include + +namespace efl { namespace eldbus { namespace _detail { + +template +void _callback_wrapper(void* data, Eldbus_Message const* message, Eldbus_Pending* pending) +{ + std::cout << "_callback_wrapper" << std::endl; + Callback* callback(static_cast(data)); + + const char* errname, *errmsg; + if (eldbus_message_error_get(message, &errname, &errmsg)) + { + std::cout << "error " << errname << " " << errmsg << std::endl; + std::tuple tuple; + eldbus::const_message msg( ::eldbus_message_ref(const_cast(message))); + eina::error_code ec (eldbus::call_error_code(), eina::eina_error_category()); + eina::call_tuple_unwrap_prefix + (*callback, tuple, eina::make_index_sequence() + , ec, msg, pending); + } + + typename raw_tuple >::type tuple; + if(sizeof...(Ins)) + { + if(!_detail::_init_raw_tuple<0u, std::tuple > + (eldbus_message_iter_get(message) + , tuple, std::integral_constant())) + { + std::cout << "error init raw tuple" << std::endl; + std::tuple tuple; + eldbus::const_message msg( ::eldbus_message_ref(const_cast(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() + , ec, msg, pending); + } + } + std::cout << "OK go" << std::endl; + eina::error_code ec; + eldbus::const_message msg( ::eldbus_message_ref(const_cast(message))); + eina::call_tuple_unwrap_prefix + (*callback, tuple, eina::make_index_sequence() + , ec, msg, pending); +} + +template +void _free_cb(void* data, const void*) +{ + delete static_cast(data); +} + +} + +template +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); + eldbus_pending_free_cb_add(r.native_handle(), &_detail::_free_cb, f); + return r; +} + +} } + +#endif diff --git a/src/bindings/eldbus_cxx/eldbus_integer_sequence.hh b/src/bindings/eldbus_cxx/eldbus_integer_sequence.hh new file mode 100644 index 0000000000..282936a91a --- /dev/null +++ b/src/bindings/eldbus_cxx/eldbus_integer_sequence.hh @@ -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 +struct integer_sequence +{ + typedef T value_type; + static constexpr std::size_t size() { return sizeof...(Ints); } + typedef integer_sequence type; +}; + +template struct concat; + +template +struct concat, integer_sequence > + : integer_sequence {}; + +template +using Concat = typename concat::type; + +template struct gen_seq; +template using make_integer_sequence = typename gen_seq::type; + +template +struct gen_seq : Concat + , make_integer_sequence>{}; + +template<> struct gen_seq : integer_sequence{}; +template<> struct gen_seq : integer_sequence{}; + +template +using index_sequence = integer_sequence; + +template +using make_index_sequence = make_integer_sequence; + +} } } + +#endif diff --git a/src/bindings/eldbus_cxx/eldbus_message.hh b/src/bindings/eldbus_cxx/eldbus_message.hh new file mode 100644 index 0000000000..9a6eeab014 --- /dev/null +++ b/src/bindings/eldbus_cxx/eldbus_message.hh @@ -0,0 +1,283 @@ +#ifndef ELDBUS_CXX_ELDBUS_MESSAGE_HH +#define ELDBUS_CXX_ELDBUS_MESSAGE_HH + +#include +#include + +namespace efl { namespace eldbus { + +struct message_value +{ + message_value() : _iterator(0) {} + message_value( ::Eldbus_Message_Iter* iterator) : _iterator(iterator) {} + + template + T get() const + { + assert(!!_iterator); + std::cout << "trying to read " << _detail::signature_traits::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::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(value); + } + pointer operator->() const + { + return const_cast(&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(other.native_handle()))) + { + } + ~const_message() + { + eldbus_message_unref(const_cast(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 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(other)) + { + } + typedef Eldbus_Message* native_handle_type; + native_handle_type native_handle() { return const_cast(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(const_pending::native_handle()); + } +}; + +} } + +#endif diff --git a/src/bindings/eldbus_cxx/eldbus_message_arguments.hh b/src/bindings/eldbus_cxx/eldbus_message_arguments.hh new file mode 100644 index 0000000000..6c57b0216b --- /dev/null +++ b/src/bindings/eldbus_cxx/eldbus_message_arguments.hh @@ -0,0 +1,56 @@ +#ifndef ELDBUS_CXX_ELDBUS_MESSAGE_ARGUMENTS_HH +#define ELDBUS_CXX_ELDBUS_MESSAGE_ARGUMENTS_HH + +#include + +#include +#include + +namespace efl { namespace eldbus { namespace _detail { + +template +bool _init_raw_tuple(Eldbus_Message_Iter*, Tuple const&, std::true_type) +{ + return true; +} + +template +bool _init_raw_tuple(Eldbus_Message_Iter* iterator, Tuple const& tuple, std::false_type) +{ + typedef signature_traits::type> traits; + typedef typename traits::value_type element_type; + + char* c = eldbus_message_iter_signature_get(iterator); + if(c[0] != signature_traits::sig) + { + return false; + } + + eldbus_message_iter_get_and_next(iterator, *c, &std::get(tuple)); + + return _init_raw_tuple + (iterator, tuple, std::integral_constant::value)>()); +} + +template +bool _append_tuple(Eldbus_Message*, Tuple const&, std::true_type) +{ + return true; +} + +template +bool _append_tuple(Eldbus_Message* message, Tuple const& tuple, std::false_type) +{ + typedef signature_traits::type> traits; + + char signature[2] = {traits::sig, 0}; + if(!eldbus_message_arguments_append(message, signature, traits::to_raw(std::get(tuple)))) + return false; + + return _append_tuple + (message, tuple, std::integral_constant::value)>()); +} + +} } } + +#endif diff --git a/src/bindings/eldbus_cxx/eldbus_proxy_call.hh b/src/bindings/eldbus_cxx/eldbus_proxy_call.hh new file mode 100644 index 0000000000..2780e75687 --- /dev/null +++ b/src/bindings/eldbus_cxx/eldbus_proxy_call.hh @@ -0,0 +1,117 @@ +#ifndef ELDBUS_PROXY_CALL_HH +#define ELDBUS_PROXY_CALL_HH + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +namespace efl { namespace eldbus { namespace _detail { + +template struct tag {}; + +template +void _on_call_impl(void* data, Eldbus_Message const* message, Eldbus_Pending* pending) +{ + std::unique_ptr callback(static_cast(data)); + + const char* errname, *errmsg; + if (eldbus_message_error_get(message, &errname, &errmsg)) + { + Seq tuple; + ::eldbus_message_ref(const_cast(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::value>() + , ec, msg, pending); + } + + typename raw_tuple::type tuple; + if(std::tuple_size::value) + { + if(!_detail::_init_raw_tuple<0u, Seq> + (eldbus_message_iter_get(message) + , tuple, std::integral_constant::value == 0)>())) + { + Seq tuple; + ::eldbus_message_ref(const_cast(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::value>() + , ec, msg, pending); + } + } + eina::error_code ec; + ::eldbus_message_ref(const_cast(message)); + eldbus::const_message msg(message); + eina::call_tuple_unwrap_prefix + (*callback, tuple, eina::make_index_sequence::value>() + , ec, msg, pending); +} + +template +void _on_call(void* data, Eldbus_Message const* message, Eldbus_Pending* pending) +{ + _detail::_on_call_impl(data, message, pending); +} + +template +void proxy_call_impl2(Eldbus_Proxy* proxy, const char* method, double timeout + , Callback&& callback, Args const&... args) +{ + typedef std::tuple tuple_args; + char signature[signature_size::value +1]; + _detail::init_signature_array + (signature, eina::make_index_sequence::value +1>()); + + Callback* c = new Callback(std::move(callback)); + + eldbus_proxy_call(proxy, method, &_on_call, c, timeout, signature + , _detail::to_raw(args)...); +} + +template +void proxy_call_impl(tag, Eldbus_Proxy* proxy, const char* method, double timeout + , Callback&& callback, Args const&... args) +{ + typedef std::tuple reply_tuple; + _detail::proxy_call_impl2(proxy, method, timeout, std::move(callback), args...); +} + +template +void proxy_call_impl(tag >, Eldbus_Proxy* proxy, const char* method, double timeout + , Callback&& callback, Args const&... args) +{ + typedef std::tuple reply_tuple; + _detail::proxy_call_impl2(proxy, method, timeout, std::move(callback), args...); +} + +template +void proxy_call_impl(tag, Eldbus_Proxy* proxy, const char* method, double timeout + , Callback&& callback, Args const&... args) +{ + typedef std::tuple<> reply_tuple; + _detail::proxy_call_impl2(proxy, method, timeout, std::move(callback), args...); +} + +template +void proxy_call(Eldbus_Proxy* proxy, const char* method, double timeout + , Callback&& callback, Args const&... args) +{ + return proxy_call_impl(tag(), proxy, method, timeout, std::move(callback), args...); +} + +} } } + +#endif + diff --git a/src/bindings/eldbus_cxx/eldbus_raw_tuple.hh b/src/bindings/eldbus_cxx/eldbus_raw_tuple.hh new file mode 100644 index 0000000000..ee17cfb32f --- /dev/null +++ b/src/bindings/eldbus_cxx/eldbus_raw_tuple.hh @@ -0,0 +1,30 @@ +#ifndef EFL_ELDBUS_CXX_ELDBUS_RAW_TUPLE_HH +#define EFL_ELDBUS_CXX_ELDBUS_RAW_TUPLE_HH + +#include + +#include +#include + +namespace efl { namespace eldbus { namespace _detail { + +template +struct raw_tuple; + +template +struct raw_tuple > +{ + struct push_back + { + template + struct apply + : eina::_mpl::push_back::raw_type> {}; + }; + + typedef typename eina::_mpl::fold< std::tuple, push_back + , std::tuple<> >::type type; +}; + +} } } + +#endif diff --git a/src/bindings/eldbus_cxx/eldbus_service.hh b/src/bindings/eldbus_cxx/eldbus_service.hh new file mode 100644 index 0000000000..aca6d3fa35 --- /dev/null +++ b/src/bindings/eldbus_cxx/eldbus_service.hh @@ -0,0 +1,379 @@ +#ifndef ELDBUS_CXX_ELDBUS_SERVICE_HH +#define ELDBUS_CXX_ELDBUS_SERVICE_HH + +#include + +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 +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 +struct const_char_type +{ + typedef const char* type; +}; + +} + +template +struct ins +{ + ins(typename _detail::const_char_type::type... names) : _names({names...}) {} + + static constexpr std::size_t size() { return sizeof...(Args); } + + typedef std::tuple types; + std::array _names; +}; + +template +struct outs +{ + outs(typename _detail::const_char_type::type... names) : _names({names...}) {} + + static constexpr std::size_t size() { return sizeof...(Args); } + + typedef std::tuple types; + std::array _names; +}; + +void foo(int); + +template +method_specification +method(const char* name, F f, Ins ins, Outs outs) +{ + return method_specification + {name, f, ins, outs} + ; +} + +template +method_specification, service::outs > +method(const char* name, F f, service::outs outs) +{ + return method_specification, service::outs > + {name, f, service::ins<>(), outs} + ; +} + +template +method_specification, service::outs<> > +method(const char* name, F f, service::ins ins) +{ + return method_specification, service::outs<> > + {name, f, ins, service::outs<>()} + ; +} + +} + +template class params + , typename ... Args> +int _fill_method_impl(std::array& array + , params const& + , std::true_type) +{ + array[I] = Eldbus_Arg_Info {0, 0}; + return 0; +} + + +template class params + , typename ... Args> +int _fill_method_impl(std::array& array + , params const& directional_methods + , std::false_type) +{ + typedef std::tuple params_type; + static const char sig[2] + = {_detail::signature_traits + < + typename std::tuple_element::type + >::sig + , '\0' + }; + array[I] = {sig + , directional_methods._names[I] + }; + return 0; +} + + +template class params + , typename ... Args> +int _fill_method(std::array& array + , params const& directional_methods) +{ + _fill_method_impl(array, directional_methods + , std::integral_constant()); + return 0; +} + +template +void _foo(T...) {} + +template class params, typename ... Args + , std::size_t... Seq> +void _fill_methods_impl(std::array& array + , params const& directional_methods + , eina::index_sequence + ) +{ + eldbus::_foo(eldbus::_fill_method(array, directional_methods) ...); +} + +template class params, typename ... Args> +void _fill_methods(std::array& array + , params const& directional_methods) +{ + eldbus::_fill_methods_impl(array, directional_methods + , eina::make_index_sequence()); +} + +template +void _create_methods_specification(Tuple const& + , std::array::value+1>& methods + , std::integral_constant + , std::true_type) +{ + methods[I] = Eldbus_Method {0, 0, 0, 0, 0, 0}; +}; + +template +T get_in(Eldbus_Message const* msg) +{ + typename _detail::signature_traits::raw_type object; + + const char sig[2] = {_detail::signature_traits::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 +Eldbus_Message* _method_callback_call +(Callable const& callable, service::ins const&, service::outs const& + , eina::index_sequence, eina::index_sequence + , eina::index_sequence + , Eldbus_Service_Interface const* iface, Eldbus_Message const* message + , typename std::enable_if + (nullptr) + , *static_cast(nullptr) + , std::get(std::tuple())... + , &std::get + (*static_cast*>(nullptr))... + ) + )>::value, int>::type) +{ + typedef std::tuple tuple_ins; + typename _detail::raw_tuple::type tuple_ins_raw; + _detail::_init_raw_tuple<0u, tuple_ins> + (eldbus_message_iter_get(message), tuple_ins_raw + , std::integral_constant::value == 0u)>()); + + std::tuple tuple_outs; + + eldbus::const_message msg( ::eldbus_message_ref(const_cast(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 traits; + std::get<0u>(tuple_outs) = + callable(msg, siface, std::get(tuple_ins_raw)..., &std::get(tuple_outs)...); + + Eldbus_Message *reply = eldbus_message_method_return_new(message); + _detail::_append_tuple<0u>(reply, tuple_outs, std::false_type()); + return reply; +} + +template +Eldbus_Message* _method_callback_call +(Callable const& callable, service::ins const&, service::outs const& + , eina::index_sequence, eina::index_sequence + , eina::index_sequence + , Eldbus_Service_Interface const* iface, Eldbus_Message const* message + , long) +{ + typedef std::tuple tuple_ins; + typename _detail::raw_tuple::type tuple_ins_raw; + _detail::_init_raw_tuple<0u, tuple_ins> + (eldbus_message_iter_get(message), tuple_ins_raw + , std::integral_constant::value == 0u)>()); + + typedef std::tuple tuple_outs_type; + tuple_outs_type tuple_outs; + + eldbus::const_message msg( ::eldbus_message_ref(const_cast(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(tuple_ins_raw)..., &std::get(tuple_outs)...); + + Eldbus_Message *reply = eldbus_message_method_return_new(message); + _detail::_append_tuple<0u> + (reply, tuple_outs + , std::integral_constant::value == 0u>()); + return reply; +} + +template +Eldbus_Message* _method_callback(void* data, Eldbus_Service_Interface const* iface, Eldbus_Message const* msg) +{ + std::tuple* + tuple = static_cast*>(data); + + return _method_callback_call(std::get<0u>(*tuple), std::get<1u>(*tuple), std::get<2u>(*tuple) + , eina::make_index_sequence + ::value>() + , eina::make_index_sequence + ::value>() + , eina::pop_integer_sequence + + , eina::make_index_sequence + ::value> + >() + , iface, msg, 0); +} + +template +void _create_methods_specification_impl(Method const& method, Eldbus_Method& eldbus_method, std::false_type) +{ + std::array* + in_params = new std::array; + + eldbus::_fill_methods(*in_params, method.ins); + + std::array* + out_params = new std::array; + + eldbus::_fill_methods(*out_params, method.outs); + + eldbus_method = {method.name, &(*in_params)[0], &(*out_params)[0] + , reinterpret_cast + (static_cast + (&_method_callback)) + , ELDBUS_METHOD_FLAG_HAS_DATA + , new std::tuple(std::move(method.f), method.ins, method.outs)}; +} + +template +void _create_methods_specification_impl(Method const& method, Eldbus_Method& eldbus_method, std::true_type) +{ + std::array* + in_params = new std::array; + + eldbus::_fill_methods(*in_params, method.ins); + + std::array* + out_params = new std::array; + + eldbus::_fill_methods(*out_params, method.outs); + + eldbus_method = {method.name, &(*in_params)[0], &(*out_params)[0], method.f, 0, 0}; +} + +template +void _create_methods_specification(Tuple const& tuple + , std::array::value+1>& methods + , std::integral_constant + , std::false_type) +{ + typedef Eldbus_Message*(*function_type)(Eldbus_Service_Interface const*, Eldbus_Message const*); + + typedef typename std::tuple_element::type method_type; + + _create_methods_specification_impl(std::get(tuple), methods[I] + , std::is_convertible()); + + return _create_methods_specification(tuple, methods + , std::integral_constant() + , std::integral_constant::value>()); +}; + +template +std::array::value+1> _create_methods_specification + (Tuple const& tuple + ) +{ + typedef std::tuple_size tuple_size; + std::array array; + + _create_methods_specification(tuple, array + , std::integral_constant() + , std::integral_constant::value>()); + return array; +}; + +template +service_interface service_interface_register(connection& c, const char* path + , const char* interface + , Args... args + ) +{ + std::array* methods + = new std::array + ( + _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 diff --git a/src/bindings/eldbus_cxx/eldbus_signature_traits.hh b/src/bindings/eldbus_cxx/eldbus_signature_traits.hh new file mode 100644 index 0000000000..8f2f32400b --- /dev/null +++ b/src/bindings/eldbus_cxx/eldbus_signature_traits.hh @@ -0,0 +1,194 @@ +#ifndef ELDBUS_SIGNATURE_TRAITS_HH_ +#define ELDBUS_SIGNATURE_TRAITS_HH_ + +#include +#include + +namespace efl { namespace eldbus { namespace _detail { + +template +struct signature_traits; + +template <> +struct signature_traits +{ + typedef Eina_Bool raw_type; + typedef bool value_type; + typedef std::integral_constant 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 +{ + typedef char raw_type; + typedef raw_type value_type; + typedef std::integral_constant sig_size; + static int const sig = 'y'; + + static raw_type to_raw(value_type v) { return v; } +}; + +template <> +struct signature_traits +{ + typedef int16_t raw_type; + typedef raw_type value_type; + typedef std::integral_constant sig_size; + static char const sig = 'n'; + + static raw_type to_raw(value_type v) { return v; } +}; + +template <> +struct signature_traits +{ + typedef uint16_t raw_type; + typedef raw_type value_type; + typedef std::integral_constant sig_size; + static char const sig = 'q'; + + static raw_type to_raw(value_type i) { return i; } +}; + +template <> +struct signature_traits +{ + typedef int32_t raw_type; + typedef raw_type value_type; + typedef std::integral_constant sig_size; + static char const sig = 'i'; + + static raw_type to_raw(value_type i) { return i; } +}; + +template <> +struct signature_traits +{ + typedef uint32_t raw_type; + typedef raw_type value_type; + typedef std::integral_constant sig_size; + static char const sig = 'u'; + + static raw_type to_raw(value_type i) { return i; } +}; + +template <> +struct signature_traits +{ + typedef int64_t raw_type; + typedef raw_type value_type; + typedef std::integral_constant sig_size; + static char const sig = 'x'; + + static raw_type to_raw(value_type i) { return i; } +}; + +template <> +struct signature_traits +{ + typedef uint64_t raw_type; + typedef raw_type value_type; + typedef std::integral_constant sig_size; + static char const sig = 't'; + + static raw_type to_raw(value_type i) { return i; } +}; + +template <> +struct signature_traits +{ + typedef double raw_type; + typedef raw_type value_type; + typedef std::integral_constant sig_size; + static char const sig = 'd'; + + static raw_type to_raw(value_type i) { return i; } +}; + +template <> +struct signature_traits +{ + typedef const char* raw_type; + typedef std::string value_type; + typedef std::integral_constant sig_size; + static char const sig = 's'; + + static raw_type to_raw(std::string const& s) { return s.c_str(); } +}; + +template +struct signature_traits : signature_traits +{ +}; + +template +typename signature_traits::raw_type to_raw(T const& object) +{ + return signature_traits::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 +constexpr std::size_t add(std::size_t L, std::size_t R, T ... O) +{ + return L + R + add(O...); +} + +template +struct signature_size_impl; + +template +struct signature_size_impl > + : std::integral_constant + ::type>::sig_size::value...)> +{ + +}; + +template +struct signature_size : signature_size_impl::value> > +{ + +}; + +template +void call_all(T...) {} + +template ::type> +int init_signature(char (&signature)[N]) +{ + signature[I] = signature_traits::type>::sig; + return 0; +} + +template +int init_signature(char (&signature)[I+1]) +{ + signature[I] = 0; + return 0; +} + +template +void init_signature_array(char (&signature)[N], eina::index_sequence) +{ + call_all(_detail::init_signature >(signature)...); +} + +} } } + +#endif diff --git a/src/lib/eldbus/eldbus_service.c b/src/lib/eldbus/eldbus_service.c index 4b7295ca8d..0b06fa37de 100644 --- a/src/lib/eldbus/eldbus_service.c +++ b/src/lib/eldbus/eldbus_service.c @@ -395,7 +395,7 @@ cb_introspect(const Eldbus_Service_Interface *_iface, const Eldbus_Message *mess } 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 @@ -435,15 +435,15 @@ _default_interfaces_free(void) static const Eldbus_Method _property_methods[] = { { "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"}), - NULL, _cb_property_set, 0 + NULL, _cb_property_set, 0, NULL }, { "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 = { "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[] = { @@ -1282,6 +1282,20 @@ _object_unregister(DBusConnection *conn EINA_UNUSED, void *user_data) _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 _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)) 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 { - if (iface->obj) - reply = method->cb(iface, eldbus_msg); - else - { - /* if iface does have obj it is some of FreeDesktop interfaces: - Introspectable, Properties or ObjectManager */ - iface->obj = obj; - reply = method->cb(iface, eldbus_msg); - iface->obj = NULL; - } + if (iface->obj) + reply = _eldbus_method_call(method, iface, eldbus_msg); + else + { + /* if iface does have obj it is some of FreeDesktop interfaces: + Introspectable, Properties or ObjectManager */ + iface->obj = obj; + reply = _eldbus_method_call(method, iface, eldbus_msg); + iface->obj = NULL; + } } eldbus_message_unref(eldbus_msg); diff --git a/src/lib/eldbus/eldbus_service.h b/src/lib/eldbus/eldbus_service.h index e5915dc15c..fdf272e37c 100644 --- a/src/lib/eldbus/eldbus_service.h +++ b/src/lib/eldbus/eldbus_service.h @@ -9,6 +9,7 @@ */ #define ELDBUS_METHOD_FLAG_DEPRECATED 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 @@ -32,6 +33,8 @@ typedef struct _Eldbus_Arg_Info 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_Data_Cb)(void* data, const Eldbus_Service_Interface *iface, const Eldbus_Message *message); // @since 1.11 + /** * Callback function to append property value to message. * @@ -69,6 +72,7 @@ typedef struct _Eldbus_Method const Eldbus_Arg_Info *out; Eldbus_Method_Cb cb; unsigned int flags; + void* data; // @since 1.11 } Eldbus_Method; typedef struct _Eldbus_Signal diff --git a/src/tests/eldbus_cxx/eldbus_cxx_suite.cc b/src/tests/eldbus_cxx/eldbus_cxx_suite.cc new file mode 100644 index 0000000000..a8be883abd --- /dev/null +++ b/src/tests/eldbus_cxx/eldbus_cxx_suite.cc @@ -0,0 +1,106 @@ + +#include +#include "Eldbus.hh" + +#include +#include + +#include + +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("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; +} diff --git a/src/tests/eldbus_cxx/eldbus_cxx_test_eldbus_client.cc b/src/tests/eldbus_cxx/eldbus_cxx_test_eldbus_client.cc new file mode 100644 index 0000000000..5355196a9a --- /dev/null +++ b/src/tests/eldbus_cxx/eldbus_cxx_test_eldbus_client.cc @@ -0,0 +1,458 @@ + +#include "Eldbus.hh" +#include "Ecore.hh" + +#include + +#include + +#include + +#include + +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") + , es::outs("bool") + ) + , es::method("SendByte" + , [expected_byte] (edb::const_message, edb::service_interface, char c) + { + ck_assert(c == expected_byte); + return c; + } + , es::ins("byte") + , es::outs("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") + , es::outs("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") + , es::outs("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") + , es::outs("int16") + ) + , es::method("SendDouble" + , [expected_double] (edb::const_message, edb::service_interface, double n) + { + ck_assert(n == expected_double); + return n; + } + , es::ins("double") + , es::outs("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("string") + , es::outs("string") + ) + , es::method("GetVoid" + , [expected_bool] (edb::const_message, edb::service_interface, bool b) + { + ck_assert(b == expected_bool); + } + , es::ins("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("string", "bool") + , es::outs("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("string", "bool") + , es::outs("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("string", "bool") + , es::outs("string", "bool") + ) + ); + using namespace std::placeholders; + edb::name_request(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 + ("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 + ("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 + ("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 + ("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 + ("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 + ("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 + ("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 + ("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 + ("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 > + ("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 > + ("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); +} diff --git a/src/tests/eldbus_cxx/eldbus_cxx_test_eldbus_connect.cc b/src/tests/eldbus_cxx/eldbus_cxx_test_eldbus_connect.cc new file mode 100644 index 0000000000..3d7716ec06 --- /dev/null +++ b/src/tests/eldbus_cxx/eldbus_cxx_test_eldbus_connect.cc @@ -0,0 +1,32 @@ + +#include "Eldbus.hh" +#include "Ecore.hh" + +#include + +#include + +#include + +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); +}