From: Felipe Magno de Almeida Date: Fri, 1 Apr 2016 17:49:58 +0000 (-0300) Subject: eina: add promise X-Git-Tag: upstream/1.20.0~6929 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=09eea7bc01dd1381589eeab35e705cbd45820f1e;p=platform%2Fupstream%2Fefl.git eina: add promise Add a promise object that will allows Eolian interface to include promises as a way to have asynchronous value return and composibility. To understand better, let see the coming usage in a .eo file: class Foo { methods { bar { params { @inout promise: Promise; } } } } Which will create the following API interface: void foo_bar(Eo* obj, Eina_Promise** promise); and the equivalent declaration for implementation. However, the API function will instantiate the Promise for the user and the implementer of the class automatically. So the user of this function will treat it as a @out parameter, while the developer of the function will treat it like a @inout parameter. So, the user will use this function like this: Eina_Promise* promise; // No need to instantiate foo_bar(obj, &promise); eina_promise_then(promise, callback); Signed-off-by: Cedric Bail --- diff --git a/src/Makefile_Eina.am b/src/Makefile_Eina.am index 71d0330..da76e0a 100644 --- a/src/Makefile_Eina.am +++ b/src/Makefile_Eina.am @@ -96,6 +96,7 @@ lib/eina/eina_util.h \ lib/eina/eina_quaternion.h \ lib/eina/eina_vector.h \ lib/eina/eina_inline_vector.x \ +lib/eina/eina_promise.h \ lib/eina/eina_bezier.h lib_eina_libeina_la_SOURCES = \ @@ -166,6 +167,7 @@ lib/eina/eina_private.h \ lib/eina/eina_share_common.h \ lib/eina/eina_strbuf_common.h \ lib/eina/eina_quaternion.c \ +lib/eina/eina_promise.c \ lib/eina/eina_bezier.c if HAVE_WIN32 diff --git a/src/lib/eina/Eina.h b/src/lib/eina/Eina.h index db9260e..fe0a4ec 100644 --- a/src/lib/eina/Eina.h +++ b/src/lib/eina/Eina.h @@ -268,6 +268,7 @@ extern "C" { #include #include #include +#include #include #undef EAPI diff --git a/src/lib/eina/eina_promise.c b/src/lib/eina/eina_promise.c new file mode 100644 index 0000000..9a7c259 --- /dev/null +++ b/src/lib/eina/eina_promise.c @@ -0,0 +1,640 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include + +typedef struct _Eina_Promise_Then_Cb _Eina_Promise_Then_Cb; +typedef struct _Eina_Promise_Progress_Cb _Eina_Promise_Progress_Cb; +typedef struct _Eina_Promise_Cancel_Cb _Eina_Promise_Cancel_Cb; +typedef struct _Eina_Promise_Default _Eina_Promise_Default; +typedef struct _Eina_Promise_Default_Owner _Eina_Promise_Default_Owner; +typedef struct _Eina_Promise_Iterator _Eina_Promise_Iterator; +typedef struct _Eina_Promise_Success_Iterator _Eina_Promise_Success_Iterator; + +struct _Eina_Promise_Then_Cb +{ + EINA_INLIST; + + Eina_Promise_Cb callback; + Eina_Promise_Error_Cb error_cb; + void* data; +}; + +struct _Eina_Promise_Progress_Cb +{ + EINA_INLIST; + + Eina_Promise_Progress_Cb callback; + void* data; +}; + +struct _Eina_Promise_Cancel_Cb +{ + EINA_INLIST; + + Eina_Promise_Default_Cancel_Cb callback; + Eina_Promise_Free_Cb free; + void* data; +}; + +struct _Eina_Promise_Default +{ + Eina_Promise vtable; + Eina_Error error; + size_t value_size; + + Eina_Inlist *then_callbacks; + Eina_Inlist *progress_callbacks; + Eina_Inlist *cancel_callbacks; + Eina_Promise_Free_Cb value_free_cb; + + int ref; + + Eina_Bool has_finished : 1; + Eina_Bool has_errored : 1; + Eina_Bool is_cancelled : 1; + Eina_Bool is_manual_then : 1; + Eina_Bool is_first_then : 1; +}; + +struct _Eina_Promise_Default_Owner +{ + Eina_Promise_Owner owner_vtable; + _Eina_Promise_Default promise; + + char value[]; +}; + +#define EINA_PROMISE_GET_OWNER(p) (_Eina_Promise_Default_Owner*)((unsigned char*)p - offsetof(struct _Eina_Promise_Default_Owner, promise)) + +struct _Eina_Promise_Iterator +{ + Eina_Iterator* success_iterator; + struct _Eina_Promise_Success_Iterator + { + Eina_Iterator success_iterator_impl; + unsigned int promise_index; + unsigned int num_promises; + unsigned int promises_finished; + Eina_Promise* promises[]; + } data; +}; + +static void _eina_promise_finish(_Eina_Promise_Default_Owner* promise); +static void _eina_promise_ref(_Eina_Promise_Default* promise); +static void _eina_promise_unref(_Eina_Promise_Default* promise); + +static void _eina_promise_iterator_setup(_Eina_Promise_Iterator* iterator, Eina_Array* promises); + +static void +_eina_promise_then_calls(_Eina_Promise_Default_Owner* promise) +{ + _Eina_Promise_Then_Cb* callback; + Eina_Inlist* list2; + Eina_Bool error; + + _eina_promise_ref(&promise->promise); + error = promise->promise.has_errored; + + EINA_INLIST_FOREACH_SAFE(promise->promise.then_callbacks, list2, callback) + { + if (error) + { + if (callback->error_cb) + (*callback->error_cb)(callback->data, &promise->promise.error); + } + else if (callback->callback) + { + fprintf(stderr, "then callback\n"); + (*callback->callback)(callback->data, &promise->value[0]); + } + _eina_promise_unref(&promise->promise); + } + _eina_promise_unref(&promise->promise); +} + +static void +_eina_promise_cancel_calls(_Eina_Promise_Default_Owner* promise, Eina_Bool call_cancel EINA_UNUSED) +{ + _Eina_Promise_Cancel_Cb* callback; + Eina_Inlist* list2; + + EINA_INLIST_FOREACH_SAFE(promise->promise.cancel_callbacks, list2, callback) + { + if (callback->callback) + { + (*callback->callback)(callback->data, (Eina_Promise_Owner*)promise); + } + } + + if (!promise->promise.is_manual_then) + { + _eina_promise_then_calls(promise); + } +} + +static void +_eina_promise_del(_Eina_Promise_Default_Owner* promise) +{ + if (promise->promise.has_finished) + { + if (promise->promise.value_free_cb) + promise->promise.value_free_cb((void*)&promise->value[0]); + } + else + { + _eina_promise_cancel_calls(promise, EINA_TRUE); + } +} + +static void * +_eina_promise_buffer_get(_Eina_Promise_Default_Owner* promise) +{ + return &promise->value[0]; +} + +static void * +_eina_promise_value_get(_Eina_Promise_Default_Owner const* promise) +{ + if (promise->promise.has_finished) + { + return (void*)(promise->promise.value_size && !promise->promise.has_errored ? + &promise->value[0] : NULL); + } + else + { + return NULL; + } +} + +static void +_eina_promise_value_set(_Eina_Promise_Default_Owner* promise, void* data, Eina_Promise_Free_Cb free) +{ + if (data && promise->promise.value_size) + { + memcpy(&promise->value[0], data, promise->promise.value_size); + } + + promise->promise.value_free_cb = free; + + _eina_promise_finish(promise); +} + +static void +_eina_promise_then(_Eina_Promise_Default* p, Eina_Promise_Cb callback, + Eina_Promise_Error_Cb error_cb, void* data) +{ + _Eina_Promise_Default_Owner* promise; + _Eina_Promise_Then_Cb* cb; + + promise = EINA_PROMISE_GET_OWNER(p); + + cb = malloc(sizeof(struct _Eina_Promise_Then_Cb)); + + cb->callback = callback; + cb->error_cb = error_cb; + cb->data = data; + promise->promise.then_callbacks = eina_inlist_append(promise->promise.then_callbacks, EINA_INLIST_GET(cb)); + fprintf(stderr, "appending then callback\n"); + + if (!promise->promise.is_first_then) + { + _eina_promise_ref(p); + promise->promise.is_first_then = EINA_FALSE; + } + if (promise->promise.has_finished) + { + _eina_promise_then_calls(promise); + } +} + +static void +_eina_promise_error_set(_Eina_Promise_Default_Owner* promise, Eina_Error error) +{ + promise->promise.error = error; + promise->promise.has_errored = EINA_TRUE; + + _eina_promise_finish(promise); +} + +static void +_eina_promise_finish(_Eina_Promise_Default_Owner* promise) +{ + promise->promise.has_finished = EINA_TRUE; + if (!promise->promise.is_manual_then) + { + _eina_promise_then_calls(promise); + } +} + +static Eina_Error +_eina_promise_error_get(_Eina_Promise_Default_Owner const* promise) +{ + if (promise->promise.has_errored) + { + return promise->promise.error; + } + else + { + return 0; + } +} + +static Eina_Bool +_eina_promise_pending_is(_Eina_Promise_Default const* promise) +{ + return !promise->has_finished; +} + +static Eina_Bool +_eina_promise_owner_pending_is(_Eina_Promise_Default_Owner const* promise) +{ + return !promise->promise.has_finished; +} + +static Eina_Bool +_eina_promise_owner_cancelled_is(_Eina_Promise_Default_Owner const* promise) +{ + return promise->promise.is_cancelled; +} + +static void +_eina_promise_progress_cb_add(_Eina_Promise_Default* promise, Eina_Promise_Progress_Cb callback, void* data) +{ + _Eina_Promise_Progress_Cb* cb; + + cb = malloc(sizeof(struct _Eina_Promise_Progress_Cb)); + cb->callback = callback; + cb->data = data; + promise->progress_callbacks = eina_inlist_append(promise->progress_callbacks, EINA_INLIST_GET(cb)); +} + +static void +_eina_promise_cancel(_Eina_Promise_Default* promise) +{ + _Eina_Promise_Default_Owner* owner = EINA_PROMISE_GET_OWNER(promise); + + if (!owner->promise.is_cancelled) + { + owner->promise.is_cancelled = EINA_TRUE; + owner->promise.has_finished = EINA_TRUE; + owner->promise.has_errored = EINA_TRUE; + _eina_promise_cancel_calls(owner, EINA_TRUE); + } +} + +static size_t +_eina_promise_value_size_get(_Eina_Promise_Default_Owner const* promise) +{ + return promise->promise.value_size; +} + +static void +_eina_promise_ref(_Eina_Promise_Default* p) +{ + ++p->ref; +} + +static void +_eina_promise_unref(_Eina_Promise_Default* p) +{ + if (p->ref == 1 && p->has_finished) + { + _eina_promise_del(EINA_PROMISE_GET_OWNER(p)); + } + else + { + --p->ref; + } +} + +static Eina_Promise * +_eina_promise_owner_promise_get(_Eina_Promise_Default_Owner* p) +{ + return &p->promise.vtable; +} + +void +eina_promise_owner_default_cancel_cb_add(Eina_Promise_Owner* p, + Eina_Promise_Default_Cancel_Cb callback, void* data, + Eina_Promise_Free_Cb free_cb) +{ + _Eina_Promise_Default_Owner *promise; + _Eina_Promise_Cancel_Cb *cb; + + promise = (_Eina_Promise_Default_Owner *)p; + + cb = malloc(sizeof(struct _Eina_Promise_Cancel_Cb)); + + cb->callback = callback; + cb->free = free_cb; + cb->data = data; + promise->promise.cancel_callbacks = eina_inlist_append(promise->promise.cancel_callbacks, EINA_INLIST_GET(cb)); + + if (promise->promise.is_cancelled) + { + _eina_promise_cancel_calls(promise, EINA_TRUE); + } +} + +static void +_eina_promise_owner_progress(_Eina_Promise_Default_Owner* promise, void* data) +{ + _Eina_Promise_Progress_Cb* callback; + Eina_Inlist* list2; + + EINA_INLIST_FOREACH_SAFE(promise->promise.progress_callbacks, list2, callback) + { + (*callback->callback)(callback->data, data); + } +} + +Eina_Promise_Owner * +eina_promise_default_add(int value_size) +{ + _Eina_Promise_Default_Owner* p; + + p = malloc(sizeof(_Eina_Promise_Default_Owner) + value_size); + p->promise.vtable.version = EINA_PROMISE_VERSION; + p->promise.vtable.then = EINA_FUNC_PROMISE_THEN(_eina_promise_then); + p->promise.vtable.value_get = EINA_FUNC_PROMISE_VALUE_GET(_eina_promise_value_get); + p->promise.vtable.error_get = EINA_FUNC_PROMISE_ERROR_GET(_eina_promise_error_get); + p->promise.vtable.pending_is = EINA_FUNC_PROMISE_PENDING_IS(_eina_promise_pending_is); + p->promise.vtable.progress_cb_add = EINA_FUNC_PROMISE_PROGRESS_CB_ADD(_eina_promise_progress_cb_add); + p->promise.vtable.cancel = EINA_FUNC_PROMISE_CANCEL(_eina_promise_cancel); + p->promise.vtable.ref = EINA_FUNC_PROMISE_REF(_eina_promise_ref); + p->promise.vtable.unref = EINA_FUNC_PROMISE_UNREF(_eina_promise_unref); + p->promise.vtable.value_size_get = EINA_FUNC_PROMISE_VALUE_SIZE_GET(_eina_promise_value_size_get); + p->promise.has_finished = p->promise.has_errored = + p->promise.is_cancelled = p->promise.is_manual_then = EINA_FALSE; + p->promise.is_first_then = EINA_TRUE; + p->promise.ref = 1; + memset(&p->promise.then_callbacks, 0, sizeof(p->promise.then_callbacks)); + memset(&p->promise.progress_callbacks, 0, sizeof(p->promise.progress_callbacks)); + memset(&p->promise.cancel_callbacks, 0, sizeof(p->promise.cancel_callbacks)); + p->promise.value_size = value_size; + p->promise.value_free_cb = NULL; + + p->owner_vtable.version = EINA_PROMISE_VERSION; + p->owner_vtable.value_set = EINA_FUNC_PROMISE_OWNER_VALUE_SET(_eina_promise_value_set); + p->owner_vtable.error_set = EINA_FUNC_PROMISE_OWNER_ERROR_SET(_eina_promise_error_set); + p->owner_vtable.buffer_get = EINA_FUNC_PROMISE_OWNER_BUFFER_GET(_eina_promise_buffer_get); + p->owner_vtable.value_size_get = EINA_FUNC_PROMISE_OWNER_VALUE_SIZE_GET(_eina_promise_value_size_get); + p->owner_vtable.promise_get = EINA_FUNC_PROMISE_OWNER_PROMISE_GET(_eina_promise_owner_promise_get); + p->owner_vtable.pending_is = EINA_FUNC_PROMISE_OWNER_PENDING_IS(_eina_promise_owner_pending_is); + p->owner_vtable.cancelled_is = EINA_FUNC_PROMISE_OWNER_CANCELLED_IS(_eina_promise_owner_cancelled_is); + p->owner_vtable.progress = EINA_FUNC_PROMISE_OWNER_PROGRESS(_eina_promise_owner_progress); + + return &p->owner_vtable; +} + +void +eina_promise_owner_default_manual_then_set(Eina_Promise_Owner* owner, Eina_Bool is_manual) +{ + _Eina_Promise_Default_Owner* p = (_Eina_Promise_Default_Owner*)owner; + + p->promise.is_manual_then = is_manual; +} + +void +eina_promise_owner_default_call_then(Eina_Promise_Owner* promise) +{ + _Eina_Promise_Default_Owner* owner = (_Eina_Promise_Default_Owner*)promise; + + _eina_promise_then_calls(owner); +} + +static void +_eina_promise_all_compose_then_cb(_Eina_Promise_Default_Owner* promise, void* value EINA_UNUSED) +{ + _Eina_Promise_Iterator* iterator; + + if (!promise->promise.has_finished) + { + iterator = (_Eina_Promise_Iterator*)promise->value; + if (++iterator->data.promises_finished == iterator->data.num_promises) + { + _eina_promise_finish(promise); + } + } +} + +static void +_eina_promise_all_compose_error_then_cb(_Eina_Promise_Default_Owner* promise, Eina_Error const* error) +{ + if (!promise->promise.has_finished) + { + promise->promise.has_finished = promise->promise.has_errored = EINA_TRUE; + promise->promise.error = *error; + _eina_promise_finish(promise); + } +} + +static void +_eina_promise_all_free(_Eina_Promise_Iterator* value) +{ + unsigned i = 0; + + eina_iterator_free(value->success_iterator); + + for (;i != value->data.num_promises; ++i) + { + eina_promise_unref(value->data.promises[i]); + } +} + +Eina_Promise * +eina_promise_all(Eina_Iterator* it) +{ + _Eina_Promise_Default_Owner *promise; + Eina_Promise* current; + Eina_Array* promises; + Eina_Promise **cur_promise, **last; + _Eina_Promise_Iterator* internal_it; + + promises = eina_array_new(20); + + EINA_ITERATOR_FOREACH(it, current) + { + eina_array_push(promises, current); + } + + eina_iterator_free(it); + + promise = (_Eina_Promise_Default_Owner*) + eina_promise_default_add(sizeof(_Eina_Promise_Iterator) + + sizeof(_Eina_Promise_Default_Owner*)*eina_array_count_get(promises)); + internal_it = (_Eina_Promise_Iterator*)&promise->value[0]; + _eina_promise_iterator_setup(internal_it, promises); + eina_array_free(promises); + + promise->promise.value_free_cb = (Eina_Promise_Free_Cb)&_eina_promise_all_free; + + cur_promise = internal_it->data.promises; + last = internal_it->data.promises + internal_it->data.num_promises; + for (;cur_promise != last; ++cur_promise) + { + eina_promise_then(*cur_promise, (Eina_Promise_Cb)&_eina_promise_all_compose_then_cb, + (Eina_Promise_Error_Cb)&_eina_promise_all_compose_error_then_cb, promise); + eina_promise_ref(*cur_promise); // We need to keep the value alive until this promise is freed + } + + return &promise->promise.vtable; +} + +static Eina_Bool +_eina_promise_iterator_next(_Eina_Promise_Success_Iterator *it, void **data) +{ + if (it->promise_index == it->num_promises) + return EINA_FALSE; + + if (eina_promise_error_get(it->promises[it->promise_index])) + { + return EINA_FALSE; + } + else + { + *data = eina_promise_value_get(it->promises[it->promise_index++]); + return EINA_TRUE; + } +} + +static void ** +_eina_promise_iterator_get_container(_Eina_Promise_Success_Iterator *it) +{ + return (void**)it->promises; +} + +static void +_eina_promise_iterator_free(_Eina_Promise_Success_Iterator *it EINA_UNUSED) +{ +} + +static void +_eina_promise_iterator_setup(_Eina_Promise_Iterator* it, Eina_Array* promises_array) +{ + Eina_Promise** promises; + + it->success_iterator = &it->data.success_iterator_impl; + it->data.num_promises = eina_array_count_get(promises_array); + it->data.promise_index = 0; + it->data.promises_finished = 0; + promises = (Eina_Promise**)promises_array->data; + + memcpy(&it->data.promises[0], promises, it->data.num_promises*sizeof(Eina_Promise*)); + + EINA_MAGIC_SET(&it->data.success_iterator_impl, EINA_MAGIC_ITERATOR); + + it->data.success_iterator_impl.version = EINA_ITERATOR_VERSION; + it->data.success_iterator_impl.next = FUNC_ITERATOR_NEXT(_eina_promise_iterator_next); + it->data.success_iterator_impl.get_container = FUNC_ITERATOR_GET_CONTAINER( + _eina_promise_iterator_get_container); + it->data.success_iterator_impl.free = FUNC_ITERATOR_FREE(_eina_promise_iterator_free); +} + +// API functions +EAPI void +eina_promise_then(Eina_Promise* promise, Eina_Promise_Cb callback, + Eina_Promise_Error_Cb error_cb, void* data) +{ + promise->then(promise, callback, error_cb, data); +} + +EAPI void +eina_promise_owner_value_set(Eina_Promise_Owner* promise, void* value, Eina_Promise_Free_Cb free) +{ + promise->value_set(promise, value, free); +} + +EAPI void +eina_promise_owner_error_set(Eina_Promise_Owner* promise, Eina_Error error) +{ + promise->error_set(promise, error); +} + +EAPI void * +eina_promise_value_get(Eina_Promise const* promise) +{ + return promise->value_get(promise); +} + +EAPI Eina_Error +eina_promise_error_get(Eina_Promise const* promise) +{ + return promise->error_get(promise); +} + +EAPI Eina_Bool +eina_promise_pending_is(Eina_Promise const* promise) +{ + return promise->pending_is(promise); +} + +EAPI void +eina_promise_progress_cb_add(Eina_Promise* promise, Eina_Promise_Progress_Cb callback, void* data) +{ + promise->progress_cb_add(promise, callback, data); +} + +EAPI void +eina_promise_cancel(Eina_Promise* promise) +{ + promise->cancel(promise); +} + +EAPI void +eina_promise_ref(Eina_Promise* promise) +{ + promise->ref(promise); +} + +EAPI void +eina_promise_unref(Eina_Promise* promise) +{ + promise->unref(promise); +} + +EAPI void * +eina_promise_owner_buffer_get(Eina_Promise_Owner* promise) +{ + return promise->buffer_get(promise); +} + +EAPI void * +eina_promise_buffer_get(Eina_Promise* promise) +{ + return promise->buffer_get(promise); +} + +EAPI size_t +eina_promise_value_size_get(Eina_Promise const* promise) +{ + return promise->value_size_get(promise); +} + +EAPI Eina_Promise * +eina_promise_owner_promise_get(Eina_Promise_Owner* promise) +{ + return promise->promise_get(promise); +} + +EAPI Eina_Bool +eina_promise_owner_pending_is(Eina_Promise_Owner const* promise) +{ + return promise->pending_is(promise); +} + +EAPI Eina_Bool +eina_promise_owner_cancelled_is(Eina_Promise_Owner const* promise) +{ + return promise->cancelled_is(promise); +} + +EAPI void +eina_promise_owner_progress(Eina_Promise_Owner const* promise, void* progress) +{ + promise->progress(promise, progress); +} diff --git a/src/lib/eina/eina_promise.h b/src/lib/eina/eina_promise.h new file mode 100644 index 0000000..fa9376f --- /dev/null +++ b/src/lib/eina/eina_promise.h @@ -0,0 +1,441 @@ + +#ifdef EFL_BETA_API_SUPPORT + +struct _Eina_Promise; +struct _Eina_Promise_Default; + +/* + * @def Eina_Promise + */ +typedef struct _Eina_Promise Eina_Promise; + +/* + * @def Eina_Promise + */ +typedef struct _Eina_Promise_Owner Eina_Promise_Owner; + +/* + * @brief Callback type for freeing Promise value and void* pointer data for callbacks + */ +typedef void(*Eina_Promise_Free_Cb)(void* value); + +/* + * @brief Function callback type for when using eina_promise_then + */ +typedef void(*Eina_Promise_Cb)(void* data, void* value); + +/* + * @brief Function callback type for when using eina_promise_then + */ +typedef void(*Eina_Promise_Error_Cb)(void* data, Eina_Error const* error); + +/* + * @brief Function callback type for progress information + */ +typedef void(*Eina_Promise_Progress_Cb)(void* data, void* value); + +/* + * @brief Function callback type for then function override + */ +typedef void(*Eina_Promise_Then_Cb)(Eina_Promise* promise, Eina_Promise_Cb callback, + Eina_Promise_Error_Cb error_cb, void* data); + +#define EINA_FUNC_PROMISE_THEN(Function) ((Eina_Promise_Then_Cb)Function) + +/* + * @brief Function callback type for promise's value_get function override + */ +typedef void*(*Eina_Promise_Value_Get_Cb)(Eina_Promise const* promise); + +#define EINA_FUNC_PROMISE_VALUE_GET(Function) ((Eina_Promise_Value_Get_Cb)Function) + +/* + * @brief Function callback type for promise's error_get function override + */ +typedef Eina_Error(*Eina_Promise_Error_Get_Cb)(Eina_Promise const* promise); + +#define EINA_FUNC_PROMISE_ERROR_GET(Function) ((Eina_Promise_Error_Get_Cb)Function) + +/* + * @brief Function callback type for promise's pending function override + */ +typedef Eina_Bool(*Eina_Promise_Pending_Is_Cb)(Eina_Promise const* promise); + +#define EINA_FUNC_PROMISE_PENDING_IS(Function) ((Eina_Promise_Pending_Is_Cb)Function) + +/* + * @brief Function callback type for promise's progress add function override + */ +typedef void(*Eina_Promise_Progress_Cb_Add_Cb)(Eina_Promise* promise, Eina_Promise_Progress_Cb callback, void* data); + +#define EINA_FUNC_PROMISE_PROGRESS_CB_ADD(Function) ((Eina_Promise_Progress_Cb_Add_Cb)Function) + +/* + * @brief Function callback type for promise's cancel function override + */ +typedef void(*Eina_Promise_Cancel_Cb)(Eina_Promise* promise); + +#define EINA_FUNC_PROMISE_CANCEL(Function) ((Eina_Promise_Cancel_Cb)Function) + +/* + * @brief Function callback type for promise's ref function override + */ +typedef void(*Eina_Promise_Ref_Cb)(Eina_Promise* promise); + +#define EINA_FUNC_PROMISE_REF(Function) ((Eina_Promise_Ref_Cb)Function) + +/* + * @brief Function callback type for promise's unref function override + */ +typedef void(*Eina_Promise_Unref_Cb)(Eina_Promise* promise); + +#define EINA_FUNC_PROMISE_UNREF(Function) ((Eina_Promise_Unref_Cb)Function) + +/* + * @brief Function callback type for promise's buffer_get function override + */ +typedef void*(*Eina_Promise_Buffer_Get_Cb)(Eina_Promise* promise); + +#define EINA_FUNC_PROMISE_BUFFER_GET(Function) ((Eina_Promise_Buffer_Get_Cb)Function) + +/* + * @brief Function callback type for promise's value_size_get function override + */ +typedef size_t(*Eina_Promise_Value_Size_Get_Cb)(Eina_Promise const* promise); + +#define EINA_FUNC_PROMISE_VALUE_SIZE_GET(Function) ((Eina_Promise_Value_Size_Get_Cb)Function) + + +/* + * @brief Function callback type for promise owner's buffer_get function override + */ +typedef void*(*Eina_Promise_Owner_Buffer_Get_Cb)(Eina_Promise_Owner* promise); + +#define EINA_FUNC_PROMISE_OWNER_BUFFER_GET(Function) ((Eina_Promise_Owner_Buffer_Get_Cb)Function) + +/* + * @brief Function callback type for promise owner's value_size_get function override + */ +typedef size_t(*Eina_Promise_Owner_Value_Size_Get_Cb)(Eina_Promise_Owner const* promise); + +#define EINA_FUNC_PROMISE_OWNER_VALUE_SIZE_GET(Function) ((Eina_Promise_Owner_Value_Size_Get_Cb)Function) + +/* + * @brief Function callback type for promise owner's promise_get function override + */ +typedef void*(*Eina_Promise_Owner_Promise_Get_Cb)(Eina_Promise_Owner const* promise); + +#define EINA_FUNC_PROMISE_OWNER_PROMISE_GET(Function) ((Eina_Promise_Owner_Promise_Get_Cb)Function) + +/* + * @brief Function callback type for promise owner's value_set function override + */ +typedef void(*Eina_Promise_Owner_Value_Set_Cb)(Eina_Promise_Owner* promise, void* data, Eina_Promise_Free_Cb free_fun); + +#define EINA_FUNC_PROMISE_OWNER_VALUE_SET(Function) ((Eina_Promise_Owner_Value_Set_Cb)Function) + +/* + * @brief Function callback type for promise owner's error_set function override + */ +typedef void(*Eina_Promise_Owner_Error_Set_Cb)(Eina_Promise_Owner* promise, Eina_Error error); + +#define EINA_FUNC_PROMISE_OWNER_ERROR_SET(Function) ((Eina_Promise_Owner_Error_Set_Cb)Function) + +/* + * @brief Function callback type for promise owner's pending function override + */ +typedef Eina_Bool(*Eina_Promise_Owner_Pending_Is_Cb)(Eina_Promise_Owner const* promise); + +#define EINA_FUNC_PROMISE_OWNER_PENDING_IS(Function) ((Eina_Promise_Owner_Pending_Is_Cb)Function) + +/* + * @brief Function callback type for promise owner's cancelled function override + */ +typedef Eina_Bool(*Eina_Promise_Owner_Cancelled_Is_Cb)(Eina_Promise_Owner const* promise); + +#define EINA_FUNC_PROMISE_OWNER_CANCELLED_IS(Function) ((Eina_Promise_Owner_Cancelled_Is_Cb)Function) + +/* + * @brief Function callback type for promise owner's progress function override + */ +typedef Eina_Bool(*Eina_Promise_Owner_Progress_Cb)(Eina_Promise_Owner const* promise, void* progress); + +#define EINA_FUNC_PROMISE_OWNER_PROGRESS(Function) ((Eina_Promise_Owner_Progress_Cb)Function) + + +#define EINA_PROMISE_VERSION 1 + +struct _Eina_Promise +{ + int version; + Eina_Promise_Then_Cb then; + Eina_Promise_Value_Get_Cb value_get; + Eina_Promise_Error_Get_Cb error_get; + Eina_Promise_Pending_Is_Cb pending_is; + Eina_Promise_Progress_Cb_Add_Cb progress_cb_add; + Eina_Promise_Cancel_Cb cancel; + Eina_Promise_Ref_Cb ref; + Eina_Promise_Unref_Cb unref; + Eina_Promise_Value_Size_Get_Cb value_size_get; + Eina_Promise_Buffer_Get_Cb buffer_get; +#define EINA_MAGIC_PROMISE 0x07932A5B + EINA_MAGIC; +}; + +struct _Eina_Promise_Owner +{ + int version; + Eina_Promise_Owner_Value_Set_Cb value_set; + Eina_Promise_Owner_Error_Set_Cb error_set; + Eina_Promise_Owner_Buffer_Get_Cb buffer_get; + Eina_Promise_Owner_Value_Size_Get_Cb value_size_get; + Eina_Promise_Owner_Promise_Get_Cb promise_get; + Eina_Promise_Owner_Pending_Is_Cb pending_is; + Eina_Promise_Owner_Cancelled_Is_Cb cancelled_is; + Eina_Promise_Owner_Progress_Cb progress; +#define EINA_MAGIC_PROMISE_OWNER 0x07932A5C + EINA_MAGIC; +}; + +/* + * @brief Appends a callback to be called when the Eina_Promise is + * finished. + * + * @param promise The Eina_Promise to wait for + * @param callback Callback to be called when Eina_Promise is finished + * @param data Private data passed to the callback + */ +EAPI void eina_promise_then(Eina_Promise* promise, Eina_Promise_Cb callback, + Eina_Promise_Error_Cb error_cb, void* data); + +/* + * @brief Creates a new Eina_Promise from other Eina_Promises + * + * @param promises An Eina_Iterator for all Eina_Promises + * @return Returns a new Eina_Promise + */ +EAPI Eina_Promise* eina_promise_all(Eina_Iterator* promises); + +/* + * @brief Sets value for Eina_Promise_Owner + * + * This finishes the Promise and calls all eina_promise_then callbacks + * that have been registered on Eina_Promise. This function must be + * called only once per Eina_Promise_Owner + * + * @param promise The promise owner for which to set the value + * @param value The pointer to the value that is going to be copied, or NULL. + * @param free_cb Callback function to be used to free the value copied + */ +EAPI void eina_promise_owner_value_set(Eina_Promise_Owner* promise, void* value, Eina_Promise_Free_Cb free_cb); + +/* + * @brief Returns the pointer to the value + * + * If the Eina_Promise is not pending anymore and has not failed, + * returns the pointer to the value, otherwise returns NULL. + * + * @param promise The promise for which to get the value + * @return Value pointer or @NULL + */ +EAPI void* eina_promise_value_get(Eina_Promise const* promise); + +/* + * @brief Returns the pointer to the buffer that holds the value. + * + * If the promise is finished and has not failed, this function is the + * same as @eina_promise_value_get. Otherwise, instead of returning + * NULL as @eina_promise_value_get, this function always returns the + * buffer pointer to where the value will be hold. + * + * @param promise The promise for which to get the buffer pointer + * @return Buffer pointer + */ +EAPI void* eina_promise_buffer_get(Eina_Promise* promise); + +/* + * @brief Returns the pointer to the buffer that holds the value. + * + * This function always return the buffer pointer independently if the + * value has been set or not. This is useful to instantiate the value + * directly in the correct buffer, without needing to copy. Then the + * user can @eina_promise_owner_value_set with a NULL pointer for the + * value to avoid copying over the buffer. + * + * @param promise The promise owner for which to get the buffer pointer + * @return Buffer pointer + */ +EAPI void* eina_promise_owner_buffer_get(Eina_Promise_Owner* promise); + +/* + * @brief Sets an error to the Eina_Promise + * + * Sets an error to the promise, finishing the promise and calling all + * eina_promise_then callbacks registered. + * + * @param promise The promise owner for which to set the error + * @param error Eina_Error to be set + */ +EAPI void eina_promise_owner_error_set(Eina_Promise_Owner* promise, Eina_Error error); + +/* + * @brief Gets the error of the @Eina_Promise + * + * If the promise is finished and has been set with an error, it + * retuns the @Eina_Error, otherwise returns 0. + * + * @param promise The promise for which to get the error + * @return @Eina_Error set in @Eina_Promise + */ +EAPI Eina_Error eina_promise_error_get(Eina_Promise const* promise); + +/* + * @brief Gets the size of the value in eina_promise_value_get. + * + * @param promise The promise for which to get the value size + * @return The size of the value in eina_promise_value_get. + */ +EAPI size_t eina_promise_value_size_get(Eina_Promise const* promise); + +/* + * @brief Returns @EINA_TRUE if the promise is still pending and + * still waiting on a value to be set and @EINA_FALSE otherwise. + * + * @param promise The promise for which to get the pending status + * @return Returns @EINA_TRUE if the promise is still pending and + * still waiting on a value to be set and @EINA_FALSE otherwise. + */ +EAPI Eina_Bool eina_promise_pending_is(Eina_Promise const* promise); + +/* + * @brief Adds a progress callback that is called by the asynchronous + * call to inform of any progress made. + * + * @param promise The promise for which to register a progress callback + * @param progress The callback to be called when progress is made + * @param data The private data that will be passed to the progress callback + */ +EAPI void eina_promise_progress_cb_add(Eina_Promise* promise, Eina_Promise_Progress_Cb progress, void* data); + +/* + * @brief Increments the reference count for the Eina_Promise + * + * @param promise The promise for which to increment its reference + */ +EAPI void eina_promise_ref(Eina_Promise* promise); + +/* + * @brief Cancel asynchronous operation, if possible. + * + * @param promise The promise to cancel + */ +EAPI void eina_promise_cancel(Eina_Promise* promise); + +/* + * @brief Gets Promise from Promise_Owner + * + * This function returns an @Eina_Promise from an + * @Eina_Promise_Owner. The user of the asynchronous operation can + * query the value from the @Eina_Promise object, while the + * asynchronous operation should use the @Eina_Promise_Owner object to + * set the value, or error, and thus finish the promise. + * + * @param promise The promise owner to get promise from. + * @return Return the @Eina_Promise + */ +EAPI Eina_Promise* eina_promise_owner_promise_get(Eina_Promise_Owner* promise); + +/* + * @brief Returns @EINA_TRUE if the promise is still pending and + * still waiting on a value to be set and @EINA_FALSE otherwise. + * + * @param promise The promise owner for which to get the pending status + * @return Returns @EINA_TRUE if the promise is still pending and + * still waiting on a value to be set and @EINA_FALSE otherwise. + */ +EAPI Eina_Bool eina_promise_owner_pending_is(Eina_Promise_Owner const* promise); + +/* + * @brief Returns @EINA_TRUE if the promise was cancelled + * or @EINA_FALSE otherwise. + * + * @param promise The promise owner for which to get the cancelled status + * @return Returns @EINA_TRUE if the promise was cancelled + * or @EINA_FALSE otherwise. + */ +EAPI Eina_Bool eina_promise_owner_cancelled_is(Eina_Promise_Owner const* promise); + +/* + * @brief Calls progress callbacks in promise, if any exists, with + * the data. + * + * The progress callbacks registered in @Eina_Promise must not free + * the progress data pointer. The data pointer ownership must be dealt + * by the @Eina_Promise_Owner's user. + * + * @param promise The promise for which to get the cancelled status + * @param data The data to be passed to progress + */ +EAPI void eina_promise_owner_progress(Eina_Promise_Owner const* promise, void* progress); + +/* + * @brief Decrement the reference count for the Eina_Promise. + + * The Eina_Promise, if its reference count drops to zero and is not + * pending, will be free'd immediately. + * + * @param promise The promise for which to decrement its reference + */ +EAPI void eina_promise_unref(Eina_Promise* promise); + +/* + * @brief Function callback type when promise is canceled + */ +typedef void(*Eina_Promise_Default_Cancel_Cb)(void* data, Eina_Promise_Owner* promise); + +/* + * @brief Creates a @Eina_Promise_Owner + * + * Create a @Eina_Promise_Owner with a value of size value_size. Which + * is a promise with ownership of the value to be set. It is used by + * the asynchronous operation to set the actual value when it becomes + * available. The Promise itself, returned by + * eina_promise_owner_promise_get, represents the asynchronicity of + * the value itself and is used solely to get the value and to handle + * users of the asynchronous value. That's why Promises have a + * reference count while Promise Owners do not, the + * eina_promise_owner_value_set must be done only once, and + * consequently, has a unique ownership of the owner lifetime, while + * the promise can be queried and used by multiple users. + * + * @param value_size Size of value-type that Eina_Promise will hold + * @return @Eina_Promise_Owner just instantiated + */ +EAPI Eina_Promise_Owner* eina_promise_default_add(int value_size); + +/* + * @brief Adds a cancel callback to be called when the promise is + * canceled by the usuer + * + * @param promise The promise for which to register a cancel callback + */ +EAPI void eina_promise_owner_default_cancel_cb_add( + Eina_Promise_Owner* promise, Eina_Promise_Default_Cancel_Cb cancel, void* data, + Eina_Promise_Free_Cb free_cb); + +/* + * @brief Commands the @Eina_Promise_Owner not to call the then + * callbacks automatically + * + * @param promise The promise for which to register a cancel callback + */ +EAPI void eina_promise_owner_default_manual_then_set(Eina_Promise_Owner* promise, Eina_Bool is_manual); + +/* + * @brief Calls the @Eina_Promise_Owner's then callbacks already registered + * + * @param promise The promise for which to register a cancel callback + */ +EAPI void eina_promise_owner_default_call_then(Eina_Promise_Owner* promise); + +#endif