summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuilherme Iscaro <iscaro@profusion.mobi>2017-08-25 19:53:15 -0300
committerGuilherme Iscaro <iscaro@profusion.mobi>2017-08-25 19:53:49 -0300
commit0dd2c1a53018e1c0a7f4c695782fd453bd03a362 (patch)
tree705f4dd2afe3b780138d3752506c0213a750de2d
parentd30c0d4f032726cf33a1801ea5e68fead641669a (diff)
Efl_Object: Add integration with Eina_Future.
This commit adds the EO support for the new future infra. From now on there's no need to efl_future_link()/efl_future_unlink() object and futures since the new API already handles that internally.
-rw-r--r--src/lib/eo/Eo.h235
-rw-r--r--src/lib/eo/eo.c95
-rw-r--r--src/lib/eo/eo_base_class.c177
3 files changed, 488 insertions, 19 deletions
diff --git a/src/lib/eo/Eo.h b/src/lib/eo/Eo.h
index 3757392ed2..2a8cb44d9f 100644
--- a/src/lib/eo/Eo.h
+++ b/src/lib/eo/Eo.h
@@ -340,6 +340,239 @@ EOAPI Eina_Bool efl_event_callback_legacy_call(Eo *obj, const Efl_Event_Descript
340 */ 340 */
341EOAPI Eina_Bool efl_future_link(Eo *obj, Efl_Future *link); 341EOAPI Eina_Bool efl_future_link(Eo *obj, Efl_Future *link);
342 342
343
344/**
345 * @struct _Efl_Future_Cb_Desc
346 *
347 * A struct with callbacks to be used by efl_future_cb_from_desc() and efl_future_chain_from_array()
348 *
349 * @see efl_future_cb_from_desc()
350 * @see efl_future_chain_from_array()
351 */
352typedef struct _Efl_Future_Cb_Desc {
353 /**
354 * Called on success (value.type is not @c EINA_VALUE_TYPE_ERROR).
355 *
356 * if @c success_type is not NULL, then the value is guaranteed to be of that type,
357 * if it's not, then it will trigger @c error with @c EINVAL.
358 *
359 * After this function returns, @c free callback is called if provided.
360 *
361 * @note This function is always called from a safe context (main loop or some platform defined safe context).
362 *
363 * @param o The object used to create the link in efl_future_cb_from_desc() or efl_future_chain_from_array().
364 * @param value The operation result
365 * @return An Eina_Value to pass to the next Eina_Future in the chain (if any).
366 * If there is no need to convert the received value, it's @b recommended
367 * to pass-thru @p value argument. If you need to convert to a different type
368 * or generate a new value, use @c eina_value_setup() on @b another Eina_Value
369 * and return it. By returning an promise Eina_Value (eina_promise_as_value()) the
370 * whole chain will wait until the promise is resolved in
371 * order to continue its execution.
372 * Note that the value contents must survive this function scope,
373 * that is, do @b not use stack allocated blobs, arrays, structures or types that
374 * keeps references to memory you give. Values will be automatically cleaned up
375 * using @c eina_value_flush() once they are unused (no more future or futures
376 * returned a new value).
377 */
378 Eina_Value (*success)(Eo *o, const Eina_Value value);
379 /**
380 * Called on error (value.type is @c EINA_VALUE_TYPE_ERROR).
381 *
382 * This function can return another error, propagating or converting it. However it
383 * may also return a non-error, in this case the next future in chain will receive a regular
384 * value, which may call its @c success.
385 *
386 * If this function is not provided, then it will pass thru the error to the next error handler.
387 *
388 * It may be called with @c EINVAL if @c success_type is provided and doesn't
389 * match the received type.
390 *
391 * It may be called with @c ECANCELED if future was canceled.
392 *
393 * It may be called with @c ENOMEM if memory allocation failed during callback creation.
394 *
395 * After this function returns, @c free callback is called if provided.
396 *
397 * @note On future creation errors and future cancellation this function will be called
398 * from the current context with the following errors respectitally: `EINVAL`, `ENOMEM` and `ECANCELED`.
399 * Otherwise this function is called from a safe context.
400 *
401 *
402 * @param o The object used to create the link in efl_future_cb_from_desc() or efl_future_chain_from_array().
403 * @param error The operation error
404 * @return An Eina_Value to pass to the next Eina_Future in the chain (if any).
405 * If you need to convert to a different type or generate a new value,
406 * use @c eina_value_setup() on @b another Eina_Value
407 * and return it. By returning an promise Eina_Value (eina_promise_as_value()) the
408 * whole chain will wait until the promise is resolved in
409 * order to continue its execution.
410 * Note that the value contents must survive this function scope,
411 * that is, do @b not use stack allocated blobs, arrays, structures or types that
412 * keeps references to memory you give. Values will be automatically cleaned up
413 * using @c eina_value_flush() once they are unused (no more future or futures
414 * returned a new value).
415 */
416 Eina_Value (*error)(Eo *o, Eina_Error error);
417 /**
418 * Called on @b all situations to notify future destruction.
419 *
420 * This is called after @c success or @c error, as well as it's called if none of them are
421 * provided. Thus can be used as a "weak ref" mechanism.
422 *
423 * @note On future creation errors and future cancellation this function will be called
424 * from the current context with the following errors respectitally: `EINVAL`, `ENOMEM` and `ECANCELED`.
425 * Otherwise this function is called from a safe context.
426 *
427 * @param o The object used to create the link in efl_future_cb_from_desc() or efl_future_chain_from_array().
428 * @param dead_future The future that was freed.
429 */
430 void (*free)(Eo *o, const Eina_Future *dead_future);
431 /**
432 * If provided, then @c success will only be called if the value type matches the given pointer.
433 *
434 * If provided and doesn't match, then @c error will be called with @c EINVAL. If no @c error,
435 * then it will be propagated to the next future in the chain.
436 */
437 const Eina_Value_Type *success_type;
438 /**
439 * This is used by Eo to cancel a pending futures in case
440 * an Eo object is deleted. It can be @c NULL.
441 */
442 Eina_Future **storage;
443} Efl_Future_Cb_Desc;
444
445/**
446 * Creates an Eina_Future_Desc for an EO object.
447 *
448 * This function creates an Eina_Future_Desc based on an Efl_Future_Cb_Desc.
449 * The main purpose of this function is create a "link" between the future
450 * and the object. In case the object is deleted before the future is resolved/rejected,
451 * the object destructor will cancel the future.
452 *
453 * @note In case context info are needed for the #Efl_Future_Desc callbacks efl_key_data_set()
454 * can be used.
455 *
456 * The example below shows a file download using an Eo object, if the download
457 * lasts more than 30 seconds the Eo object will be deleted, causing the
458 * future to also be deleted.
459 * Usually this would be done with an eina_future_race() of the download promise and a timeout promise,
460 * however we provide the following example to illustrate efl_key_data_set() usage.
461 *
462 * @code
463 *
464 * static Eina_Bool
465 * _timeout(void *data)
466 * {
467 * Eo *downloader = data;
468 * //In case the download is not completed yet.
469 * //Delete the downloader (which in cancel the file download and the future)
470 * efl_key_data_set(downloader, "timer", NULL);
471 * efl_unref(downloader);
472 * return EINA_FALSE;
473 * }
474 *
475 * static Eina_Value
476 * _file_ok(Eo *o EINA_UNUSED, const Eina_Value value)
477 * {
478 * const char *data;
479 * //There's no need to check the value type since EO infra already did that for us
480 * eina_value_get(&value, &data);
481 * //Deliver the data to the user
482 * data_deliver(data);
483 * return v;
484 * }
485 *
486 * static Eina_Value
487 * _file_err(Eo *o EINA_UNUSED, Eina_Error error)
488 * {
489 * //In case the downloader is deleted before the future is resolved, the future will be canceled thus this callback will be called.
490 * fprintf(stderr, "Could not download the file. Reason: %s\n", eina_error_msg_get(error));
491 * return EINA_VALUE_EMPTY;
492 * }
493 *
494 * static void
495 * _downlader_free(Eo *o, const Eina_Future *dead_future EINA_UNUSED)
496 * {
497 * Ecore_Timer *t = efl_key_data_get(o, "timer");
498 * //The download was finished before the timer expired. Cancel it...
499 * if (t)
500 * {
501 * ecore_timer_del(t);
502 * efl_unref(o); //Delete the object
503 * } //else - In this case the future was canceled due efl_unref() in _timeout - No need to call efl_unref()
504 * }
505 *
506 * void download_file(const char *file)
507 * {
508 * //This could be rewritten using eina_future_race()
509 * Eo *downloader = efl_add(MY_DOWNLOADER_CLASS, NULL);
510 * Eina_Future *f = downloader_download_file(downloader, file);
511 * timer = ecore_timer_add(30, _timeout, downloader);
512 * //Usually this would be done with an eina_future_race() of the download promise and a timeout promise,
513 * //however we provide the following example to illustrate efl_key_data_set() usage.
514 * efl_key_data_set(downloader, "timer", timer);
515 * eina_future_then_from_desc(f, efl_future_cb(.success = _file_ok, .error = _file_err, .success_type = EINA_VALUE_TYPE_STRING, .free = downloader_free));
516 * }
517 * @endcode
518 *
519 * @param obj The object to create the link.
520 * @param desc An Efl_Future_Cb_Desc
521 * @return An Eina_Future_Desc to be used by eina_future_then(), eina_future_chain() and friends.
522 * @see efl_future_chain_from_array()
523 * @see efl_future_cb()
524 * @see #Efl_Future_Cb_Desc
525 * @see efl_key_data_set()
526 */
527EOAPI Eina_Future_Desc efl_future_cb_from_desc(Eo *obj, const Efl_Future_Cb_Desc desc);
528
529/**
530 * Syntax suger over efl_future_cb_from_desc()
531 *
532 * Usage:
533 * @code
534 * eina_future_then_from_desc(future, efl_future_cb(my_object, .succes = success, .success_type = EINA_VALUE_TYPE_INT));
535 * @endcode
536 *
537 * @see efl_future_cb_from_desc()
538 */
539#define efl_future_cb(_eo, ...) efl_future_cb_from_desc(_eo, (Efl_Future_Cb_Desc){__VA_ARGS__})
540
541/**
542 * Creates an Future chain based on #Efl_Future_Cb_Desc
543 *
544 * This function is an wrapper around efl_future_cb_from_desc() and eina_future_then_from_desc()
545 *
546 * For more information about them, check their documentations.
547 *
548 *
549 * @param obj An EO object to link against the future
550 * @param prev The previous future
551 * @param descs An array of Efl_Future_Cb_Desc
552 * @return An Eina_Future or @c NULL on error.
553 * @note If an error happens the whole future chain will be CANCELED, causing
554 * desc.error to be called passing `ENOMEM` or `EINVAL` and desc.free
555 * to free the @p obj if necessary.
556 *
557 * @see efl_future_chain()
558 * @see efl_future_cb()
559 * @see eina_future_then_from_desc()
560 * @see #Efl_Future_Cb_Desc
561 */
562EOAPI Eina_Future *efl_future_chain_from_array(Eo *obj, Eina_Future *prev, const Efl_Future_Cb_Desc descs[]);
563
564/**
565 * Syntax suger over efl_future_chain_from_array()
566 *
567 * Usage:
568 * @code
569 * Eina_Future *f = efl_future_chain(my_object, prev_future, {}, {});
570 * @endcode
571 *
572 * @see efl_future_chain_from_array()
573 */
574#define efl_future_chain(_eo, _prev, ...) efl_future_chain_from_array(_eo, _prev, (Efl_Future_Cb_Desc []){__VA_ARGS__, {NULL, NULL, NULL, NULL, NULL}})
575
343/** 576/**
344 * @addtogroup Eo_Debug_Information Eo's Debug information helper. 577 * @addtogroup Eo_Debug_Information Eo's Debug information helper.
345 * @{ 578 * @{
@@ -1806,6 +2039,8 @@ efl_replace(Eo **storage, Eo *new_obj)
1806 *storage = new_obj; 2039 *storage = new_obj;
1807} 2040}
1808 2041
2042EOAPI extern const Eina_Value_Type *EINA_VALUE_TYPE_OBJECT;
2043
1809/** 2044/**
1810 * @} 2045 * @}
1811 */ 2046 */
diff --git a/src/lib/eo/eo.c b/src/lib/eo/eo.c
index e47778e4b9..489d042253 100644
--- a/src/lib/eo/eo.c
+++ b/src/lib/eo/eo.c
@@ -3182,3 +3182,98 @@ eo_objects_iterator_new(void)
3182 3182
3183 return (Eina_Iterator *)it; 3183 return (Eina_Iterator *)it;
3184} 3184}
3185
3186static Eina_Bool
3187_eo_value_setup(const Eina_Value_Type *type EINA_UNUSED, void *mem)
3188{
3189 Eo **tmem = mem;
3190 *tmem = NULL;
3191 return EINA_TRUE;
3192}
3193
3194static Eina_Bool
3195_eo_value_flush(const Eina_Value_Type *type EINA_UNUSED, void *mem)
3196{
3197 Eo **tmem = mem;
3198 if (*tmem)
3199 {
3200 efl_unref(*tmem);
3201 *tmem = NULL;
3202 }
3203 return EINA_TRUE;
3204}
3205
3206static void
3207_eo_value_replace(Eo **dst, Eo * const *src)
3208{
3209 if (*src == *dst) return;
3210 //ref *src first, since efl_unref(*dst) may trigger *src unref()
3211 efl_ref(*src);
3212 efl_unref(*dst);
3213 *dst = *src;
3214}
3215
3216static Eina_Bool
3217_eo_value_vset(const Eina_Value_Type *type EINA_UNUSED, void *mem, va_list args)
3218{
3219 Eo **dst = mem;
3220 Eo **src = va_arg(args, Eo **);
3221 _eo_value_replace(dst, src);
3222 return EINA_TRUE;
3223}
3224
3225static Eina_Bool
3226_eo_value_pset(const Eina_Value_Type *type EINA_UNUSED,
3227 void *mem, const void *ptr)
3228{
3229 Eo **dst = mem;
3230 Eo * const *src = ptr;
3231 _eo_value_replace(dst, src);
3232 return EINA_TRUE;
3233}
3234
3235static Eina_Bool
3236_eo_value_pget(const Eina_Value_Type *type EINA_UNUSED,
3237 const void *mem, void *ptr)
3238{
3239 Eo * const *src = mem;
3240 Eo **dst = ptr;
3241 *dst = *src;
3242 return EINA_TRUE;
3243}
3244
3245static Eina_Bool
3246_eo_value_convert_to(const Eina_Value_Type *type EINA_UNUSED, const Eina_Value_Type *convert, const void *type_mem, void *convert_mem)
3247{
3248 Eo * const *eo = type_mem;
3249
3250 if (convert == EINA_VALUE_TYPE_STRINGSHARE ||
3251 convert == EINA_VALUE_TYPE_STRING)
3252 {
3253 const char *other_mem;
3254 char buf[256];
3255 snprintf(buf, sizeof(buf), "Object id: %p, class: %s, name: %s",
3256 *eo, efl_class_name_get(efl_class_get(*eo)),
3257 efl_debug_name_get(*eo));
3258 other_mem = buf;
3259 return eina_value_type_pset(convert, convert_mem, &other_mem);
3260 }
3261 return EINA_FALSE;
3262}
3263
3264static const Eina_Value_Type _EINA_VALUE_TYPE_OBJECT = {
3265 .version = EINA_VALUE_TYPE_VERSION,
3266 .value_size = sizeof(Eo *),
3267 .name = "Efl_Object",
3268 .setup = _eo_value_setup,
3269 .flush = _eo_value_flush,
3270 .copy = NULL,
3271 .compare = NULL,
3272 .convert_to = _eo_value_convert_to,
3273 .convert_from = NULL,
3274 .vset = _eo_value_vset,
3275 .pset = _eo_value_pset,
3276 .pget = _eo_value_pget
3277};
3278
3279EOAPI const Eina_Value_Type *EINA_VALUE_TYPE_OBJECT = &_EINA_VALUE_TYPE_OBJECT;
diff --git a/src/lib/eo/eo_base_class.c b/src/lib/eo/eo_base_class.c
index da33114736..913e7fbe5d 100644
--- a/src/lib/eo/eo_base_class.c
+++ b/src/lib/eo/eo_base_class.c
@@ -8,6 +8,7 @@
8#include "Eo.h" 8#include "Eo.h"
9#include "eo_ptr_indirection.h" 9#include "eo_ptr_indirection.h"
10#include "eo_private.h" 10#include "eo_private.h"
11#include "eina_promise_private.h"
11 12
12#define EFL_EVENT_SPECIAL_SKIP 1 13#define EFL_EVENT_SPECIAL_SKIP 1
13 14
@@ -45,6 +46,7 @@ typedef struct
45 46
46 Efl_Event_Callback_Frame *event_frame; 47 Efl_Event_Callback_Frame *event_frame;
47 Eo_Callback_Description **callbacks; 48 Eo_Callback_Description **callbacks;
49 Eina_Inlist *pending_futures;
48 unsigned int callbacks_count; 50 unsigned int callbacks_count;
49 51
50 unsigned short event_freeze_count; 52 unsigned short event_freeze_count;
@@ -79,6 +81,15 @@ typedef struct
79 Eo_Generic_Data_Node_Type d_type; 81 Eo_Generic_Data_Node_Type d_type;
80} Eo_Generic_Data_Node; 82} Eo_Generic_Data_Node;
81 83
84typedef struct _Efl_Future_Pending
85{
86 EINA_INLIST;
87 Eo *o;
88 Eina_Future *future;
89 Efl_Future_Cb_Desc desc;
90} Efl_Future_Pending;
91
92
82typedef struct 93typedef struct
83{ 94{
84 EINA_INLIST; 95 EINA_INLIST;
@@ -972,48 +983,77 @@ struct _Eo_Callback_Description
972 983
973static int _eo_callbacks = 0; 984static int _eo_callbacks = 0;
974static Eina_Mempool *_eo_callback_mempool = NULL; 985static Eina_Mempool *_eo_callback_mempool = NULL;
986static int _efl_pending_futures = 0;
987static Eina_Mempool *_efl_pending_future_mempool = NULL;
975 988
976static void 989static void
977_eo_callback_free(Eo_Callback_Description *cb) 990_mempool_data_free(Eina_Mempool **mp, int *usage, void *data)
978{ 991{
979 if (!cb) return; 992 if (!data) return;
980 eina_mempool_free(_eo_callback_mempool, cb); 993 eina_mempool_free(*mp, data);
981 _eo_callbacks--; 994 (*usage)--;
982 if (_eo_callbacks == 0) 995 if (*usage == 0)
983 { 996 {
984 eina_mempool_del(_eo_callback_mempool); 997 eina_mempool_del(*mp);
985 _eo_callback_mempool = NULL; 998 *mp = NULL;
986 } 999 }
987} 1000}
988 1001
989static Eo_Callback_Description * 1002static void *
990_eo_callback_new(void) 1003_mempool_data_alloc(Eina_Mempool **mp, int *usage, size_t size)
991{ 1004{
992 Eo_Callback_Description *cb; 1005 Eo_Callback_Description *cb;
993 // very unlikely that the mempool isnt initted, so take all the init code 1006 // very unlikely that the mempool isnt initted, so take all the init code
994 // and move it out of l1 instruction cache space so we dont pollute the 1007 // and move it out of l1 instruction cache space so we dont pollute the
995 // l1 cache with unused code 99% of the time 1008 // l1 cache with unused code 99% of the time
996 if (!_eo_callback_mempool) goto init_mempool; 1009 if (!*mp) goto init_mempool;
997init_mempool_back: 1010init_mempool_back:
998 1011
999 cb = eina_mempool_calloc(_eo_callback_mempool, 1012 cb = eina_mempool_calloc(*mp, size);
1000 sizeof(Eo_Callback_Description));
1001 if (cb) 1013 if (cb)
1002 { 1014 {
1003 _eo_callbacks++; 1015 (*usage)++;
1004 return cb; 1016 return cb;
1005 } 1017 }
1006 if (_eo_callbacks != 0) return NULL; 1018 if (*usage != 0) return NULL;
1007 eina_mempool_del(_eo_callback_mempool); 1019 eina_mempool_del(*mp);
1008 _eo_callback_mempool = NULL; 1020 *mp = NULL;
1009 return NULL; 1021 return NULL;
1010init_mempool: 1022init_mempool:
1011 _eo_callback_mempool = eina_mempool_add 1023 *mp = eina_mempool_add
1012 ("chained_mempool", NULL, NULL, sizeof(Eo_Callback_Description), 256); 1024 ("chained_mempool", NULL, NULL, size, 256);
1013 if (!_eo_callback_mempool) return NULL; 1025 if (!*mp) return NULL;
1014 goto init_mempool_back; 1026 goto init_mempool_back;
1015} 1027}
1016 1028
1029static void
1030_eo_callback_free(Eo_Callback_Description *cb)
1031{
1032 _mempool_data_free(&_eo_callback_mempool, &_eo_callbacks, cb);
1033}
1034
1035static Eo_Callback_Description *
1036_eo_callback_new(void)
1037{
1038 return _mempool_data_alloc(&_eo_callback_mempool, &_eo_callbacks,
1039 sizeof(Eo_Callback_Description));
1040}
1041
1042static void
1043_efl_pending_future_free(Efl_Future_Pending *pending)
1044{
1045 _mempool_data_free(&_efl_pending_future_mempool,
1046 &_efl_pending_futures, pending);
1047}
1048
1049static Efl_Future_Pending *
1050_efl_pending_future_new(void)
1051{
1052 return _mempool_data_alloc(&_efl_pending_future_mempool,
1053 &_efl_pending_futures,
1054 sizeof(Efl_Future_Pending));
1055}
1056
1017#ifdef EFL_EVENT_SPECIAL_SKIP 1057#ifdef EFL_EVENT_SPECIAL_SKIP
1018 1058
1019#define CB_COUNT_INC(cnt) do { if ((cnt) != 0xffff) (cnt)++; } while(0) 1059#define CB_COUNT_INC(cnt) do { if ((cnt) != 0xffff) (cnt)++; } while(0)
@@ -1858,6 +1898,104 @@ EAPI const Eina_Value_Type *EFL_DBG_INFO_TYPE = &_EFL_DBG_INFO_TYPE;
1858/* EFL_OBJECT_CLASS stuff */ 1898/* EFL_OBJECT_CLASS stuff */
1859#define MY_CLASS EFL_OBJECT_CLASS 1899#define MY_CLASS EFL_OBJECT_CLASS
1860 1900
1901static void
1902_efl_pending_futures_clear(Efl_Object_Data *pd)
1903{
1904 while (pd->pending_futures)
1905 {
1906 Efl_Future_Pending *pending = EINA_INLIST_CONTAINER_GET(pd->pending_futures, Efl_Future_Pending);
1907 Eina_Future *future = *pending->desc.storage;
1908 assert(future);
1909 eina_future_cancel(future);
1910 }
1911}
1912
1913static Eina_Value
1914_efl_future_cb(void *data, const Eina_Value value, const Eina_Future *dead_future)
1915{
1916 Efl_Future_Pending *pending = data;
1917 Eina_Value ret = value;
1918 Eo *o;
1919 Efl_Object_Data *pd;
1920
1921 EINA_SAFETY_ON_NULL_GOTO(pending, err);
1922 o = pending->o;
1923 pd = efl_data_scope_get(o, EFL_OBJECT_CLASS);
1924 EINA_SAFETY_ON_NULL_GOTO(pd, err);
1925
1926 pd->pending_futures = eina_inlist_remove(pd->pending_futures,
1927 EINA_INLIST_GET(pending));
1928 efl_ref(o);
1929 EASY_FUTURE_DISPATCH(ret, value, dead_future, &pending->desc, o);
1930 efl_unref(o);
1931 _efl_pending_future_free(pending);
1932
1933 return ret;
1934
1935 err:
1936 eina_value_setup(&ret, EINA_VALUE_TYPE_ERROR);
1937 eina_value_set(&ret, ENOMEM);
1938 return ret;
1939}
1940
1941EOAPI Eina_Future_Desc
1942efl_future_cb_from_desc(Eo *o, const Efl_Future_Cb_Desc desc)
1943{
1944 Efl_Future_Pending *pending = NULL;
1945 Eina_Future **storage = NULL;
1946 Efl_Object_Data *pd;
1947
1948 EINA_SAFETY_ON_NULL_GOTO(o, end);
1949 pd = efl_data_scope_get(o, EFL_OBJECT_CLASS);
1950 EINA_SAFETY_ON_NULL_GOTO(pd, end);
1951 pending = _efl_pending_future_new();
1952 EINA_SAFETY_ON_NULL_GOTO(pending, end);
1953 memcpy(&pending->desc, &desc, sizeof(Efl_Future_Cb_Desc));
1954 pending->o = o;
1955 pending->future = NULL;
1956 if (!pending->desc.storage) pending->desc.storage = &pending->future;
1957 pd->pending_futures = eina_inlist_append(pd->pending_futures,
1958 EINA_INLIST_GET(pending));
1959 storage = pending->desc.storage;
1960 end:
1961 return (Eina_Future_Desc){ .cb = _efl_future_cb, .data = pending, .storage = storage };
1962}
1963
1964EOAPI Eina_Future *
1965efl_future_chain_from_array(Eo *obj,
1966 Eina_Future *prev,
1967 const Efl_Future_Cb_Desc descs[])
1968{
1969 size_t i = -1;
1970 Eina_Future *f = prev;
1971
1972 for (i = 0; descs[i].success || descs[i].error || descs[i].free || descs[i].success_type; i++)
1973 {
1974 Eina_Future_Desc eina_desc = efl_future_cb_from_desc(obj, descs[i]);
1975 f = eina_future_then_from_desc(f, eina_desc);
1976 EINA_SAFETY_ON_NULL_GOTO(f, err);
1977 }
1978
1979 return f;
1980
1981 err:
1982 /*
1983 There's no need to cancel the futures, since eina_future_then_from_desc()
1984 will cancel the whole chain in case of failure.
1985 All we need to do is to free the remaining descs
1986 */
1987 for (i = i + 1; descs[i].error || descs[i].free; i++)
1988 {
1989 if (descs[i].error)
1990 {
1991 Eina_Value r = descs[i].error(obj, ENOMEM);
1992 if (r.type) eina_value_flush(&r);
1993 }
1994 if (descs[i].free) descs[i].free(obj, NULL);
1995 }
1996 return NULL;
1997}
1998
1861EOLIAN static Eo * 1999EOLIAN static Eo *
1862_efl_object_constructor(Eo *obj, Efl_Object_Data *pd EINA_UNUSED) 2000_efl_object_constructor(Eo *obj, Efl_Object_Data *pd EINA_UNUSED)
1863{ 2001{
@@ -1905,6 +2043,7 @@ composite_obj_back:
1905 if (pd->parent) goto err_parent; 2043 if (pd->parent) goto err_parent;
1906err_parent_back: 2044err_parent_back:
1907 2045
2046 _efl_pending_futures_clear(pd);
1908 _eo_generic_data_del_all(obj, pd); 2047 _eo_generic_data_del_all(obj, pd);
1909 _wref_destruct(pd); 2048 _wref_destruct(pd);
1910 _eo_callback_remove_all(pd); 2049 _eo_callback_remove_all(pd);