summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelipe Magno de Almeida <felipe@expertisesolutions.com.br>2016-08-07 16:52:48 -0300
committerFelipe Magno de Almeida <felipe@expertisesolutions.com.br>2016-09-11 23:44:05 -0300
commita63cfcafc7f8524dfad4e1bba763fb17c69d50e1 (patch)
treeadc59470b9cb5f6458351842bcc82de523dec247
parent98229bc5d6cf1ebe11af4bb05a32f2a30b470f6e (diff)
downloadefl-a63cfcafc7f8524dfad4e1bba763fb17c69d50e1.tar.gz
eolian-cxx: Implement future template class for C++
-rw-r--r--src/Makefile_Cxx.am34
-rw-r--r--src/Makefile_Ecore.am13
-rw-r--r--src/Makefile_Eolian_Cxx.am4
-rw-r--r--src/bindings/cxx/ecore_cxx/Ecore.hh164
-rw-r--r--src/bindings/cxx/ecore_cxx/Ecore_Manual.hh176
-rw-r--r--src/bindings/cxx/eina_cxx/Eina.hh1
-rw-r--r--src/bindings/cxx/eina_cxx/eina_copy_traits.hh43
-rw-r--r--src/bindings/cxx/eo_cxx/Eo.hh3
-rw-r--r--src/bindings/cxx/eo_cxx/eo_cxx_interop.hh34
-rw-r--r--src/bindings/cxx/eo_cxx/eo_promise.hh416
-rw-r--r--src/lib/eolian_cxx/grammar/type_impl.hpp8
-rw-r--r--src/tests/eo_cxx/eo_cxx_suite.cc27
-rw-r--r--src/tests/eo_cxx/eo_cxx_suite.h11
-rw-r--r--src/tests/eo_cxx/eo_cxx_test_promise.cc347
14 files changed, 1096 insertions, 185 deletions
diff --git a/src/Makefile_Cxx.am b/src/Makefile_Cxx.am
index 2fda128446..917d285aca 100644
--- a/src/Makefile_Cxx.am
+++ b/src/Makefile_Cxx.am
@@ -13,6 +13,7 @@ bindings/cxx/eo_cxx/Eo.hh \
bindings/cxx/eo_cxx/eo_init.hh \
bindings/cxx/eo_cxx/eo_ops.hh \
bindings/cxx/eo_cxx/eo_wref.hh \
+bindings/cxx/eo_cxx/eo_promise.hh \
bindings/cxx/eo_cxx/eo_private.hh
### Elementary C++
@@ -120,7 +121,8 @@ CLEANFILES += $(edje_eolian_cxx_hh) $(edje_eolian_cxx_impl) lib/edje/Edje.hh
### Ecore src/lib/ecore
installed_ecorecxxheadersdir = $(includedir)/ecore-cxx-@VMAJ@
dist_installed_ecorecxxheaders_DATA = \
-bindings/cxx/ecore_cxx/Ecore.hh
+bindings/cxx/ecore_cxx/Ecore.hh \
+bindings/cxx/ecore_cxx/Ecore_Manual.hh
nodist_installed_ecorecxxheaders_DATA = $(ecore_eolian_cxx_hh) $(ecore_eolian_cxx_impl) \
lib/ecore/Ecore.eo.hh
@@ -168,6 +170,7 @@ bindings/cxx/eina_cxx/eina_tuple_unwrap.hh \
bindings/cxx/eina_cxx/eina_type_traits.hh \
bindings/cxx/eina_cxx/eina_value.hh \
bindings/cxx/eina_cxx/eina_workarounds.hh \
+bindings/cxx/eina_cxx/eina_copy_traits.hh \
bindings/cxx/eina_cxx/Eina.hh
### Eio
@@ -186,9 +189,9 @@ CLEANFILES += $(eio_eolian_cxx_hh) $(eio_eolian_cxx_impl) lib/eio/Eio.hh
if EFL_ENABLE_TESTS
-### Tests for Eina
-check_PROGRAMS += tests/eina_cxx/eina_cxx_suite
-TESTS += tests/eina_cxx/eina_cxx_suite
+### Tests for Eina and Eo
+check_PROGRAMS += tests/eina_cxx/eina_cxx_suite tests/eo_cxx/eo_cxx_suite
+TESTS += tests/eina_cxx/eina_cxx_suite tests/eo_cxx/eo_cxx_suite
tests_eina_cxx_eina_cxx_suite_SOURCES = \
tests/eina_cxx/eina_cxx_suite.cc \
@@ -232,11 +235,34 @@ tests_eina_cxx_eina_cxx_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
@CHECK_CFLAGS@ \
@EO_CFLAGS@ \
@ECORE_CFLAGS@ \
+@ECORE_CXX_CFLAGS@ \
@EO_CXX_CFLAGS@ \
@EINA_CXX_CFLAGS@
tests_eina_cxx_eina_cxx_suite_LDADD = @CHECK_LIBS@ @USE_EINA_LIBS@ @USE_EO_LIBS@
tests_eina_cxx_eina_cxx_suite_DEPENDENCIES = @USE_EINA_INTERNAL_LIBS@ @USE_EO_INTERNAL_LIBS@
+tests_eo_cxx_eo_cxx_suite_SOURCES = \
+tests/eo_cxx/eo_cxx_suite.cc \
+tests/eo_cxx/eo_cxx_test_promise.cc
+
+tests_eo_cxx_eo_cxx_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
+-DTESTS_WD=\"`pwd`\" \
+-DTESTS_SRC_DIR=\"$(top_srcdir)/src/tests/eo_cxx\" \
+-DPACKAGE_BUILD_DIR=\"$(abs_top_builddir)/src/tests/eo_cxx\" \
+-DTESTS_BUILD_DIR=\"$(top_builddir)/src/tests/eo_cxx\" \
+-I$(top_builddir)/src/lib/efl \
+-I$(top_builddir)/src/lib/efl/interfaces \
+-I$(top_srcdir)/src/bin/eina_cxx \
+-I$(top_builddir)/src/tests/eina_cxx \
+@CHECK_CFLAGS@ \
+@EO_CFLAGS@ \
+@ECORE_CFLAGS@ \
+@ECORE_CXX_CFLAGS@ \
+@EO_CXX_CFLAGS@ \
+@EINA_CXX_CFLAGS@
+tests_eo_cxx_eo_cxx_suite_LDADD = @CHECK_LIBS@ @USE_EINA_LIBS@ @USE_EO_LIBS@ @USE_ECORE_LIBS@
+tests_eo_cxx_eo_cxx_suite_DEPENDENCIES = @USE_EINA_INTERNAL_LIBS@ @USE_EO_INTERNAL_LIBS@ @USE_ECORE_INTERNAL_LIBS@
+
### Tests for ecore
check_PROGRAMS += tests/ecore_cxx/ecore_cxx_suite tests/ecore_cxx/cxx_compile_test
diff --git a/src/Makefile_Ecore.am b/src/Makefile_Ecore.am
index 4a1d6a6795..606ae66482 100644
--- a/src/Makefile_Ecore.am
+++ b/src/Makefile_Ecore.am
@@ -6,7 +6,7 @@ ecore_eolian_files_legacy = \
lib/ecore/ecore_exe.eo \
lib/ecore/efl_loop_timer.eo
-ecore_eolian_files = \
+ecore_eolian_files_public = \
lib/ecore/efl_loop.eo \
lib/ecore/efl_loop_user.eo \
lib/ecore/efl_loop_fd.eo \
@@ -20,8 +20,11 @@ ecore_eolian_files = \
lib/ecore/efl_io_stderr.eo \
lib/ecore/efl_io_file.eo \
lib/ecore/efl_io_copier.eo \
+ lib/ecore/ecore_parent.eo
+
+ecore_eolian_files = \
+ $(ecore_eolian_files_public) \
lib/ecore/efl_promise.eo \
- lib/ecore/ecore_parent.eo \
$(ecore_eolian_files_legacy)
ecore_eolian_type_files = \
@@ -300,7 +303,7 @@ endif
if HAVE_JS
-generated_ecore_js_bindings = $(ecore_eolian_files:%.eo=%.eo.js.cc)
+generated_ecore_js_bindings = $(ecore_eolian_files_public:%.eo=%.eo.js.cc)
GENERATED_JS_BINDINGS += $(generated_ecore_js_bindings)
@@ -308,7 +311,7 @@ endif
if HAVE_CXX11
-ecore_eolian_cxx_hh = $(ecore_eolian_files:%.eo=%.eo.hh)
-ecore_eolian_cxx_impl = $(ecore_eolian_files:%.eo=%.eo.impl.hh)
+ecore_eolian_cxx_hh = $(ecore_eolian_files_public:%.eo=%.eo.hh)
+ecore_eolian_cxx_impl = $(ecore_eolian_files_public:%.eo=%.eo.impl.hh)
endif
diff --git a/src/Makefile_Eolian_Cxx.am b/src/Makefile_Eolian_Cxx.am
index b8fad1cf4a..c142a4b5fa 100644
--- a/src/Makefile_Eolian_Cxx.am
+++ b/src/Makefile_Eolian_Cxx.am
@@ -57,7 +57,7 @@ bin_eolian_cxx_eolian_cxx_SOURCES = \
bin_eolian_cxx_eolian_cxx_CXXFLAGS = -I$(top_builddir)/src/lib/efl \
-I$(top_srcdir)/src/lib/eolian_cxx/ \
-@CHECK_CFLAGS@ @EINA_CFLAGS@ @EINA_CXX_CFLAGS@ @EO_CFLAGS@ \
+@CHECK_CFLAGS@ @EINA_CFLAGS@ @EINA_CXX_CFLAGS@ @EO_CXX_CFLAGS@ @ECORE_CXX_CFLAGS@ @EO_CFLAGS@ \
-I$(top_srcdir)/src/bindings/cxx/eina_cxx \
@EOLIAN_CXX_CFLAGS@ @EOLIAN_CFLAGS@
@@ -159,7 +159,7 @@ tests_eolian_cxx_eolian_cxx_suite_CXXFLAGS = \
-DTESTS_BUILD_DIR=\"$(top_builddir)/src/tests/eolian_cxx\" \
@CHECK_CFLAGS@ @EOLIAN_CXX_CFLAGS@ @EINA_CXX_CFLAGS@ \
@EOLIAN_CFLAGS@ @EINA_CFLAGS@ @EO_CFLAGS@ @ECORE_CFLAGS@ \
-@EO_CXX_CFLAGS@
+@EO_CXX_CFLAGS@ @ECORE_CXX_CFLAGS@
tests_eolian_cxx_eolian_cxx_suite_CFLAGS = ${tests_eolian_cxx_eolian_cxx_suite_CXXFLAGS}
tests_eolian_cxx_eolian_cxx_suite_CPPFLAGS = ${tests_eolian_cxx_eolian_cxx_suite_CXXFLAGS}
diff --git a/src/bindings/cxx/ecore_cxx/Ecore.hh b/src/bindings/cxx/ecore_cxx/Ecore.hh
index 75ebc3e26a..bd2cd7e40a 100644
--- a/src/bindings/cxx/ecore_cxx/Ecore.hh
+++ b/src/bindings/cxx/ecore_cxx/Ecore.hh
@@ -13,168 +13,6 @@
#ifdef EFL_BETA_API_SUPPORT
#include <Ecore.eo.hh>
#endif
-
-namespace efl { namespace ecore {
-
-template <typename T>
-struct _identity
-{
- typedef T type;
-};
-
-template <typename F>
-void _ecore_main_loop_thread_safe_call_async_callback(void* data)
-{
- std::unique_ptr<F> f (static_cast<F*>(data));
- try
- {
- (*f)();
- }
- catch(std::bad_alloc const& e)
- {
- eina_error_set(ENOMEM);
- }
- catch(std::system_error const& e)
- {
- efl::eina::set_error_code(e.code());
- }
- catch(...)
- {
- eina_error_set( efl::eina::unknown_error() );
- }
-}
-
-template <typename T>
-struct _return_buffer
-{
- typename std::aligned_storage<sizeof(T),std::alignment_of<T>::value>::type buffer;
-};
-
-template <>
-struct _return_buffer<void>
-{
-};
-
-template <typename F>
-struct _data
-{
- F& f;
- std::exception_ptr exception;
- typedef typename std::result_of<F()>::type result_type;
- _return_buffer<result_type> return_buffer;
-};
-
-template <typename F>
-void* _ecore_main_loop_thread_safe_call_sync_callback_aux(_data<F>* d, _identity<void>)
-{
- d->f();
- if(eina_error_get())
- d->exception = make_exception_ptr(std::system_error(efl::eina::get_error_code()));
- return 0;
-}
-
-template <typename F, typename R>
-void* _ecore_main_loop_thread_safe_call_sync_callback_aux(_data<F>* d, _identity<R>)
-{
- typedef R result_type;
- new (&d->return_buffer.buffer) result_type ( std::move(d->f()) );
- if(eina_error_get())
- {
- d->exception = make_exception_ptr(std::system_error(efl::eina::get_error_code()));
- eina_error_set(0);
- result_type* p = static_cast<result_type*>(static_cast<void*>(&d->return_buffer.buffer));
- p->~result_type();
- }
- return 0;
-}
-
-template <typename F>
-void* _ecore_main_loop_thread_safe_call_sync_callback(void* data)
-{
- _data<F>* d = static_cast<_data<F>*>(data);
- try
- {
- return _ecore_main_loop_thread_safe_call_sync_callback_aux
- (d, _identity<typename std::result_of<F()>::type>());
- }
- catch(std::bad_alloc const& e)
- {
- d->exception = std::current_exception();
- }
- catch(std::system_error const& e)
- {
- d->exception = std::current_exception();
- }
- catch(...)
- {
- d->exception = std::current_exception();
- }
- return 0;
-}
-
-template <typename F>
-void main_loop_thread_safe_call_async(F&& f)
-{
- ::ecore_main_loop_thread_safe_call_async( &ecore::_ecore_main_loop_thread_safe_call_async_callback<F>
- , new F(std::forward<F>(f)) );
-}
-
-template <typename F>
-void _get_return_value(_data<F>& data, _identity<void>)
-{
- if(data.exception)
- {
- std::rethrow_exception(data.exception);
- }
-}
-
-template <typename F, typename R>
-R _get_return_value(_data<F>& data, _identity<R>)
-{
- if(!data.exception)
- {
- R* b_ = static_cast<R*>(static_cast<void*>(&data.return_buffer.buffer));
- struct destroy
- {
- destroy(R* x_) : p_(x_)
- {}
- ~destroy()
- {
- p_->~R();
- }
- R* p_;
- } destroy_temp(b_);
- return std::move(*b_);
- }
- else
- {
- std::rethrow_exception(data.exception);
- }
-}
-
-template <typename F>
-typename std::result_of<F()>::type
-main_loop_thread_safe_call_sync(F&& f)
-{
- typedef typename std::result_of<F()>::type result_type;
- _data<F> data {f, nullptr, {}};
- ::ecore_main_loop_thread_safe_call_sync
- (&ecore::_ecore_main_loop_thread_safe_call_sync_callback<F>, &data);
- return _get_return_value(data, _identity<result_type>());
-}
-
-struct ecore_init
-{
- ecore_init()
- {
- ::ecore_init();
- }
- ~ecore_init()
- {
- ::ecore_shutdown();
- }
-};
-
-} }
+#include <Ecore_Manual.hh>
#endif
diff --git a/src/bindings/cxx/ecore_cxx/Ecore_Manual.hh b/src/bindings/cxx/ecore_cxx/Ecore_Manual.hh
new file mode 100644
index 0000000000..4bc90629a3
--- /dev/null
+++ b/src/bindings/cxx/ecore_cxx/Ecore_Manual.hh
@@ -0,0 +1,176 @@
+#ifndef _EFL_ECORE_CXX_ECORE_MANUAL_HH
+#define _EFL_ECORE_CXX_ECORE_MANUAL_HH
+
+#include <Ecore.h>
+
+#include <Eina.hh>
+
+#include <utility>
+#include <type_traits>
+#include <memory>
+#include <cstring>
+
+namespace efl { namespace ecore {
+
+template <typename T>
+struct _identity
+{
+ typedef T type;
+};
+
+template <typename F>
+void _ecore_main_loop_thread_safe_call_async_callback(void* data)
+{
+ std::unique_ptr<F> f (static_cast<F*>(data));
+ try
+ {
+ (*f)();
+ }
+ catch(std::bad_alloc const& e)
+ {
+ eina_error_set( ::EINA_ERROR_OUT_OF_MEMORY);
+ }
+ catch(std::system_error const& e)
+ {
+ efl::eina::set_error_code(e.code());
+ }
+ catch(...)
+ {
+ eina_error_set( efl::eina::unknown_error() );
+ }
+}
+
+template <typename T>
+struct _return_buffer
+{
+ typename std::aligned_storage<sizeof(T),std::alignment_of<T>::value>::type buffer;
+};
+
+template <>
+struct _return_buffer<void>
+{
+};
+
+template <typename F>
+struct _data
+{
+ F& f;
+ std::exception_ptr exception;
+ typedef typename std::result_of<F()>::type result_type;
+ _return_buffer<result_type> return_buffer;
+};
+
+template <typename F>
+void* _ecore_main_loop_thread_safe_call_sync_callback_aux(_data<F>* d, _identity<void>)
+{
+ d->f();
+ if(eina_error_get())
+ d->exception = make_exception_ptr(std::system_error(efl::eina::get_error_code()));
+ return 0;
+}
+
+template <typename F, typename R>
+void* _ecore_main_loop_thread_safe_call_sync_callback_aux(_data<F>* d, _identity<R>)
+{
+ typedef R result_type;
+ new (&d->return_buffer.buffer) result_type ( std::move(d->f()) );
+ if(eina_error_get())
+ {
+ d->exception = make_exception_ptr(std::system_error(efl::eina::get_error_code()));
+ eina_error_set(0);
+ result_type* p = static_cast<result_type*>(static_cast<void*>(&d->return_buffer.buffer));
+ p->~result_type();
+ }
+ return 0;
+}
+
+template <typename F>
+void* _ecore_main_loop_thread_safe_call_sync_callback(void* data)
+{
+ _data<F>* d = static_cast<_data<F>*>(data);
+ try
+ {
+ return _ecore_main_loop_thread_safe_call_sync_callback_aux
+ (d, _identity<typename std::result_of<F()>::type>());
+ }
+ catch(std::bad_alloc const& e)
+ {
+ d->exception = std::current_exception();
+ }
+ catch(std::system_error const& e)
+ {
+ d->exception = std::current_exception();
+ }
+ catch(...)
+ {
+ d->exception = std::current_exception();
+ }
+ return 0;
+}
+
+template <typename F>
+void main_loop_thread_safe_call_async(F&& f)
+{
+ ::ecore_main_loop_thread_safe_call_async( &ecore::_ecore_main_loop_thread_safe_call_async_callback<F>
+ , new F(std::forward<F>(f)) );
+}
+
+template <typename F>
+void _get_return_value(_data<F>& data, _identity<void>)
+{
+ if(data.exception)
+ {
+ std::rethrow_exception(data.exception);
+ }
+}
+
+template <typename F, typename R>
+R _get_return_value(_data<F>& data, _identity<R>)
+{
+ if(!data.exception)
+ {
+ R* b_ = static_cast<R*>(static_cast<void*>(&data.return_buffer.buffer));
+ struct destroy
+ {
+ destroy(R* x_) : p_(x_)
+ {}
+ ~destroy()
+ {
+ p_->~R();
+ }
+ R* p_;
+ } destroy_temp(b_);
+ return std::move(*b_);
+ }
+ else
+ {
+ std::rethrow_exception(data.exception);
+ }
+}
+
+template <typename F>
+typename std::result_of<F()>::type
+main_loop_thread_safe_call_sync(F&& f)
+{
+ typedef typename std::result_of<F()>::type result_type;
+ _data<F> data {f, nullptr, {}};
+ ::ecore_main_loop_thread_safe_call_sync
+ (&ecore::_ecore_main_loop_thread_safe_call_sync_callback<F>, &data);
+ return _get_return_value(data, _identity<result_type>());
+}
+
+struct ecore_init
+{
+ ecore_init()
+ {
+ ::ecore_init();
+ }
+ ~ecore_init()
+ {
+ ::ecore_shutdown();
+ }
+};
+
+} }
+
+#endif
diff --git a/src/bindings/cxx/eina_cxx/Eina.hh b/src/bindings/cxx/eina_cxx/Eina.hh
index c98681551d..f613415064 100644
--- a/src/bindings/cxx/eina_cxx/Eina.hh
+++ b/src/bindings/cxx/eina_cxx/Eina.hh
@@ -26,6 +26,7 @@
#include <eina_workarounds.hh>
#include <eina_future.hh>
#include <eina_deleter.hh>
+#include <eina_copy_traits.hh>
/**
* @page eina_cxx_main Eina C++ (BETA)
diff --git a/src/bindings/cxx/eina_cxx/eina_copy_traits.hh b/src/bindings/cxx/eina_cxx/eina_copy_traits.hh
new file mode 100644
index 0000000000..0db8bd85b4
--- /dev/null
+++ b/src/bindings/cxx/eina_cxx/eina_copy_traits.hh
@@ -0,0 +1,43 @@
+///
+/// @file eo_concrete.hh
+///
+
+#ifndef EFL_CXX_EINA_COPY_TRAITS_HH
+#define EFL_CXX_EINA_COPY_TRAITS_HH
+
+namespace efl { namespace eina {
+
+template <typename T, typename Enable = void>
+struct copy_from_c_traits;
+
+template <typename T>
+struct copy_from_c_traits<T, typename std::enable_if<std::is_fundamental<T>::value>::type>
+{
+ static void copy_to_unitialized(T* storage, void const* data)
+ {
+ std::memcpy(storage, data, sizeof(T));
+ }
+};
+
+template <typename T, typename Enable = void>
+struct alloc_to_c_traits;
+
+template <typename T>
+struct alloc_to_c_traits<T, typename std::enable_if<std::is_fundamental<T>::value>::type>
+{
+ typedef T c_type;
+ static c_type* copy_alloc(T const& value)
+ {
+ c_type* v = static_cast<c_type*>(malloc(sizeof(c_type)));
+ std::memcpy(v, &value, sizeof(c_type));
+ return v;
+ }
+ static void free_alloc(void* data)
+ {
+ ::free(data);
+ }
+};
+
+} }
+
+#endif
diff --git a/src/bindings/cxx/eo_cxx/Eo.hh b/src/bindings/cxx/eo_cxx/Eo.hh
index b7d1e856a3..771ee12da9 100644
--- a/src/bindings/cxx/eo_cxx/Eo.hh
+++ b/src/bindings/cxx/eo_cxx/Eo.hh
@@ -4,8 +4,9 @@
#include <eo_concrete.hh>
#include <eo_init.hh>
#include <eo_wref.hh>
-// #include <eo_inherit.hh>
+//#include <eo_inherit.hh>
//#include <eo_own_ptr.hh>
+#include <eo_promise.hh>
#include <eo_cxx_interop.hh>
#include <eo_event.hh>
diff --git a/src/bindings/cxx/eo_cxx/eo_cxx_interop.hh b/src/bindings/cxx/eo_cxx/eo_cxx_interop.hh
index 597ef3b703..fc1793fb67 100644
--- a/src/bindings/cxx/eo_cxx/eo_cxx_interop.hh
+++ b/src/bindings/cxx/eo_cxx/eo_cxx_interop.hh
@@ -55,14 +55,14 @@ struct out_traits<eina::optional<T&>> { typedef eina::optional<T&> type; };
template <>
struct out_traits<void*> { typedef void*& type; };
template <typename T>
-struct out_traits<efl::eina::future<T>> { typedef efl::eina::future<T>& type; };
+struct out_traits<efl::shared_future<T>> { typedef efl::shared_future<T>& type; };
template <typename T>
struct inout_traits { typedef T& type; };
template <>
struct inout_traits<void> { typedef void* type; };
template <typename T>
-struct inout_traits<efl::eina::future<T>> { typedef efl::eina::future<T>& type; };
+struct inout_traits<efl::shared_future<T>> { typedef efl::shared_future<T>& type; };
template <typename T>
struct return_traits { typedef T type; };
@@ -126,7 +126,11 @@ void assign_out_impl(T& lhs, Eo const* rhs, tag<T&, Eo const*>
lhs._reset(const_cast<Eo*>(rhs));
}
template <typename T>
-void assign_out_impl(efl::eina::future<T>& /*v*/, Eina_Promise*, tag<efl::eina::future<T>&, Eina_Promise*>)
+void assign_out_impl(efl::promise<T>& /*v*/, Eina_Promise*, tag<efl::promise<T>&, Eina_Promise*>)
+{
+}
+template <typename T>
+void assign_out_impl(efl::shared_future<T>& /*v*/, Efl_Future*, tag<efl::shared_future<T>&, Efl_Future*>)
{
}
template <typename Tag>
@@ -257,7 +261,12 @@ Eo const* convert_inout_impl(T v, tag<T, Eo const*>
return v._eo_ptr();
}
template <typename T>
-Eina_Promise* convert_inout_impl(efl::eina::future<T>& /*v*/, tag<efl::eina::future<T>, Eina_Promise*>)
+Eina_Promise* convert_inout_impl(efl::promise<T>& /*v*/, tag<efl::promise<T>, Eina_Promise*>)
+{
+ return nullptr;
+}
+template <typename T>
+Efl_Future* convert_inout_impl(efl::shared_future<T>& /*v*/, tag<efl::shared_future<T>, Efl_Future*>)
{
return nullptr;
}
@@ -511,7 +520,12 @@ inline const char* convert_to_c_impl(efl::eina::stringshare x, tag<const char*,
return eina_stringshare_ref(x.c_str());
}
template <typename T>
-Eina_Promise* convert_to_c_impl(efl::eina::future<T> const&, tag<Eina_Promise*, efl::eina::future<T>const&>)
+Eina_Promise* convert_to_c_impl(efl::promise<T> const&, tag<Eina_Promise*, efl::promise<T>const&>)
+{
+ std::abort();
+}
+template <typename T>
+Efl_Future* convert_to_c_impl(efl::shared_future<T> const&, tag<Efl_Future*, efl::shared_future<T>const&>)
{
std::abort();
}
@@ -653,11 +667,13 @@ eina::accessor<T> convert_to_return(Eina_Accessor* value, tag<Eina_Accessor*, ei
return eina::accessor<T>{ value };
}
template <typename T>
-struct is_future : std::false_type {};
-template <typename T>
-struct is_future<efl::eina::future<T>> : std::true_type {};
+efl::promise<T> convert_to_return(Eina_Promise* /*value*/, tag<Eina_Promise*, efl::promise<T>>)
+{
+ std::abort();
+ return {};
+}
template <typename T>
-T convert_to_return(Eina_Promise* /*value*/, tag<Eina_Promise*, T>, typename std::enable_if<is_future<T>::value>::type* = 0)
+efl::shared_future<T> convert_to_return(Efl_Future* /*value*/, tag<Efl_Future*, efl::shared_future<T>>)
{
std::abort();
return {};
diff --git a/src/bindings/cxx/eo_cxx/eo_promise.hh b/src/bindings/cxx/eo_cxx/eo_promise.hh
new file mode 100644
index 0000000000..b325d9cd12
--- /dev/null
+++ b/src/bindings/cxx/eo_cxx/eo_promise.hh
@@ -0,0 +1,416 @@
+///
+/// @file eo_concrete.hh
+///
+
+#ifndef EFL_CXX_EO_PROMISE_HH
+#define EFL_CXX_EO_PROMISE_HH
+
+#include <Efl.h>
+
+#include <Eina.hh>
+#include <Ecore_Manual.hh>
+
+#include <mutex>
+#include <condition_variable>
+
+namespace efl {
+
+namespace _impl {
+
+template <typename F, typename...Args>
+struct future_invoke_result_of;
+
+template <typename F, typename A0>
+struct future_invoke_result_of<F, A0>
+{
+ typedef typename std::result_of<F(A0)>::type type;
+};
+
+template <typename F>
+struct future_invoke_result_of<F, void>
+{
+ typedef typename std::result_of<F()>::type type;
+};
+
+template <typename A0, typename F>
+typename std::enable_if
+<
+ !std::is_same<A0, void>::value
+ && !std::is_same<typename std::result_of<F(A0)>::type, void>::value
+>::type
+future_invoke(F f, Efl_Event const* event)
+{
+ Efl_Future_Event_Success* info = static_cast<Efl_Future_Event_Success*>(event->info);
+ try
+ {
+ typename std::aligned_storage<sizeof(A0), alignof(A0)>::type storage;
+ eina::copy_from_c_traits<A0>::copy_to_unitialized
+ (static_cast<A0*>(static_cast<void*>(&storage)), info->value);
+ auto r = f(*static_cast<A0*>(static_cast<void*>(&storage)));
+ typedef decltype(r) result_type;
+ typedef typename eina::alloc_to_c_traits<result_type>::c_type c_type;
+ c_type* c_value = eina::alloc_to_c_traits<result_type>::copy_alloc(r);
+ efl_promise_value_set(info->next, c_value, & eina::alloc_to_c_traits<result_type>::free_alloc);
+ }
+ catch(...)
+ {
+ }
+}
+
+template <typename A0, typename F>
+typename std::enable_if<std::is_same<A0, void>::value>::type
+future_invoke(F f, Efl_Event const* event)
+{
+ Efl_Future_Event_Success* info = static_cast<Efl_Future_Event_Success*>(event->info);
+ try
+ {
+ f();
+ }
+ catch(...)
+ {
+ }
+}
+
+template <typename A0, typename A1, typename...OtherArgs, typename F>
+// typename future_invoke_result_of<F, A0, A1, OtherArgs...>::type
+void
+future_invoke(F f, Efl_Event const* event)
+{
+ Efl_Future_Event_Success* info = static_cast<Efl_Future_Event_Success*>(event->info);
+
+}
+
+}
+
+template <typename T>
+struct progress;
+
+namespace _impl {
+
+template <typename V = char>
+struct wait_state
+{
+ bool available = false;
+ bool has_failed = false;
+ std::mutex mutex;
+ std::condition_variable cv;
+ typename std::aligned_storage<sizeof(V), alignof(V)>::type storage;
+ Eina_Error error;
+};
+
+static void get_error_cb(void* data, Efl_Event const* event)
+{
+ struct wait_state<>* wait_state = static_cast<struct wait_state<>*>(data);
+ Efl_Future_Event_Failure* info = static_cast<Efl_Future_Event_Failure*>(event->info);
+ std::unique_lock<std::mutex> l(wait_state->mutex);
+ wait_state->error = info->error;
+ wait_state->has_failed = true;
+ wait_state->available = true;
+ wait_state->cv.notify_one();
+}
+
+struct shared_future_common
+{
+ explicit shared_future_common(Efl_Future* future)
+ : _future(future) {}
+ shared_future_common()
+ : _future(nullptr) {}
+ ~shared_future_common()
+ {
+ if(_future)
+ efl_unref(_future);
+ }
+ shared_future_common(shared_future_common const& future)
+ : _future(efl_ref(future._future))
+ {
+ }
+ shared_future_common& operator=(shared_future_common const& other)
+ {
+ _self_type tmp(other);
+ tmp.swap(*this);
+ return *this;
+ }
+ shared_future_common(shared_future_common&& future)
+ : _future(future._future)
+ {
+ future._future = nullptr;
+ }
+ shared_future_common& operator=(shared_future_common&& other)
+ {
+ other.swap(*this);
+ return *this;
+ }
+ void swap(shared_future_common& other)
+ {
+ std::swap(_future, other._future);
+ }
+ bool valid() const noexcept
+ {
+ return _future != nullptr;
+ }
+ void wait() const
+ {
+ if(eina_main_loop_is())
+ throw std::runtime_error("Deadlock");
+
+ struct wait_state<> wait_state;
+
+ efl::ecore::main_loop_thread_safe_call_async
+ ([&]
+ {
+ efl_future_then(this->_future, &wait_success, &wait_success, nullptr, &wait_state);
+ });
+
+ std::unique_lock<std::mutex> lock(wait_state.mutex);
+ while(!wait_state.available)
+ wait_state.cv.wait(lock);
+ }
+ static void wait_success(void* data, Efl_Event const*)
+ {
+ struct wait_state<>* wait_state = static_cast<struct wait_state<>*>(data);
+ std::unique_lock<std::mutex> l(wait_state->mutex);
+ wait_state->available = true;
+ wait_state->cv.notify_one();
+ }
+
+ typedef Efl_Future* native_handle_type;
+ typedef Efl_Future const* const_native_handle_type;
+ native_handle_type native_handle() noexcept { return _future; }
+ const_native_handle_type native_handle() const noexcept { return _future; }
+
+ typedef shared_future_common _self_type;
+ Efl_Future* _future;
+};
+
+template <typename T>
+struct shared_future_1_type : private shared_future_common
+{
+ typedef shared_future_common _base_type;
+
+ using _base_type::_base_type;
+ using _base_type::swap;
+ using _base_type::valid;
+ using _base_type::native_handle;
+ using _base_type::wait;
+ typedef _base_type::native_handle_type native_handle_type;
+
+ T get() const
+ {
+ if(eina_main_loop_is())
+ throw std::runtime_error("Deadlock");
+
+ struct wait_state<T> wait_state;
+
+ efl::ecore::main_loop_thread_safe_call_async
+ ([&]
+ {
+ efl_future_then(this->_future, &get_success, &_impl::get_error_cb, nullptr, &wait_state);
+ });
+
+ {
+ std::unique_lock<std::mutex> lock(wait_state.mutex);
+ while(!wait_state.available)
+ wait_state.cv.wait(lock);
+ }
+ if(wait_state.has_failed)
+ EFL_CXX_THROW(eina::system_error(eina::error_code(wait_state.error, eina::eina_error_category()), "EFL Eina Error"));
+ return *static_cast<T*>(static_cast<void*>(&wait_state.storage));
+ }
+
+ static void get_success(void* data, Efl_Event const* event)
+ {
+ struct wait_state<T>* wait_state = static_cast<struct wait_state<T>*>(data);
+ Efl_Future_Event_Success* info = static_cast<Efl_Future_Event_Success*>(event->info);
+
+ std::unique_lock<std::mutex> l(wait_state->mutex);
+ eina::copy_from_c_traits<T>::copy_to_unitialized
+ (static_cast<T*>(static_cast<void*>(&wait_state->storage)), info->value);
+ wait_state->available = true;
+ wait_state->cv.notify_one();
+ }
+
+ typedef shared_future_1_type<T> _self_type;
+};
+
+template <typename...Args>
+struct shared_future_varargs_type : private shared_future_common
+{
+ typedef shared_future_common _base_type;
+
+ using _base_type::_base_type;
+ using _base_type::swap;
+ using _base_type::valid;
+ using _base_type::native_handle;
+ using _base_type::wait;
+ typedef _base_type::native_handle_type native_handle_type;
+
+ typedef std::tuple<Args...> tuple_type;
+
+ std::tuple<Args...> get() const
+ {
+ if(eina_main_loop_is())
+ throw std::runtime_error("Deadlock");
+
+ struct wait_state<tuple_type> wait_state;
+
+ efl::ecore::main_loop_thread_safe_call_async
+ ([&]
+ {
+ efl_future_then(this->_future, &get_success, &_impl::get_error_cb, nullptr, &wait_state);
+ });
+
+ {
+ std::unique_lock<std::mutex> lock(wait_state.mutex);
+ while(!wait_state.available)
+ wait_state.cv.wait(lock);
+ }
+ if(wait_state.has_failed)
+ EFL_CXX_THROW(eina::system_error(eina::error_code(wait_state.error, eina::eina_error_category()), "EFL Eina Error"));
+ return *static_cast<tuple_type*>(static_cast<void*>(&wait_state.storage));
+ }
+
+ template <std::size_t N>
+ static void read_accessor(Eina_Accessor* accessor
+ , std::tuple<typename std::aligned_storage<sizeof(Args), alignof(Args)>::type...>& storage_tuple
+ , wait_state<tuple_type>* wait_state
+ , std::false_type)
+ {
+ typedef typename std::tuple_element<N, tuple_type>::type type;
+ void* value;
+ if(eina_accessor_data_get(accessor, N, &value))
+ {
+ eina::copy_from_c_traits<type>::copy_to_unitialized
+ (static_cast<type*>(static_cast<void*>(&std::get<N>(storage_tuple))), value);
+
+ std::cout << "copied value " << *static_cast<type*>(static_cast<void*>(&std::get<N>(storage_tuple)))
+ << std::endl;
+
+ _self_type::read_accessor<N+1>(accessor, storage_tuple, wait_state
+ , std::integral_constant<bool, (N+1 == sizeof...(Args))>());
+ }
+ else
+ {
+ std::abort();
+ // some error
+ }
+ }
+
+ template <std::size_t N, std::size_t...I>
+ static void read_accessor_end(std::tuple<typename std::aligned_storage<sizeof(Args), alignof(Args)>::type...>& storage_tuple
+ , wait_state<tuple_type>* wait_state
+ , eina::index_sequence<I...>)
+ {
+ std::unique_lock<std::mutex> l(wait_state->mutex);
+
+ new (&wait_state->storage) tuple_type{(*static_cast<typename std::tuple_element<I, tuple_type>::type*>
+ (static_cast<void*>(&std::get<I>(storage_tuple))))...};
+
+ wait_state->available = true;
+ wait_state->cv.notify_one();
+ }
+
+ template <std::size_t N>
+ static void read_accessor(Eina_Accessor*
+ , std::tuple<typename std::aligned_storage<sizeof(Args), alignof(Args)>::type...>& storage_tuple
+ , wait_state<tuple_type>* wait_state
+ , std::true_type)
+ {
+ _self_type::read_accessor_end<N>(storage_tuple, wait_state, eina::make_index_sequence<sizeof...(Args)>{});
+ }
+
+ static void get_success(void* data, Efl_Event const* event)
+ {
+ struct wait_state<tuple_type>* wait_state = static_cast<struct wait_state<tuple_type>*>(data);
+ Efl_Future_Event_Success* info = static_cast<Efl_Future_Event_Success*>(event->info);
+
+ Eina_Accessor* accessor = static_cast<Eina_Accessor*>(info->value);
+ std::tuple<typename std::aligned_storage<sizeof(Args), alignof(Args)>::type...> storage_tuple;
+
+ _self_type::read_accessor<0u>(accessor, storage_tuple, wait_state, std::false_type());
+ }
+
+ typedef shared_future_varargs_type<Args...> _self_type;
+};
+
+}
+
+template <typename...Args>
+struct shared_future : private std::conditional<sizeof...(Args) == 1, _impl::shared_future_1_type<typename std::tuple_element<0u, std::tuple<Args...>>::type>, _impl::shared_future_varargs_type<Args...>>::type
+{
+ typedef typename std::conditional<sizeof...(Args) == 1, _impl::shared_future_1_type<typename std::tuple_element<0u, std::tuple<Args...>>::type>, _impl::shared_future_varargs_type<Args...>>::type _base_type;
+
+ using _base_type::_base_type;
+ using _base_type::swap;
+ using _base_type::valid;
+ using _base_type::get;
+ using _base_type::wait;
+ using _base_type::native_handle;
+ typedef typename _base_type::native_handle_type native_handle_type;
+};
+
+template <typename...Args, typename Success, typename Error>
+shared_future
+<
+ typename std::enable_if
+ <
+ !std::is_same<void, typename std::tuple_element<0, std::tuple<Args...>>::type>::value
+ && !std::is_same<void, typename std::result_of<Success(Args...)>::type>::value
+ , typename std::result_of<Success(Args...)>::type
+ >::type
+> then(shared_future<Args...> future, Success success_cb, Error error_cb)
+{
+ struct private_data
+ {
+ Success success_cb;
+ Error error_cb;
+ shared_future<Args...> future;
+ };
+ private_data* pdata = new private_data
+ {std::move(success_cb), std::move(error_cb), std::move(future)};
+
+ Efl_Event_Cb raw_success_cb =
+ [] (void* data, Efl_Event const* event)
+ {
+ private_data* pdata = static_cast<private_data*>(data);
+ try
+ {
+ _impl::future_invoke<Args...>(pdata->success_cb, event);
+ // should value_set the next promise
+ }
+ catch(...)
+ {
+ // should fail the next promise
+ }
+ delete pdata;
+ };
+ Efl_Event_Cb raw_error_cb =
+ [] (void* data, Efl_Event const* event)
+ {
+ private_data* pdata = static_cast<private_data*>(data);
+ Efl_Future_Event_Failure* info = static_cast<Efl_Future_Event_Failure*>(event->info);
+ pdata->error_cb(eina::error_code(info->error, eina::eina_error_category()));
+ // should error the next promise (or should the promise do that for me automatically?)
+ delete pdata;
+ };
+
+ assert(pdata->future.valid());
+ Efl_Future* new_future
+ = efl_future_then(pdata->future.native_handle(), raw_success_cb, raw_error_cb, nullptr, pdata);
+ return shared_future<typename std::result_of<Success(Args...)>::type>{efl_ref(new_future)};
+}
+
+template <typename...Args, typename F>
+void then(shared_future<Args...> future, F function)
+{
+
+}
+
+template <typename...Args>
+struct promise
+{
+
+};
+
+}
+
+#endif
diff --git a/src/lib/eolian_cxx/grammar/type_impl.hpp b/src/lib/eolian_cxx/grammar/type_impl.hpp
index 6e18b2bda1..ac1118f077 100644
--- a/src/lib/eolian_cxx/grammar/type_impl.hpp
+++ b/src/lib/eolian_cxx/grammar/type_impl.hpp
@@ -256,7 +256,13 @@ struct visitor_generate
, {"promise", nullptr, nullptr, [&]
{
return replace_outer
- (complex, regular_type_def{" ::efl::eina::future", complex.outer.base_qualifier, {}});
+ (complex, regular_type_def{" ::efl::promise", complex.outer.base_qualifier, {}});
+ }
+ }
+ , {"future", nullptr, nullptr, [&]
+ {
+ return replace_outer
+ (complex, regular_type_def{" ::efl::shared_future", complex.outer.base_qualifier, {}});
}
}
, {"iterator", nullptr, nullptr, [&]
diff --git a/src/tests/eo_cxx/eo_cxx_suite.cc b/src/tests/eo_cxx/eo_cxx_suite.cc
new file mode 100644
index 0000000000..2362d38359
--- /dev/null
+++ b/src/tests/eo_cxx/eo_cxx_suite.cc
@@ -0,0 +1,27 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "eo_cxx_suite.h"
+#include "../efl_check.h"
+
+static const Efl_Test_Case etc[] = {
+ { "Promise", eo_cxx_test_promise },
+ { NULL, NULL }
+};
+
+int
+main(int argc, char* argv[])
+{
+ int failed_count;
+
+ if (!_efl_test_option_disp(argc, argv, etc))
+ return 0;
+
+ putenv(const_cast<char*>("EFL_RUN_IN_TREE=1"));
+
+ failed_count = _efl_suite_build_and_run(argc - 1, (const char **)argv + 1,
+ "Eo C++", etc);
+
+ return (failed_count == 0) ? 0 : 255;
+}
diff --git a/src/tests/eo_cxx/eo_cxx_suite.h b/src/tests/eo_cxx/eo_cxx_suite.h
new file mode 100644
index 0000000000..a5a1d6147c
--- /dev/null
+++ b/src/tests/eo_cxx/eo_cxx_suite.h
@@ -0,0 +1,11 @@
+#ifndef _EINA_CXX_SUITE_H
+#define _EINA_CXX_SUITE_H
+
+#include <cassert>
+#include <algorithm>
+
+#include <check.h>
+
+void eo_cxx_test_promise(TCase* tc);
+
+#endif /* _EINA_CXX_SUITE_H */
diff --git a/src/tests/eo_cxx/eo_cxx_test_promise.cc b/src/tests/eo_cxx/eo_cxx_test_promise.cc
new file mode 100644
index 0000000000..b3a2b32b31
--- /dev/null
+++ b/src/tests/eo_cxx/eo_cxx_test_promise.cc
@@ -0,0 +1,347 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <Eina.hh>
+#include <Eo.hh>
+#include <Ecore.hh>
+
+#include "eo_cxx_suite.h"
+
+START_TEST(eo_cxx_future_construct_and_destroy)
+{
+ Efl_Promise *p;
+ Efl_Future *f;
+
+ ecore_init();
+
+ {
+ p = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p);
+
+ f = efl_promise_future_get(p);
+ fail_if(!f);
+
+ efl::shared_future<int> future(efl_ref(f));
+ }
+ ecore_shutdown();
+}
+END_TEST
+
+START_TEST(eo_cxx_future_wait)
+{
+ Efl_Promise *p;
+ Efl_Future *f;
+
+ ecore_init();
+
+ p = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p);
+
+ f = efl_promise_future_get(p);
+ fail_if(!f);
+
+ {
+ efl::shared_future<int> future(efl_ref(f));
+
+ std::thread thread([&]
+ {
+ efl::ecore::main_loop_thread_safe_call_sync([]{}); // wait for ecore_main_loop_begin() call to start
+ efl::ecore::main_loop_thread_safe_call_async
+ ([&]
+ {
+ int* i = static_cast<int*>(malloc(sizeof(int)));
+ *i = 5;
+ efl_promise_value_set(p, i, & ::free);
+ });
+
+ future.wait();
+ efl::ecore::main_loop_thread_safe_call_sync([] { ecore_main_loop_quit(); });
+ });
+
+ ecore_main_loop_begin();
+
+ thread.join();
+ }
+ ecore_shutdown();
+}
+END_TEST
+
+START_TEST(eo_cxx_future_get)
+{
+ Efl_Promise *p;
+ Efl_Future *f;
+
+ ecore_init();
+
+ p = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p);
+
+ f = efl_promise_future_get(p);
+ fail_if(!f);
+
+ {
+ efl::shared_future<int> future(efl_ref(f));
+
+ std::thread thread([&]
+ {
+ efl::ecore::main_loop_thread_safe_call_sync([]{}); // wait for ecore_main_loop_begin() call to start
+ efl::ecore::main_loop_thread_safe_call_async
+ ([&]
+ {
+ int* i = static_cast<int*>(malloc(sizeof(int)));
+ *i = 5;
+ efl_promise_value_set(p, i, & ::free);
+ });
+
+ int i = future.get();
+ ck_assert_int_eq(i, 5);
+ efl::ecore::main_loop_thread_safe_call_sync([] { ecore_main_loop_quit(); });
+ });
+
+ ecore_main_loop_begin();
+
+ thread.join();
+ }
+ ecore_shutdown();
+}
+END_TEST
+
+START_TEST(eo_cxx_future_get_error)
+{
+ Efl_Promise *p;
+ Efl_Future *f;
+
+ ecore_init();
+
+ p = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p);
+
+ f = efl_promise_future_get(p);
+ fail_if(!f);
+
+ {
+ efl::shared_future<int> future(efl_ref(f));
+
+ std::thread thread([&]
+ {
+ efl::ecore::main_loop_thread_safe_call_sync([]{}); // wait for ecore_main_loop_begin() call to start
+ efl::ecore::main_loop_thread_safe_call_async
+ ([&]
+ {
+ efl_promise_failed_set(p, EINA_ERROR_OUT_OF_MEMORY);
+ });
+
+ try {
+ future.get();
+ ck_abort_msg("Execution should not have continued, exception expected");
+ }
+ catch(std::system_error const& e)
+ {
+ }
+ efl::ecore::main_loop_thread_safe_call_sync([] { ecore_main_loop_quit(); });
+ });
+
+ ecore_main_loop_begin();
+
+ thread.join();
+ }
+ ecore_shutdown();
+}
+END_TEST
+
+START_TEST(eo_cxx_future_then_value)
+{
+ Efl_Promise *promise;
+ Efl_Future *f;
+
+ ecore_init();
+
+ promise = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!promise);
+
+ f = efl_promise_future_get(promise);
+ fail_if(!f);
+
+ {
+ efl::shared_future<int> future(efl_ref(f)), rfuture;
+
+
+ std::thread thread
+ ([&]
+ {
+ efl::ecore::main_loop_thread_safe_call_sync
+ ([&]
+ {
+ rfuture = then
+ (future, [] (int i) -> int
+ {
+ ck_assert_int_eq(i, 5);
+ return 42;
+ }, [] (std::error_code)
+ {
+ throw std::bad_alloc();
+ });
+ });
+ efl::ecore::main_loop_thread_safe_call_async
+ ([&]
+ {
+ int* i = static_cast<int*>(malloc(sizeof(int)));
+ *i = 5;
+ efl_promise_value_set(promise, i, &::free);
+ });
+
+ int i = rfuture.get();
+ ck_assert_int_eq(i, 42);
+ efl::ecore::main_loop_thread_safe_call_sync([] { ecore_main_loop_quit(); });
+ });
+
+ ecore_main_loop_begin();
+ thread.join();
+ }
+ ecore_shutdown();
+}
+END_TEST
+
+START_TEST(eo_cxx_future_composite_construct_and_destroy)
+{
+ ecore_init();
+
+ {
+ Efl_Promise *p1 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p1);
+
+ Efl_Future *f1 = efl_promise_future_get(p1);
+ fail_if(!f1);
+
+ Efl_Promise *p2 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p1);
+
+ Efl_Future *f2 = efl_promise_future_get(p2);
+ fail_if(!f2);
+
+ Efl_Future *f3 = efl_future_all(f1, f2);
+ fail_if(!f3);
+
+ efl::shared_future<int> future1(efl_ref(f1))
+ , future2(efl_ref(f2));
+ efl::shared_future<int, int> future3(efl_ref(f3));
+ }
+ ecore_shutdown();
+}
+END_TEST
+
+START_TEST(eo_cxx_future_composite_wait)
+{
+ ecore_init();
+
+ {
+ Efl_Promise *p1 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p1);
+
+ Efl_Future* f1 = efl_promise_future_get(p1);
+ fail_if(!f1);
+
+ Efl_Promise *p2 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p2);
+
+ Efl_Future* f2 = efl_promise_future_get(p2);
+ fail_if(!f2);
+
+ Efl_Future *f3 = efl_future_all(f1, f2);
+ fail_if(!f3);
+
+ efl::shared_future<int> future1(efl_ref(f1))
+ , future2(efl_ref(f2));
+ efl::shared_future<int, int> future3(efl_ref(f3));
+
+ std::thread thread([&]
+ {
+ efl::ecore::main_loop_thread_safe_call_sync([]{}); // wait for ecore_main_loop_begin() call to start
+ efl::ecore::main_loop_thread_safe_call_async
+ ([&]
+ {
+ int* i1 = static_cast<int*>(malloc(sizeof(int)));
+ *i1 = 5;
+ efl_promise_value_set(p1, i1, & ::free);
+ int* i2 = static_cast<int*>(malloc(sizeof(int)));
+ *i2 = 42;
+ efl_promise_value_set(p2, i2, & ::free);
+ });
+
+ future3.wait();
+ efl::ecore::main_loop_thread_safe_call_sync([] { ecore_main_loop_quit(); });
+ });
+
+ ecore_main_loop_begin();
+
+ thread.join();
+ }
+ ecore_shutdown();
+}
+END_TEST
+
+START_TEST(eo_cxx_future_composite_get)
+{
+ ecore_init();
+
+ {
+ Efl_Promise *p1 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p1);
+
+ Efl_Future *f1 = efl_promise_future_get(p1);
+ fail_if(!f1);
+
+ Efl_Promise *p2 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p2);
+
+ Efl_Future *f2 = efl_promise_future_get(p2);
+ fail_if(!f2);
+
+ Efl_Future *f3 = efl_future_all(f1, f2);
+ fail_if(!f3);
+
+ efl::shared_future<int> future1(efl_ref(f1))
+ , future2(efl_ref(f2));
+ efl::shared_future<int, int> future3(efl_ref(f3));
+
+ std::thread thread([&]
+ {
+ efl::ecore::main_loop_thread_safe_call_sync([]{}); // wait for ecore_main_loop_begin() call to start
+ efl::ecore::main_loop_thread_safe_call_async
+ ([&]
+ {
+ int* i1 = static_cast<int*>(malloc(sizeof(int)));
+ *i1 = 5;
+ efl_promise_value_set(p1, i1, & ::free);
+ int* i2 = static_cast<int*>(malloc(sizeof(int)));
+ *i2 = 42;
+ efl_promise_value_set(p2, i2, & ::free);
+ });
+
+ std::tuple<int, int> tuple = future3.get();
+ ck_assert_int_eq(std::get<0>(tuple), 5);
+ ck_assert_int_eq(std::get<1>(tuple), 42);
+ efl::ecore::main_loop_thread_safe_call_sync([] { ecore_main_loop_quit(); });
+ });
+
+ ecore_main_loop_begin();
+
+ thread.join();
+ }
+ ecore_shutdown();
+}
+END_TEST
+
+void
+eo_cxx_test_promise(TCase* tc)
+{
+ tcase_add_test(tc, eo_cxx_future_construct_and_destroy);
+ tcase_add_test(tc, eo_cxx_future_wait);
+ tcase_add_test(tc, eo_cxx_future_get);
+ tcase_add_test(tc, eo_cxx_future_get_error);
+ tcase_add_test(tc, eo_cxx_future_then_value);
+ tcase_add_test(tc, eo_cxx_future_composite_construct_and_destroy);
+ tcase_add_test(tc, eo_cxx_future_composite_wait);
+ tcase_add_test(tc, eo_cxx_future_composite_get);
+}