forked from enlightenment/efl
eina: Add progress notify callback feature for Promise Owners
Add a way for users of the promise owner to get notified when a promise progress is registered. Also added a convenience composition function that creates a promise which is fulfilled when another promise has a progress notification.
This commit is contained in:
parent
8df2686d90
commit
236c13df34
|
@ -87,6 +87,7 @@ static int _eina_main_count = 0;
|
|||
static int _eina_main_thread_count = 0;
|
||||
#endif
|
||||
static int _eina_log_dom = -1;
|
||||
void _eina_promise_init(void);
|
||||
|
||||
#ifdef ERR
|
||||
#undef ERR
|
||||
|
@ -299,6 +300,8 @@ eina_init(void)
|
|||
}
|
||||
}
|
||||
|
||||
_eina_promise_init();
|
||||
|
||||
eina_cpu_count_internal();
|
||||
|
||||
eina_log_timing(_eina_log_dom, EINA_LOG_STATE_STOP, EINA_LOG_STATE_INIT);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
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_Owner_Progress_Notify_Data _Eina_Promise_Owner_Progress_Notify_Data;
|
||||
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;
|
||||
|
@ -40,6 +41,15 @@ struct _Eina_Promise_Cancel_Cb
|
|||
void* data;
|
||||
};
|
||||
|
||||
struct _Eina_Promise_Owner_Progress_Notify_Data
|
||||
{
|
||||
EINA_INLIST;
|
||||
|
||||
Eina_Promise_Progress_Notify_Cb callback;
|
||||
Eina_Promise_Free_Cb free_cb;
|
||||
void* data;
|
||||
};
|
||||
|
||||
struct _Eina_Promise_Default
|
||||
{
|
||||
Eina_Promise vtable;
|
||||
|
@ -49,6 +59,7 @@ struct _Eina_Promise_Default
|
|||
Eina_Inlist *then_callbacks;
|
||||
Eina_Inlist *progress_callbacks;
|
||||
Eina_Inlist *cancel_callbacks;
|
||||
Eina_Inlist *progress_notify_callbacks;
|
||||
Eina_Promise_Free_Cb value_free_cb;
|
||||
|
||||
int ref;
|
||||
|
@ -89,6 +100,21 @@ 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_free_callback_list(Eina_Inlist** list, void(*free_cb)(void* node))
|
||||
{
|
||||
struct node
|
||||
{
|
||||
EINA_INLIST;
|
||||
} *node;
|
||||
Eina_Inlist *list2;
|
||||
|
||||
EINA_INLIST_FOREACH_SAFE(*list, list2, node)
|
||||
{
|
||||
free_cb(node);
|
||||
}
|
||||
*list = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
_eina_promise_then_calls(_Eina_Promise_Default_Owner* promise)
|
||||
{
|
||||
|
@ -188,6 +214,7 @@ _eina_promise_then(_Eina_Promise_Default* p, Eina_Promise_Cb callback,
|
|||
{
|
||||
_Eina_Promise_Default_Owner* promise;
|
||||
_Eina_Promise_Then_Cb* cb;
|
||||
_Eina_Promise_Owner_Progress_Notify_Data* notify_data;
|
||||
|
||||
promise = EINA_PROMISE_GET_OWNER(p);
|
||||
|
||||
|
@ -198,6 +225,12 @@ _eina_promise_then(_Eina_Promise_Default* p, Eina_Promise_Cb callback,
|
|||
cb->data = data;
|
||||
promise->promise.then_callbacks = eina_inlist_append(promise->promise.then_callbacks, EINA_INLIST_GET(cb));
|
||||
|
||||
EINA_INLIST_FOREACH(promise->promise.progress_notify_callbacks, notify_data)
|
||||
{
|
||||
(*notify_data->callback)(notify_data->data, &promise->owner_vtable);
|
||||
}
|
||||
_eina_promise_free_callback_list(&promise->promise.progress_notify_callbacks, &free);
|
||||
|
||||
if (!promise->promise.is_first_then)
|
||||
{
|
||||
_eina_promise_ref(p);
|
||||
|
@ -263,11 +296,19 @@ static void
|
|||
_eina_promise_progress_cb_add(_Eina_Promise_Default* promise, Eina_Promise_Progress_Cb callback, void* data)
|
||||
{
|
||||
_Eina_Promise_Progress_Cb* cb;
|
||||
_Eina_Promise_Owner_Progress_Notify_Data* notify_data;
|
||||
_Eina_Promise_Default_Owner* owner = EINA_PROMISE_GET_OWNER(promise);
|
||||
|
||||
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));
|
||||
|
||||
EINA_INLIST_FOREACH(owner->promise.progress_notify_callbacks, notify_data)
|
||||
{
|
||||
(*notify_data->callback)(notify_data->data, &owner->owner_vtable);
|
||||
}
|
||||
_eina_promise_free_callback_list(&owner->promise.progress_notify_callbacks, &free);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -356,6 +397,20 @@ _eina_promise_owner_progress(_Eina_Promise_Default_Owner* promise, void* data)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_eina_promise_owner_progress_notify(_Eina_Promise_Default_Owner* promise, Eina_Promise_Progress_Notify_Cb notify,
|
||||
void* data, Eina_Promise_Free_Cb free_cb)
|
||||
{
|
||||
_Eina_Promise_Owner_Progress_Notify_Data* cb
|
||||
= malloc(sizeof(struct _Eina_Promise_Owner_Progress_Notify_Data));
|
||||
|
||||
cb->callback = notify;
|
||||
cb->free_cb = free_cb;
|
||||
cb->data = data;
|
||||
promise->promise.progress_notify_callbacks =
|
||||
eina_inlist_append(promise->promise.progress_notify_callbacks, EINA_INLIST_GET(cb));
|
||||
}
|
||||
|
||||
Eina_Promise_Owner *
|
||||
eina_promise_default_add(int value_size)
|
||||
{
|
||||
|
@ -378,6 +433,7 @@ eina_promise_default_add(int value_size)
|
|||
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.progress_notify_callbacks, 0, sizeof(p->promise.progress_notify_callbacks));
|
||||
memset(&p->promise.cancel_callbacks, 0, sizeof(p->promise.cancel_callbacks));
|
||||
p->promise.value_size = value_size;
|
||||
p->promise.value_free_cb = NULL;
|
||||
|
@ -392,6 +448,7 @@ eina_promise_default_add(int value_size)
|
|||
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);
|
||||
p->owner_vtable.progress_notify = EINA_FUNC_PROMISE_OWNER_PROGRESS_NOTIFY(_eina_promise_owner_progress_notify);
|
||||
|
||||
return &p->owner_vtable;
|
||||
}
|
||||
|
@ -540,6 +597,36 @@ _eina_promise_iterator_setup(_Eina_Promise_Iterator* it, Eina_Array* promises_ar
|
|||
it->data.success_iterator_impl.free = FUNC_ITERATOR_FREE(_eina_promise_iterator_free);
|
||||
}
|
||||
|
||||
static void
|
||||
_eina_promise_progress_notify_fulfilled(void* data, Eina_Promise_Owner* p EINA_UNUSED)
|
||||
{
|
||||
Eina_Promise_Owner* owner = data;
|
||||
eina_promise_owner_value_set(owner, NULL, NULL);
|
||||
}
|
||||
|
||||
EAPI Eina_Error EINA_ERROR_PROMISE_NO_NOTIFY;
|
||||
|
||||
static void
|
||||
_eina_promise_progress_notify_failed(void* data)
|
||||
{
|
||||
Eina_Promise_Owner* owner = data;
|
||||
if(eina_promise_owner_pending_is(owner))
|
||||
eina_promise_owner_error_set(owner, EINA_ERROR_PROMISE_NO_NOTIFY);
|
||||
}
|
||||
|
||||
EAPI Eina_Promise*
|
||||
eina_promise_progress_notification(Eina_Promise_Owner* promise)
|
||||
{
|
||||
Eina_Promise_Owner* owner;
|
||||
|
||||
owner = eina_promise_default_add(0);
|
||||
|
||||
eina_promise_owner_progress_notify(promise, &_eina_promise_progress_notify_fulfilled, owner,
|
||||
&_eina_promise_progress_notify_failed);
|
||||
|
||||
return eina_promise_owner_promise_get(owner);
|
||||
}
|
||||
|
||||
// API functions
|
||||
EAPI void
|
||||
eina_promise_then(Eina_Promise* promise, Eina_Promise_Cb callback,
|
||||
|
@ -643,3 +730,17 @@ eina_promise_owner_progress(Eina_Promise_Owner const* promise, void* progress)
|
|||
{
|
||||
promise->progress(promise, progress);
|
||||
}
|
||||
|
||||
EAPI void
|
||||
eina_promise_owner_progress_notify(Eina_Promise_Owner* promise, Eina_Promise_Progress_Notify_Cb progress_cb,
|
||||
void* data, Eina_Promise_Free_Cb free_cb)
|
||||
{
|
||||
promise->progress_notify(promise, progress_cb, data, free_cb);
|
||||
}
|
||||
|
||||
static const char EINA_ERROR_PROMISE_NO_NOTIFY_STR[] = "Out of memory";
|
||||
|
||||
void _eina_promise_init()
|
||||
{
|
||||
EINA_ERROR_PROMISE_NO_NOTIFY = eina_error_msg_static_register(EINA_ERROR_PROMISE_NO_NOTIFY_STR);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,11 @@ typedef struct _Eina_Promise_Owner Eina_Promise_Owner;
|
|||
*/
|
||||
typedef void(*Eina_Promise_Free_Cb)(void* value);
|
||||
|
||||
/*
|
||||
* @brief Callback type for Promise_Owner to get notified of when someone registered a progress and/or then callback
|
||||
*/
|
||||
typedef void(*Eina_Promise_Progress_Notify_Cb)(void* data, Eina_Promise_Owner* promise);
|
||||
|
||||
/*
|
||||
* @brief Function callback type for when using eina_promise_then
|
||||
*/
|
||||
|
@ -162,6 +167,14 @@ typedef Eina_Bool(*Eina_Promise_Owner_Progress_Cb)(Eina_Promise_Owner const* pro
|
|||
|
||||
#define EINA_FUNC_PROMISE_OWNER_PROGRESS(Function) ((Eina_Promise_Owner_Progress_Cb)Function)
|
||||
|
||||
/*
|
||||
* @brief Function callback type for promise owner's progress notify registration function override
|
||||
*/
|
||||
typedef Eina_Bool(*Eina_Promise_Owner_Progress_Notify_Cb)(Eina_Promise_Owner* promise,
|
||||
Eina_Promise_Progress_Notify_Cb progress_cb, void* data, Eina_Promise_Free_Cb free_cb);
|
||||
|
||||
#define EINA_FUNC_PROMISE_OWNER_PROGRESS_NOTIFY(Function) ((Eina_Promise_Owner_Progress_Notify_Cb)Function)
|
||||
|
||||
|
||||
#define EINA_PROMISE_VERSION 1
|
||||
|
||||
|
@ -193,6 +206,7 @@ struct _Eina_Promise_Owner
|
|||
Eina_Promise_Owner_Pending_Is_Cb pending_is;
|
||||
Eina_Promise_Owner_Cancelled_Is_Cb cancelled_is;
|
||||
Eina_Promise_Owner_Progress_Cb progress;
|
||||
Eina_Promise_Owner_Progress_Notify_Cb progress_notify;
|
||||
#define EINA_MAGIC_PROMISE_OWNER 0x07932A5C
|
||||
EINA_MAGIC;
|
||||
};
|
||||
|
@ -216,6 +230,15 @@ EAPI void eina_promise_then(Eina_Promise* promise, Eina_Promise_Cb callback,
|
|||
*/
|
||||
EAPI Eina_Promise* eina_promise_all(Eina_Iterator* promises);
|
||||
|
||||
/*
|
||||
* @brief Creates a new @Eina_Promise from another @Eina_Promise_Owner which
|
||||
* is fulfilled when @promise has a progress callback registered
|
||||
*
|
||||
* @param promise Promise Owner which to be waited for a progress callback register
|
||||
* @return Returns a new Eina_Promise
|
||||
*/
|
||||
EAPI Eina_Promise* eina_promise_progress_notification(Eina_Promise_Owner* promise);
|
||||
|
||||
/*
|
||||
* @brief Sets value for Eina_Promise_Owner
|
||||
*
|
||||
|
@ -378,6 +401,20 @@ EAPI Eina_Bool eina_promise_owner_cancelled_is(Eina_Promise_Owner const* promise
|
|||
*/
|
||||
EAPI void eina_promise_owner_progress(Eina_Promise_Owner const* promise, void* progress);
|
||||
|
||||
/*
|
||||
* @brief Registers a progress notify callbacks in promise owner.
|
||||
*
|
||||
* Registers a callback to be called for when a progress callback is
|
||||
* registered by the linked @Eina_Promise.
|
||||
*
|
||||
* @param promise The promise for which to get the cancelled status
|
||||
* @param notify_cb The callback to be called
|
||||
* @param data The data to be passed to progress notify callback
|
||||
* @param free_cb The free function that is called for the data param
|
||||
*/
|
||||
EAPI void eina_promise_owner_progress_notify(Eina_Promise_Owner* promise,
|
||||
Eina_Promise_Progress_Notify_Cb notify_cb, void* data, Eina_Promise_Free_Cb free_cb);
|
||||
|
||||
/*
|
||||
* @brief Decrement the reference count for the Eina_Promise.
|
||||
|
||||
|
@ -438,6 +475,13 @@ EAPI void eina_promise_owner_default_manual_then_set(Eina_Promise_Owner* promise
|
|||
*/
|
||||
EAPI void eina_promise_owner_default_call_then(Eina_Promise_Owner* promise);
|
||||
|
||||
/**
|
||||
* @var EINA_ERROR_PROMISE_NO_NOTIFY
|
||||
*
|
||||
* @brief The error identifier corresponding to when a promise was
|
||||
* free'd before any progress callback was registered
|
||||
*/
|
||||
EAPI extern Eina_Error EINA_ERROR_PROMISE_NO_NOTIFY;
|
||||
|
||||
/*
|
||||
* @internal
|
||||
|
|
|
@ -236,6 +236,90 @@ START_TEST(eina_test_promise_progress)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
static void progress_notify(void* data, Eina_Promise_Owner* promise EINA_UNUSED)
|
||||
{
|
||||
ck_assert(!*(Eina_Bool*)data);
|
||||
*(Eina_Bool*)data = EINA_TRUE;
|
||||
}
|
||||
|
||||
START_TEST(eina_test_promise_progress_notify1)
|
||||
{
|
||||
Eina_Bool progress_notify_ran = EINA_FALSE;
|
||||
Eina_Promise_Owner* owner;
|
||||
Eina_Promise* promise;
|
||||
|
||||
eina_init();
|
||||
|
||||
owner = eina_promise_default_add(0);
|
||||
eina_promise_owner_progress_notify(owner, &progress_notify, &progress_notify_ran, NULL);
|
||||
|
||||
promise = eina_promise_owner_promise_get(owner);
|
||||
eina_promise_progress_cb_add(promise, &progress_callback, NULL); // never run
|
||||
eina_promise_progress_cb_add(promise, &progress_callback, NULL); // never run
|
||||
|
||||
ck_assert(progress_notify_ran);
|
||||
|
||||
eina_shutdown();
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(eina_test_promise_progress_notify2)
|
||||
{
|
||||
Eina_Bool progress_notify_ran = EINA_FALSE;
|
||||
Eina_Promise_Owner* owner;
|
||||
Eina_Promise* promise;
|
||||
|
||||
eina_init();
|
||||
|
||||
owner = eina_promise_default_add(0);
|
||||
eina_promise_owner_progress_notify(owner, &progress_notify, &progress_notify_ran, NULL);
|
||||
|
||||
promise = eina_promise_owner_promise_get(owner);
|
||||
eina_promise_then(promise, NULL, &_cancel_promise_callback, NULL); // never run
|
||||
eina_promise_then(promise, NULL, &_cancel_promise_callback, NULL); // never run
|
||||
|
||||
ck_assert(progress_notify_ran);
|
||||
|
||||
eina_shutdown();
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static void
|
||||
_eina_promise_progress_notify_fulfilled(void* data, void* value EINA_UNUSED)
|
||||
{
|
||||
*(Eina_Bool*)data = EINA_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_eina_promise_progress_notify_error(void* data EINA_UNUSED, Eina_Error const* error EINA_UNUSED)
|
||||
{
|
||||
ck_assert(EINA_FALSE);
|
||||
}
|
||||
|
||||
START_TEST(eina_test_promise_progress_notify3)
|
||||
{
|
||||
Eina_Bool progress_notify_ran = EINA_FALSE;
|
||||
Eina_Promise_Owner* owner;
|
||||
Eina_Promise* promise;
|
||||
Eina_Promise* promise_progress;
|
||||
|
||||
eina_init();
|
||||
|
||||
owner = eina_promise_default_add(0);
|
||||
promise_progress = eina_promise_progress_notification(owner);
|
||||
eina_promise_then(promise_progress, &_eina_promise_progress_notify_fulfilled,
|
||||
&_eina_promise_progress_notify_error, &progress_notify_ran);
|
||||
|
||||
promise = eina_promise_owner_promise_get(owner);
|
||||
eina_promise_progress_cb_add(promise, &progress_callback, NULL); // never run
|
||||
eina_promise_progress_cb_add(promise, &progress_callback, NULL); // never run
|
||||
|
||||
ck_assert(progress_notify_ran);
|
||||
|
||||
eina_shutdown();
|
||||
}
|
||||
END_TEST
|
||||
|
||||
void
|
||||
eina_test_promise(TCase *tc)
|
||||
{
|
||||
|
@ -246,4 +330,7 @@ eina_test_promise(TCase *tc)
|
|||
tcase_add_test(tc, eina_test_promise_values_all);
|
||||
tcase_add_test(tc, eina_test_promise_cancel_promise);
|
||||
tcase_add_test(tc, eina_test_promise_progress);
|
||||
tcase_add_test(tc, eina_test_promise_progress_notify1);
|
||||
tcase_add_test(tc, eina_test_promise_progress_notify2);
|
||||
tcase_add_test(tc, eina_test_promise_progress_notify3);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue