aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelipe Magno de Almeida <felipe@expertisesolutions.com.br>2016-04-17 15:47:33 -0300
committerFelipe Magno de Almeida <felipe@expertisesolutions.com.br>2016-04-17 16:15:14 -0300
commit3ee910942cc4bcabd2b6b8a0aef3ab4f6604cfa3 (patch)
tree3ef4a863f2d78adf727960610d124a68e5f50cd8
parentEo: Silence warning about no side-effect in _eo_add_common (diff)
downloadefl-devs/felipealmeida/promises.tar.gz
eina: Add progress notify callback feature for Promise Ownersdevs/felipealmeida/promises
Add a way for users of the promise owner to get notified when a promise progress is registered
-rw-r--r--src/lib/eina/eina_promise.c64
-rw-r--r--src/lib/eina/eina_promise.h27
-rw-r--r--src/tests/eina/eina_test_promise.c50
3 files changed, 141 insertions, 0 deletions
diff --git a/src/lib/eina/eina_promise.c b/src/lib/eina/eina_promise.c
index 459f686e84..768f2596ca 100644
--- a/src/lib/eina/eina_promise.c
+++ b/src/lib/eina/eina_promise.c
@@ -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;
}
@@ -643,3 +700,10 @@ 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);
+}
diff --git a/src/lib/eina/eina_promise.h b/src/lib/eina/eina_promise.h
index 9093b92767..954e89a41f 100644
--- a/src/lib/eina/eina_promise.h
+++ b/src/lib/eina/eina_promise.h
@@ -20,6 +20,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
*/
typedef void(*Eina_Promise_Cb)(void* data, void* value);
@@ -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;
};
@@ -379,6 +393,19 @@ 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.
+ *
+ * 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_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.
* The Eina_Promise, if its reference count drops to zero and is not
diff --git a/src/tests/eina/eina_test_promise.c b/src/tests/eina/eina_test_promise.c
index 59ed7d7b0f..696ecc26e0 100644
--- a/src/tests/eina/eina_test_promise.c
+++ b/src/tests/eina/eina_test_promise.c
@@ -236,6 +236,54 @@ 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
+
void
eina_test_promise(TCase *tc)
{
@@ -246,4 +294,6 @@ 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);
}