ecore: add efl_future_race.
This commit is contained in:
parent
56df83e2c0
commit
0789156c86
|
@ -74,6 +74,21 @@ EAPI Efl_Future *efl_future_iterator_all(Eina_Iterator *it);
|
|||
|
||||
#define efl_future_all(...) efl_future_all_internal(__VA_ARGS__, NULL)
|
||||
|
||||
typedef struct _Efl_Future_Race_Success Efl_Future_Race_Success;
|
||||
typedef struct _Efl_Future_Composite_Progress Efl_Future_Race_Progress;
|
||||
|
||||
struct _Efl_Future_Race_Success
|
||||
{
|
||||
Efl_Future *winner;
|
||||
void *value;
|
||||
|
||||
unsigned int index;
|
||||
};
|
||||
|
||||
EAPI Efl_Future *efl_future_race_internal(Efl_Future *f1, ...);
|
||||
|
||||
#define efl_future_race(...) efl_future_race_internal(__VA_ARGS__, NULL)
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
@ -588,10 +588,12 @@ _efl_promise_efl_object_destructor(Eo *obj, Efl_Promise_Data *pd)
|
|||
efl_destructor(efl_super(obj, EFL_PROMISE_CLASS));
|
||||
}
|
||||
|
||||
typedef struct _Efl_Promise_All Efl_Promise_All;
|
||||
typedef struct _Efl_Promise_Composite Efl_Promise_All;
|
||||
typedef struct _Efl_Future_All Efl_Future_All;
|
||||
typedef struct _Efl_Accessor_All Efl_Accessor_All;
|
||||
|
||||
typedef struct _Efl_Promise_Composite Efl_Promise_Race;
|
||||
|
||||
struct _Efl_Accessor_All
|
||||
{
|
||||
Eina_Accessor accessor;
|
||||
|
@ -607,17 +609,34 @@ struct _Efl_Future_All
|
|||
Efl_Promise_Msg *d;
|
||||
};
|
||||
|
||||
struct _Efl_Promise_All
|
||||
struct _Efl_Promise_Composite
|
||||
{
|
||||
Eina_Array members;
|
||||
|
||||
Efl_Promise *promise;
|
||||
|
||||
Efl_Future *(*future_get)(void *item);
|
||||
|
||||
Eina_Bool failed : 1;
|
||||
Eina_Bool progress_triggered : 1;
|
||||
Eina_Bool future_triggered : 1;
|
||||
Eina_Bool done : 1;
|
||||
};
|
||||
|
||||
static Efl_Future *
|
||||
_efl_promise_all_future_get(void *item)
|
||||
{
|
||||
Efl_Future_All *fa = item;
|
||||
|
||||
return fa->f;
|
||||
}
|
||||
|
||||
static Efl_Future *
|
||||
_efl_promise_race_future_get(void *item)
|
||||
{
|
||||
return item;
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_promise_all_free(Efl_Promise_All *all)
|
||||
{
|
||||
|
@ -643,10 +662,19 @@ _efl_promise_all_die(void *data, const Efl_Event *ev EINA_UNUSED)
|
|||
}
|
||||
|
||||
static void
|
||||
_efl_all_future_set(void *data, const Eo_Event *ev EINA_UNUSED)
|
||||
_efl_promise_race_die(void *data, const Efl_Event *ev EINA_UNUSED)
|
||||
{
|
||||
Efl_Promise_All *all = data;
|
||||
Efl_Future_All *fa;
|
||||
|
||||
eina_array_flush(&all->members);
|
||||
free(all);
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_future_set(void *data, const Efl_Event *ev EINA_UNUSED)
|
||||
{
|
||||
Efl_Promise_All *all = data;
|
||||
void *item;
|
||||
Eina_Array_Iterator iterator;
|
||||
unsigned int i;
|
||||
|
||||
|
@ -654,15 +682,17 @@ _efl_all_future_set(void *data, const Eo_Event *ev EINA_UNUSED)
|
|||
all->future_triggered = EINA_TRUE;
|
||||
|
||||
// Propagate set on demand
|
||||
EINA_ARRAY_ITER_NEXT(&all->members, i, fa, iterator)
|
||||
EINA_ARRAY_ITER_NEXT(&all->members, i, item, iterator)
|
||||
{
|
||||
if (fa->f)
|
||||
Efl_Future *f = all->future_get(item);
|
||||
|
||||
if (f)
|
||||
{
|
||||
Efl_Loop_Future_Data *pd = efl_data_scope_get(fa->f, EFL_LOOP_FUTURE_CLASS);
|
||||
Efl_Loop_Future_Data *pd = efl_data_scope_get(f, EFL_LOOP_FUTURE_CLASS);
|
||||
|
||||
if (!pd->promise->set.future && !pd->promise->set.future_triggered)
|
||||
{
|
||||
efl_event_callback_call(pd->promise->promise, EFL_PROMISE_EVENT_FUTURE_SET, fa->f);
|
||||
efl_event_callback_call(pd->promise->promise, EFL_PROMISE_EVENT_FUTURE_SET, f);
|
||||
pd->promise->set.future_triggered = EINA_TRUE;
|
||||
pd->promise->set.future = EINA_TRUE;
|
||||
}
|
||||
|
@ -671,10 +701,10 @@ _efl_all_future_set(void *data, const Eo_Event *ev EINA_UNUSED)
|
|||
}
|
||||
|
||||
static void
|
||||
_efl_all_future_progress_set(void *data, const Eo_Event *ev EINA_UNUSED)
|
||||
_efl_future_progress_set(void *data, const Efl_Event *ev EINA_UNUSED)
|
||||
{
|
||||
Efl_Promise_All *all = data;
|
||||
Efl_Future_All *fa;
|
||||
void *item;
|
||||
Eina_Array_Iterator iterator;
|
||||
unsigned int i;
|
||||
|
||||
|
@ -682,15 +712,17 @@ _efl_all_future_progress_set(void *data, const Eo_Event *ev EINA_UNUSED)
|
|||
all->progress_triggered = 1;
|
||||
|
||||
// Propagate progress set
|
||||
EINA_ARRAY_ITER_NEXT(&all->members, i, fa, iterator)
|
||||
EINA_ARRAY_ITER_NEXT(&all->members, i, item, iterator)
|
||||
{
|
||||
if (fa->f)
|
||||
Efl_Future *f = all->future_get(item);
|
||||
|
||||
if (f)
|
||||
{
|
||||
Efl_Loop_Future_Data *pd = efl_data_scope_get(fa->f, EFL_LOOP_FUTURE_CLASS);
|
||||
Efl_Loop_Future_Data *pd = efl_data_scope_get(f, EFL_LOOP_FUTURE_CLASS);
|
||||
|
||||
if (!pd->promise->set.progress && !pd->promise->set.progress_triggered)
|
||||
{
|
||||
efl_event_callback_call(pd->promise->promise, EFL_PROMISE_EVENT_FUTURE_PROGRESS_SET, fa->f);
|
||||
efl_event_callback_call(pd->promise->promise, EFL_PROMISE_EVENT_FUTURE_PROGRESS_SET, f);
|
||||
pd->promise->set.progress_triggered = EINA_TRUE;
|
||||
pd->promise->set.progress = EINA_TRUE;
|
||||
}
|
||||
|
@ -712,7 +744,28 @@ _efl_all_future_none(void *data, const Efl_Event *ev EINA_UNUSED)
|
|||
// Trigger cancel on all future
|
||||
EINA_ARRAY_ITER_NEXT(&all->members, i, fa, iterator)
|
||||
{
|
||||
if (!fa->d) efl_future_cancel(fa->f);
|
||||
if (!fa->d && fa->f) efl_future_cancel(fa->f);
|
||||
}
|
||||
|
||||
// No one is listening to this promise anyway
|
||||
_efl_promise_all_free(all);
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_race_future_none(void *data, const Efl_Event *ev EINA_UNUSED)
|
||||
{
|
||||
Efl_Promise_Race *all = data;
|
||||
Efl_Future *f;
|
||||
Eina_Array_Iterator iterator;
|
||||
unsigned int i;
|
||||
|
||||
if (all->failed) return ;
|
||||
all->failed = EINA_TRUE;
|
||||
|
||||
// Trigger cancel on all future
|
||||
EINA_ARRAY_ITER_NEXT(&all->members, i, f, iterator)
|
||||
{
|
||||
if (!f) efl_future_cancel(f);
|
||||
}
|
||||
|
||||
// No one is listening to this promise anyway
|
||||
|
@ -828,29 +881,28 @@ _progress(void *data, const Efl_Event *ev)
|
|||
{
|
||||
Efl_Promise_All *all = data;
|
||||
Efl_Future_Event_Progress *p = ev->info;
|
||||
Efl_Future_All *fa;
|
||||
void *item;
|
||||
Efl_Future_All_Progress a;
|
||||
Eina_Array_Iterator iterator;
|
||||
unsigned int i;
|
||||
|
||||
a.inprogress = ev->object;
|
||||
a.progress = p->progress;
|
||||
a.index = 0;
|
||||
|
||||
EINA_ARRAY_ITER_NEXT(&all->members, i, fa, iterator)
|
||||
EINA_ARRAY_ITER_NEXT(&all->members, i, item, iterator)
|
||||
{
|
||||
if (fa->f == a.inprogress)
|
||||
{
|
||||
break ;
|
||||
}
|
||||
a.index++;
|
||||
Efl_Future *f = all->future_get(item);
|
||||
|
||||
if (f == a.inprogress) break ;
|
||||
}
|
||||
a.index = i;
|
||||
|
||||
efl_promise_progress_set(all->promise, &a);
|
||||
}
|
||||
|
||||
EFL_CALLBACKS_ARRAY_DEFINE(efl_all_callbacks,
|
||||
{ EFL_PROMISE_EVENT_FUTURE_SET, _efl_all_future_set },
|
||||
{ EFL_PROMISE_EVENT_FUTURE_PROGRESS_SET, _efl_all_future_progress_set },
|
||||
{ EFL_PROMISE_EVENT_FUTURE_SET, _efl_future_set },
|
||||
{ EFL_PROMISE_EVENT_FUTURE_PROGRESS_SET, _efl_future_progress_set },
|
||||
{ EFL_PROMISE_EVENT_FUTURE_NONE, _efl_all_future_none },
|
||||
{ EFL_EVENT_DEL, _efl_promise_all_die });
|
||||
|
||||
|
@ -964,4 +1016,147 @@ efl_future_iterator_all(Eina_Iterator *it)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
_then_race(void *data, const Efl_Event *ev)
|
||||
{
|
||||
Efl_Future_Event_Success *success = ev->info;
|
||||
Efl_Promise_Race *race = data;
|
||||
// This is a trick due to the fact we are using internal function call to register this functions
|
||||
Efl_Promise_Msg *d = success->value;
|
||||
Efl_Future *f;
|
||||
Eina_Array_Iterator iterator;
|
||||
unsigned int i;
|
||||
|
||||
if (race->done) return ;
|
||||
race->done = EINA_TRUE;
|
||||
|
||||
efl_ref(race->promise);
|
||||
|
||||
EINA_ARRAY_ITER_NEXT(&race->members, i, f, iterator)
|
||||
{
|
||||
// To avoid double cancel/success
|
||||
eina_array_data_set(&race->members, i, NULL);
|
||||
|
||||
if (f == ev->object)
|
||||
{
|
||||
Efl_Future_Race_Success *success = calloc(1, sizeof (Efl_Future_Race_Success));
|
||||
|
||||
if (!success) continue ;
|
||||
success->winner = f;
|
||||
success->value = d->value;
|
||||
success->index = i;
|
||||
|
||||
efl_promise_value_set(race->promise, success, free);
|
||||
}
|
||||
else
|
||||
{
|
||||
efl_future_cancel(f);
|
||||
}
|
||||
}
|
||||
|
||||
_efl_promise_all_free(race);
|
||||
efl_unref(race->promise);
|
||||
}
|
||||
|
||||
static void
|
||||
_fail_race(void *data, const Efl_Event *ev)
|
||||
{
|
||||
Efl_Future_Event_Failure *fail = ev->info;
|
||||
Efl_Promise_Race *race = data;
|
||||
Efl_Future *f;
|
||||
Eina_Array_Iterator iterator;
|
||||
unsigned int i;
|
||||
|
||||
if (race->done) return ;
|
||||
race->done = EINA_TRUE;
|
||||
|
||||
efl_ref(race->promise);
|
||||
|
||||
EINA_ARRAY_ITER_NEXT(&race->members, i, f, iterator)
|
||||
{
|
||||
// To avoid double cancel/success
|
||||
eina_array_data_set(&race->members, i, NULL);
|
||||
|
||||
if (f != ev->object)
|
||||
{
|
||||
efl_future_cancel(f);
|
||||
}
|
||||
}
|
||||
|
||||
efl_promise_failed(race->promise, fail->error);
|
||||
_efl_promise_all_free(race);
|
||||
efl_unref(race->promise);
|
||||
}
|
||||
|
||||
EFL_CALLBACKS_ARRAY_DEFINE(efl_race_callbacks,
|
||||
{ EFL_PROMISE_EVENT_FUTURE_SET, _efl_future_set },
|
||||
{ EFL_PROMISE_EVENT_FUTURE_PROGRESS_SET, _efl_future_progress_set },
|
||||
{ EFL_PROMISE_EVENT_FUTURE_NONE, _efl_race_future_none },
|
||||
{ EFL_EVENT_DEL, _efl_promise_race_die });
|
||||
|
||||
static Efl_Promise_Race *
|
||||
_efl_future_race_new(Eo *provider)
|
||||
{
|
||||
Efl_Promise_Race *race;
|
||||
Eo *loop;
|
||||
|
||||
loop = efl_provider_find(provider, EFL_LOOP_CLASS);
|
||||
if (!loop) return NULL;
|
||||
|
||||
race = calloc(1, sizeof (Efl_Promise_Race));
|
||||
if (!race) return NULL;
|
||||
|
||||
eina_array_step_set(&race->members, sizeof (Eina_Array), 8);
|
||||
race->future_get = _efl_promise_race_future_get;
|
||||
race->promise = efl_add(EFL_PROMISE_CLASS, loop);
|
||||
if (!race->promise) goto on_error;
|
||||
|
||||
return race;
|
||||
|
||||
on_error:
|
||||
free(race);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline Efl_Future *
|
||||
_efl_future_race_done(Efl_Promise_Race *race)
|
||||
{
|
||||
Efl_Future *fn;
|
||||
Eina_Array_Iterator iterator;
|
||||
unsigned int i;
|
||||
|
||||
EINA_ARRAY_ITER_NEXT(&race->members, i, fn, iterator)
|
||||
_efl_loop_future_internal_then(fn, _then_race, _fail_race, _progress, race);
|
||||
|
||||
efl_event_callback_array_add(race->promise, efl_race_callbacks(), race);
|
||||
|
||||
return efl_promise_future_get(race->promise);
|
||||
}
|
||||
|
||||
EAPI Efl_Future *
|
||||
efl_future_race_internal(Efl_Future *f1, ...)
|
||||
{
|
||||
Efl_Promise_Race *race;
|
||||
Efl_Future *fn;
|
||||
va_list args;
|
||||
|
||||
if (!f1) return NULL;
|
||||
|
||||
race = _efl_future_race_new(f1);
|
||||
if (!race) return NULL;
|
||||
|
||||
eina_array_push(&race->members, f1);
|
||||
|
||||
va_start(args, f1);
|
||||
|
||||
while ((fn = va_arg(args, Efl_Future *)))
|
||||
{
|
||||
eina_array_push(&race->members, fn);
|
||||
}
|
||||
|
||||
|
||||
|
||||
return _efl_future_race_done(race);
|
||||
}
|
||||
|
||||
#include "efl_promise.eo.c"
|
||||
|
|
Loading…
Reference in New Issue