Efl_Loop: add job, timeout and idle based on Eina_Future.
authorGustavo Sverzut Barbieri <barbieri@profusion.mobi>
Sat, 26 Aug 2017 22:59:39 +0000 (19:59 -0300)
committerGuilherme Iscaro <iscaro@profusion.mobi>
Mon, 4 Sep 2017 13:24:00 +0000 (10:24 -0300)
Since some clash with old version, then add Eina_FutureXXX to their
name, later we'll sed.

src/lib/ecore/ecore_alloc.c
src/lib/ecore/ecore_main.c
src/lib/ecore/ecore_private.h
src/lib/ecore/efl_loop.eo
src/tests/ecore/ecore_test_promise2.c

index bec66ef..3196b82 100644 (file)
@@ -44,6 +44,7 @@ GENERIC_ALLOC_FREE(Ecore_Event, ecore_event);
 //GENERIC_ALLOC_FREE(Ecore_Poller, ecore_poller);
 GENERIC_ALLOC_FREE(Ecore_Pipe, ecore_pipe);
 GENERIC_ALLOC_FREE(Ecore_Fd_Handler, ecore_fd_handler);
+GENERIC_ALLOC_FREE(Efl_Loop_Promise_Simple_Data, efl_loop_promise_simple_data);
 #ifdef _WIN32
 GENERIC_ALLOC_FREE(Ecore_Win32_Handler, ecore_win32_handler);
 #endif
@@ -61,6 +62,7 @@ static Ecore_Mempool *mempool_array[] = {
 //  &ecore_poller_mp,
   &ecore_pipe_mp,
   &ecore_fd_handler_mp,
+  &efl_loop_promise_simple_data_mp,
 #ifdef _WIN32
   &ecore_win32_handler_mp
 #endif
@@ -87,6 +89,7 @@ ecore_mempool_init(void)
 //   MP_SIZE_INIT(Ecore_Poller, ecore_poller);
    MP_SIZE_INIT(Ecore_Pipe, ecore_pipe);
    MP_SIZE_INIT(Ecore_Fd_Handler, ecore_fd_handler);
+   MP_SIZE_INIT(Efl_Loop_Promise_Simple_Data, efl_loop_promise_simple_data);
 #ifdef _WIN32
    MP_SIZE_INIT(Ecore_Win32_Handler, ecore_win32_handler);
 #endif
index 0bb15e0..6819a05 100644 (file)
@@ -233,6 +233,15 @@ struct _Ecore_Fd_Handler
 };
 GENERIC_ALLOC_SIZE_DECLARE(Ecore_Fd_Handler);
 
+typedef struct _Efl_Loop_Promise_Simple_Data {
+   union {
+      Ecore_Timer *timer;
+      Ecore_Idler *idler;
+   };
+   Eina_Promise *promise;
+} Efl_Loop_Promise_Simple_Data;
+GENERIC_ALLOC_SIZE_DECLARE(Efl_Loop_Promise_Simple_Data);
+
 #ifdef _WIN32
 struct _Ecore_Win32_Handler
 {
@@ -3112,6 +3121,101 @@ EFL_CALLBACKS_ARRAY_DEFINE(timeout,
                           { EFL_LOOP_TIMER_EVENT_TICK, _efl_loop_timeout_cb },
                           { EFL_EVENT_DEL, _efl_loop_timeout_force_cancel_cb });
 
+static Eina_Future *
+_efl_loop_Eina_FutureXXX_job(Eo *obj, Efl_Loop_Data *pd EINA_UNUSED)
+{
+   // NOTE: Eolian should do efl_future_then() to bind future to object.
+   return efl_future_Eina_FutureXXX_then(obj,
+      eina_future_resolved(efl_loop_future_scheduler_get(obj),
+                           EINA_VALUE_EMPTY));
+}
+
+static void
+_efl_loop_Eina_FutureXXX_idle_cancel(void *data, const Eina_Promise *dead_ptr EINA_UNUSED)
+{
+   Efl_Loop_Promise_Simple_Data *d = data;
+   ecore_idler_del(d->idler);
+   efl_loop_promise_simple_data_mp_free(d);
+}
+
+static Eina_Bool
+_efl_loop_Eina_FutureXXX_idle_done(void *data)
+{
+   Efl_Loop_Promise_Simple_Data *d = data;
+   eina_promise_resolve(d->promise, EINA_VALUE_EMPTY);
+   efl_loop_promise_simple_data_mp_free(d);
+   return EINA_FALSE;
+}
+
+static Eina_Future *
+_efl_loop_Eina_FutureXXX_idle(Eo *obj, Efl_Loop_Data *pd EINA_UNUSED)
+{
+   Efl_Loop_Promise_Simple_Data *d;
+   Eina_Promise *p;
+
+   d = efl_loop_promise_simple_data_calloc(1);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(d, NULL);
+
+   d->idler = ecore_idler_add(_efl_loop_Eina_FutureXXX_idle_done, d);
+   EINA_SAFETY_ON_NULL_GOTO(d->idler, idler_error);
+
+   p = eina_promise_new(efl_loop_future_scheduler_get(obj),
+                        _efl_loop_Eina_FutureXXX_idle_cancel, d);
+   // d is dead if p is NULL
+   EINA_SAFETY_ON_NULL_RETURN_VAL(p, NULL);
+   d->promise = p;
+
+   // NOTE: Eolian should do efl_future_then() to bind future to object.
+   return efl_future_Eina_FutureXXX_then(obj, eina_future_new(p));
+
+ idler_error:
+   efl_loop_promise_simple_data_mp_free(d);
+   return NULL;
+}
+
+static void
+_efl_loop_Eina_FutureXXX_timeout_cancel(void *data, const Eina_Promise *dead_ptr EINA_UNUSED)
+{
+   Efl_Loop_Promise_Simple_Data *d = data;
+   ecore_timer_del(d->timer);
+   efl_loop_promise_simple_data_mp_free(d);
+}
+
+static Eina_Bool
+_efl_loop_Eina_FutureXXX_timeout_done(void *data)
+{
+   Efl_Loop_Promise_Simple_Data *d = data;
+   eina_promise_resolve(d->promise, EINA_VALUE_EMPTY);
+   efl_loop_promise_simple_data_mp_free(d);
+   return EINA_FALSE;
+}
+
+static Eina_Future *
+_efl_loop_Eina_FutureXXX_timeout(Eo *obj, Efl_Loop_Data *pd EINA_UNUSED, double time)
+{
+   Efl_Loop_Promise_Simple_Data *d;
+   Eina_Promise *p;
+
+   d = efl_loop_promise_simple_data_calloc(1);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(d, NULL);
+
+   d->timer = ecore_timer_add(time, _efl_loop_Eina_FutureXXX_timeout_done, d);
+   EINA_SAFETY_ON_NULL_GOTO(d->timer, timer_error);
+
+   p = eina_promise_new(efl_loop_future_scheduler_get(obj),
+                        _efl_loop_Eina_FutureXXX_timeout_cancel, d);
+   // d is dead if p is NULL
+   EINA_SAFETY_ON_NULL_RETURN_VAL(p, NULL);
+   d->promise = p;
+
+   // NOTE: Eolian should do efl_future_then() to bind future to object.
+   return efl_future_Eina_FutureXXX_then(obj, eina_future_new(p));
+
+ timer_error:
+   efl_loop_promise_simple_data_mp_free(d);
+   return NULL;
+}
+
 /* This event will be triggered when the main loop is destroyed and destroy its timers along */
 static void _efl_loop_internal_cancel(Efl_Internal_Promise *p);
 
index 6437b41..366c169 100644 (file)
@@ -81,6 +81,8 @@ extern int _ecore_log_dom;
 
 typedef struct _Ecore_Factorized_Idle Ecore_Factorized_Idle;
 
+typedef struct _Efl_Loop_Promise_Simple_Data Efl_Loop_Promise_Simple_Data;
+
 typedef struct _Efl_Loop_Data Efl_Loop_Data;
 struct _Efl_Loop_Data
 {
@@ -371,6 +373,7 @@ GENERIC_ALLOC_FREE_HEADER(Ecore_Event, ecore_event);
 //GENERIC_ALLOC_FREE_HEADER(Ecore_Poller, ecore_poller);
 GENERIC_ALLOC_FREE_HEADER(Ecore_Pipe, ecore_pipe);
 GENERIC_ALLOC_FREE_HEADER(Ecore_Fd_Handler, ecore_fd_handler);
+GENERIC_ALLOC_FREE_HEADER(Efl_Loop_Promise_Simple_Data, efl_loop_promise_simple_data);
 #ifdef _WIN32
 GENERIC_ALLOC_FREE_HEADER(Ecore_Win32_Handler, ecore_win32_handler);
 #endif
index e34deb5..a5610c2 100644 (file)
@@ -82,6 +82,31 @@ class Efl.Loop (Efl.Object)
              scheduler: ptr(Eina.Future.Scheduler); [[The scheduler.]]
          }
       }
+      Eina_FutureXXX_job {
+         [[A future promise that will be resolved from a clean main
+           loop context as soon as possible.
+
+           This has higher priority, for low priority use
+           @.Eina_FutureXXX_idle
+         ]]
+          return: own(ptr(Eina.Future)) /* TODO: future<void> */; [[The future handle.]]
+      }
+      Eina_FutureXXX_idle {
+         [[A future promise that will be resolved from a clean main
+           loop context as soon as the main loop is idle.
+
+           This is a low priority version of @.Eina_FutureXXX_job
+         ]]
+          return: own(ptr(Eina.Future)) /* TODO: future<void> */; [[The future handle.]]
+      }
+      Eina_FutureXXX_timeout {
+         [[A future promise that will be resolved from a clean main
+           loop context after $time seconds.]]
+         params {
+            @in time: double; [[The time from now in second that the main loop will wait before triggering it.]]
+         }
+         return: own(ptr(Eina.Future)) /* future<void> */; [[The future handle.]]
+      }
       job {
          [[Will execute that promise in the near future.]]
          params {
index ea8d0d2..c23c5d1 100644 (file)
@@ -472,6 +472,67 @@ _race_end_cb(void *data, const Eina_Value v, const Eina_Future *dead EINA_UNUSED
    return v;
 }
 
+static Eina_Value
+_promise_empty_done(void *data, const Eina_Value value, const Eina_Future *dead_future EINA_UNUSED)
+{
+   Eina_Bool *pdone = data;
+
+   if (!value.type) *pdone = EINA_TRUE;
+
+   ecore_main_loop_quit();
+
+   return value;
+}
+
+START_TEST(efl_test_timeout)
+{
+   Eina_Future *f;
+   Eina_Bool done = EINA_FALSE;
+
+   fail_if(!ecore_init());
+   f = eina_future_then(efl_loop_Eina_FutureXXX_timeout(ecore_main_loop_get(), 0.0001),
+                        _promise_empty_done, &done);
+   fail_if(!f);
+   ecore_main_loop_begin();
+   ecore_shutdown();
+
+   fail_unless(done);
+}
+END_TEST
+
+START_TEST(efl_test_job)
+{
+   Eina_Future *f;
+   Eina_Bool done = EINA_FALSE;
+
+   fail_if(!ecore_init());
+   f = eina_future_then(efl_loop_Eina_FutureXXX_job(ecore_main_loop_get()),
+                        _promise_empty_done, &done);
+   fail_if(!f);
+   ecore_main_loop_begin();
+   ecore_shutdown();
+
+   fail_unless(done);
+}
+END_TEST
+
+START_TEST(efl_test_idle)
+{
+   Eina_Future *f;
+   Eina_Bool done = EINA_FALSE;
+
+   fail_if(!ecore_init());
+   f = eina_future_then(efl_loop_Eina_FutureXXX_idle(ecore_main_loop_get()),
+                        _promise_empty_done, &done);
+   fail_if(!f);
+   ecore_main_loop_begin();
+   ecore_shutdown();
+
+   fail_unless(done);
+}
+END_TEST
+
+
 START_TEST(efl_test_promise_future_success)
 {
    Eina_Future *f;
@@ -1258,6 +1319,9 @@ END_TEST
 
 void ecore_test_ecore_promise2(TCase *tc)
 {
+   tcase_add_test(tc, efl_test_timeout);
+   tcase_add_test(tc, efl_test_job);
+   tcase_add_test(tc, efl_test_idle);
    tcase_add_test(tc, efl_test_promise_future_success);
    tcase_add_test(tc, efl_test_promise_future_failure);
    tcase_add_test(tc, efl_test_promise_future_chain_no_error);