diff options
author | Felipe Magno de Almeida <felipe@expertisesolutions.com.br> | 2016-05-09 19:10:26 -0300 |
---|---|---|
committer | Felipe Magno de Almeida <felipe@expertisesolutions.com.br> | 2016-05-09 19:10:26 -0300 |
commit | 1c5ce165658820643511ff784d0c210969173a45 (patch) | |
tree | cc21e8054f327c184675c9f1cfbfe91d68fa7f42 | |
parent | d734cd4cada136add5d66e126c659223897fe487 (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.c | 103 | ||||
-rw-r--r-- | src/lib/eina/eina_promise.h | 18 | ||||
-rw-r--r-- | src/tests/eina/eina_test_promise.c | 23 |
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 | ||
107 | typedef struct _Eina_Promise_Race_Value_Type _Eina_Promise_Race_Value_Type; | ||
108 | struct _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 | |||
107 | static void _eina_promise_free_progress_callback_node(void* node) | 120 | static 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 | ||
686 | static 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 | |||
696 | static 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 | |||
713 | static 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 | |||
729 | Eina_Promise * | ||
730 | eina_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 |
673 | EAPI void | 776 | EAPI void |
674 | eina_promise_then(Eina_Promise* promise, Eina_Promise_Cb callback, | 777 | eina_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, | |||
232 | EAPI Eina_Promise* eina_promise_all(Eina_Iterator* promises); | 236 | EAPI 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 | */ | ||
248 | EAPI 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 | } |
337 | END_TEST | 337 | END_TEST |
338 | 338 | ||
339 | START_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 | } | ||
359 | END_TEST | ||
360 | |||
339 | void | 361 | void |
340 | eina_test_promise(TCase *tc) | 362 | eina_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 | } |