summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelipe Magno de Almeida <felipe@expertisesolutions.com.br>2016-05-09 19:10:26 -0300
committerFelipe Magno de Almeida <felipe@expertisesolutions.com.br>2016-05-09 19:10:26 -0300
commit1c5ce165658820643511ff784d0c210969173a45 (patch)
treecc21e8054f327c184675c9f1cfbfe91d68fa7f42
parentd734cd4cada136add5d66e126c659223897fe487 (diff)
eina: Add eina_promise_race composition function
Added eina_promise_race function that composes multiple promise objects into a new promise which is fulfilled when one of the promises are fulfilled, or fails when one of the promises have failed.
-rw-r--r--src/lib/eina/eina_promise.c103
-rw-r--r--src/lib/eina/eina_promise.h18
-rw-r--r--src/tests/eina/eina_test_promise.c23
3 files changed, 143 insertions, 1 deletions
diff --git a/src/lib/eina/eina_promise.c b/src/lib/eina/eina_promise.c
index 2fe19a4bc1..93e70948e5 100644
--- a/src/lib/eina/eina_promise.c
+++ b/src/lib/eina/eina_promise.c
@@ -104,6 +104,19 @@ struct _Eina_Promise_Iterator
104 } data; 104 } data;
105}; 105};
106 106
107typedef struct _Eina_Promise_Race_Value_Type _Eina_Promise_Race_Value_Type;
108struct _Eina_Promise_Race_Value_Type
109{
110 void* value;
111 unsigned int promise_index;
112 unsigned int num_promises;
113 struct _Eina_Promise_Race_Information
114 {
115 Eina_Promise* promise;
116 _Eina_Promise_Default_Owner* self;
117 } promises[];
118};
119
107static void _eina_promise_free_progress_callback_node(void* node) 120static void _eina_promise_free_progress_callback_node(void* node)
108{ 121{
109 _Eina_Promise_Progress_Cb *progress_cb = node; 122 _Eina_Promise_Progress_Cb *progress_cb = node;
@@ -669,6 +682,96 @@ eina_promise_progress_notification(Eina_Promise_Owner* promise)
669 return eina_promise_owner_promise_get(owner); 682 return eina_promise_owner_promise_get(owner);
670} 683}
671 684
685// Race implementation
686static void
687_eina_promise_race_free(_Eina_Promise_Race_Value_Type* value)
688{
689 unsigned i = 0;
690 for (;i != value->num_promises; ++i)
691 {
692 eina_promise_unref(value->promises[i].promise);
693 }
694}
695
696static void
697_eina_promise_race_compose_then_cb(struct _Eina_Promise_Race_Information* info, void* value EINA_UNUSED)
698{
699 _Eina_Promise_Default_Owner* race_promise;
700 _Eina_Promise_Race_Value_Type *race_value;
701
702 race_promise = info->self;
703 race_value = (_Eina_Promise_Race_Value_Type*)race_promise->value;
704
705 if (!race_promise->promise.has_finished)
706 {
707 race_value->value = value;
708 race_value->promise_index = info - &race_value->promises[0];
709 _eina_promise_finish(race_promise);
710 }
711}
712
713static void
714_eina_promise_race_compose_error_then_cb(struct _Eina_Promise_Race_Information* info, Eina_Error const* error)
715{
716 _Eina_Promise_Default_Owner* race_promise;
717 _Eina_Promise_Race_Value_Type *race_value;
718
719 race_promise = info->self;
720 race_value = (_Eina_Promise_Race_Value_Type*)race_promise->value;
721
722 if (!race_promise->promise.has_finished)
723 {
724 race_value->promise_index = info - &race_value->promises[0];
725 eina_promise_owner_error_set(&race_promise->owner_vtable, *error);
726 }
727}
728
729Eina_Promise *
730eina_promise_race(Eina_Iterator* it)
731{
732 _Eina_Promise_Default_Owner *promise;
733 Eina_Promise* current;
734 Eina_Array* promises;
735 struct _Eina_Promise_Race_Information *cur_promise, *last;
736 _Eina_Promise_Race_Value_Type *value;
737 int num_promises;
738
739 promises = eina_array_new(20);
740
741 EINA_ITERATOR_FOREACH(it, current)
742 {
743 eina_array_push(promises, current);
744 }
745
746 eina_iterator_free(it);
747
748 num_promises = eina_array_count_get(promises);
749 promise = (_Eina_Promise_Default_Owner*)
750 eina_promise_default_add(sizeof(_Eina_Promise_Race_Value_Type) +
751 sizeof(struct _Eina_Promise_Race_Information*)*num_promises);
752 value = eina_promise_owner_buffer_get((Eina_Promise_Owner*)promise);
753 value->value = NULL;
754 value->promise_index = -1;
755 value->num_promises = num_promises;
756
757 promise->promise.value_free_cb = (Eina_Promise_Free_Cb)&_eina_promise_race_free;
758
759 cur_promise = value->promises;
760 last = value->promises + value->num_promises;
761 for (int i = 0;cur_promise != last; ++cur_promise, ++i)
762 {
763 cur_promise->promise = eina_array_data_get(promises, i);
764 cur_promise->self = promise;
765 eina_promise_then(cur_promise->promise, (Eina_Promise_Cb)&_eina_promise_race_compose_then_cb,
766 (Eina_Promise_Error_Cb)&_eina_promise_race_compose_error_then_cb, cur_promise);
767 eina_promise_ref(cur_promise->promise); // We need to keep the value alive until this promise is freed
768 }
769
770 eina_array_free(promises);
771
772 return &promise->promise.vtable;
773}
774
672// API functions 775// API functions
673EAPI void 776EAPI void
674eina_promise_then(Eina_Promise* promise, Eina_Promise_Cb callback, 777eina_promise_then(Eina_Promise* promise, Eina_Promise_Cb callback,
diff --git a/src/lib/eina/eina_promise.h b/src/lib/eina/eina_promise.h
index 51bdb80884..916d6eab7d 100644
--- a/src/lib/eina/eina_promise.h
+++ b/src/lib/eina/eina_promise.h
@@ -224,7 +224,11 @@ EAPI void eina_promise_then(Eina_Promise* promise, Eina_Promise_Cb callback,
224 Eina_Promise_Error_Cb error_cb, void* data); 224 Eina_Promise_Error_Cb error_cb, void* data);
225 225
226/* 226/*
227 * @brief Creates a new Eina_Promise from other Eina_Promises 227 * @brief Creates a new @Eina_Promise from other @Eina_Promise's
228 *
229 * The new @Eina_Promise is fulfilled when all promises
230 * have also been fulfilled with success or when the
231 * first one fails
228 * 232 *
229 * @param promises An Eina_Iterator for all Eina_Promises 233 * @param promises An Eina_Iterator for all Eina_Promises
230 * @return Returns a new Eina_Promise 234 * @return Returns a new Eina_Promise
@@ -232,6 +236,18 @@ EAPI void eina_promise_then(Eina_Promise* promise, Eina_Promise_Cb callback,
232EAPI Eina_Promise* eina_promise_all(Eina_Iterator* promises); 236EAPI Eina_Promise* eina_promise_all(Eina_Iterator* promises);
233 237
234/* 238/*
239 * @brief Creates a new @Eina_Promise from other @Eina_Promises
240 *
241 * The new @Eina_Promise is fulfilled when the first promise
242 * has been fulfilled with success or when the
243 * first one fails
244 *
245 * @param promises An Eina_Iterator for all Eina_Promises
246 * @return Returns a new Eina_Promise
247 */
248EAPI Eina_Promise* eina_promise_race(Eina_Iterator* promises);
249
250/*
235 * @brief Creates a new @Eina_Promise from another @Eina_Promise_Owner which 251 * @brief Creates a new @Eina_Promise from another @Eina_Promise_Owner which
236 * is fulfilled when @promise has a progress callback registered 252 * is fulfilled when @promise has a progress callback registered
237 * 253 *
diff --git a/src/tests/eina/eina_test_promise.c b/src/tests/eina/eina_test_promise.c
index 59199e1420..2932e1c792 100644
--- a/src/tests/eina/eina_test_promise.c
+++ b/src/tests/eina/eina_test_promise.c
@@ -336,6 +336,28 @@ START_TEST(eina_test_promise_ignored)
336} 336}
337END_TEST 337END_TEST
338 338
339START_TEST(eina_test_promise_race)
340{
341 Eina_Promise_Owner* promise_owner;
342 Eina_Promise* first[2] = {NULL, NULL};
343 Eina_Promise* promise;
344 Eina_Bool ran = EINA_FALSE;
345
346 eina_init();
347
348 promise_owner = eina_promise_default_add(0);
349 first[0] = eina_promise_owner_promise_get(promise_owner);
350 promise = eina_promise_race(eina_carray_iterator_new((void**)&first[0]));
351
352 eina_promise_then(promise, &_eina_test_promise_cb, NULL, &ran);
353 eina_promise_owner_value_set(promise_owner, NULL, NULL);
354
355 ck_assert(ran == EINA_TRUE);
356
357 eina_shutdown();
358}
359END_TEST
360
339void 361void
340eina_test_promise(TCase *tc) 362eina_test_promise(TCase *tc)
341{ 363{
@@ -350,4 +372,5 @@ eina_test_promise(TCase *tc)
350 tcase_add_test(tc, eina_test_promise_progress_notify2); 372 tcase_add_test(tc, eina_test_promise_progress_notify2);
351 tcase_add_test(tc, eina_test_promise_progress_notify3); 373 tcase_add_test(tc, eina_test_promise_progress_notify3);
352 tcase_add_test(tc, eina_test_promise_ignored); 374 tcase_add_test(tc, eina_test_promise_ignored);
375 tcase_add_test(tc, eina_test_promise_race);
353} 376}