summaryrefslogtreecommitdiff
path: root/src/bindings
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 /src/bindings
parent98229bc5d6cf1ebe11af4bb05a32f2a30b470f6e (diff)
downloadefl-a63cfcafc7f8524dfad4e1bba763fb17c69d50e1.tar.gz
eolian-cxx: Implement future template class for C++
Diffstat (limited to 'src/bindings')
-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
7 files changed, 664 insertions, 173 deletions
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