summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCedric BAIL <cedric@osg.samsung.com>2017-06-29 16:48:03 -0700
committerCedric BAIL <cedric@osg.samsung.com>2017-06-29 16:48:03 -0700
commitdd6c93cb2358b35cbc8ba90189ddae9d9f4d702f (patch)
tree94bcb2b35172500e056afe3a014c7b04e2b783c8
parentc1331adbdc65788c29567009ffa60353aa1959ab (diff)
downloadefl-devs/cedric/future.tar.gz
eo: work in progress with new future.devs/cedric/future
-rw-r--r--src/lib/eo/efl_future.c324
-rw-r--r--src/lib/eo/efl_future.h100
2 files changed, 333 insertions, 91 deletions
diff --git a/src/lib/eo/efl_future.c b/src/lib/eo/efl_future.c
index aaa1d88a51..71e402af4e 100644
--- a/src/lib/eo/efl_future.c
+++ b/src/lib/eo/efl_future.c
@@ -5,52 +5,316 @@
#include <Eina.h>
#include "Eo.h"
-// Efl.Future implementation is an opaque type in Ecore.
-EOAPI const Efl_Event_Description _EFL_FUTURE_EVENT_FAILURE =
- EFL_EVENT_DESCRIPTION("future,failure");
-EOAPI const Efl_Event_Description _EFL_FUTURE_EVENT_SUCCESS =
- EFL_EVENT_DESCRIPTION("future,success");
-EOAPI const Efl_Event_Description _EFL_FUTURE_EVENT_PROGRESS =
- EFL_EVENT_DESCRIPTION("future,progress");
-
-EOAPI EFL_FUNC_BODYV(efl_future_then, Efl_Future *, 0, EFL_FUNC_CALL(success, failure, progress, data), Efl_Event_Cb success, Efl_Event_Cb failure, Efl_Event_Cb progress, const void *data);
-EOAPI EFL_VOID_FUNC_BODY(efl_future_cancel);
-
-static Eina_Bool
-_efl_future_class_initializer(Efl_Class *klass)
-{
- EFL_OPS_DEFINE(ops,
- EFL_OBJECT_OP_FUNC(efl_future_then, NULL),
- EFL_OBJECT_OP_FUNC(efl_future_cancel, NULL));
-
- return efl_class_functions_set(klass, &ops, NULL);
-}
-
-static const Efl_Class_Description _efl_future_class_desc = {
- EO_VERSION,
- "Efl.Future",
- EFL_CLASS_TYPE_REGULAR_NO_INSTANT,
- 0,
- _efl_future_class_initializer,
- NULL,
- NULL
+typedef struct _Efl_Future_Chain Efl_Future_Chain;
+typedef struct _Efl_Future_Steal Efl_Future_Steal;
+
+struct _Efl_Future_Chain
+{
+ EINA_INLIST;
+
+ Efl_Promise *next;
+
+ Efl_Future_Success_Cb success;
+ Efl_Future_Failure_Cb failure;
+ Efl_Future_Progress_Cb progress;
+
+ void *data;
};
-EFL_DEFINE_CLASS(efl_future_class_get, &_efl_future_class_desc, EFL_OBJECT_CLASS, NULL);
+struct _Efl_Future_Steal
+{
+ Efl_Promise *next;
+
+ Efl_Future_Success_Steal_Cb success;
+ Efl_Future_Failure_Cb failure;
+ Efl_Future_Progress_Cb progress;
+
+ void *data;
+};
+
+struct _Efl_Future
+{
+ Eina_Inlist *chains_start;
+
+ Efl_Future_Steal *stealer;
+
+ Efl_Future ***wrefs;
+
+ Eo *parent;
+
+ struct {
+ Efl_Future_Value *value;
+ Eina_Error error;
+ } hold;
+
+ Eina_Bool loop_iterated : 1;
+ Eina_Bool data : 1;
+ Eina_Bool error : 1;
+};
+
+static Eina_Mempool *mpf = NULL;
+static Eina_Mempool *mpfc = NULL;
+
+static Efl_Class *promise = NULL;
static const char EINA_ERROR_FUTURE_CANCEL_STR[] = "Future cancelled";
EAPI Eina_Error EINA_ERROR_FUTURE_CANCEL;
+static inline Eina_Bool
+efl_future_check(Efl_Future *f)
+{
+#ifdef DEBUG
+ return eina_mempool_from(mpf, f);
+#endif
+ return EINA_TRUE;
+}
+
+EAPI Efl_Future *
+efl_future_add(Eo *parent)
+{
+ Efl_Future *f;
+
+ f = eina_mempool_malloc(mpf, sizeof (Efl_Future));
+ if (!f) return NULL;
+
+ f->chains_start = NULL;
+ f->stealer = NULL;
+ f->wrefs = NULL;
+ f->loop_iterated = EINA_FALSE;
+ f->data = EINA_FALSE;
+ f->error = EINA_FALSE;
+
+ // FIXME: Track lifetime of parent
+ f->parent = parent;
+
+ return f;
+}
+
+EAPI Efl_Future *
+efl_future_then(Efl_Future *f,
+ Efl_Future_Success_Cb success,
+ Efl_Future_Failure_Cb failure,
+ Efl_Future_Progress_Cb progress,
+ void *data)
+{
+ Efl_Future_Chain *fc;
+
+ if (!promise)
+ {
+ ERR("Initialization of Future hasn't been done properly");
+ return NULL;
+ }
+
+ if (!efl_future_check(f)) return NULL;
+
+ fc = eina_mempool_malloc(mpfc, sizeof (Efl_Future_Chain));
+ if (!fc) return NULL;
+
+ fc->next = efl_add(promise, f->parent);
+ if (!fc->next) goto on_error;
+
+ fc->success = success;
+ fc->failure = failure;
+ fc->progress = progress;
+ fc->data = data;
+
+ f->chains_start = eina_inlist_append(f->chains_start, EINA_INLIST_GET(fc));
+
+ return efl_promise_future_get(fc->next);
+}
+
+EAPI Efl_Future *
+efl_future_steal_then(Efl_Future *f,
+ Efl_Future_Success_Steal_Cb success,
+ Efl_Future_Failure_Cb failure,
+ Efl_Future_Progress_Cb progress,
+ void *data)
+{
+ Efl_Future_Steal *stealer;
+
+ if (!efl_future_check(f)) return NULL;
+ if (f->stealer)
+ {
+ ERR("There is already a stealing callback pair registered on future %p. There can only be one.", f);
+ return NULL;
+ }
+ // FIXME: Check promise parent to see if there is already a stealer there
+
+ stealer = eina_mempool_malloc(mpfs, sizeof (Efl_Future_Steal));
+ if (!stealer) return NULL;
+
+ stealer->next = efl_add(promise, f->parent);
+ if (!stealer->next) goto on_error;
+
+ stealer->success = success;
+ stealer->failure = failure;
+ stealer->progress = progress;
+ stealer->data = data;
+
+ f->stealer = stealer;
+
+ return efl_promise_future_get(stealer->next);
+}
+
+EAPI void
+efl_future_cancel(Efl_Future *f)
+{
+ efl_future_error_set(f, EINA_ERROR_FUTURE_CANCEL);
+}
+
+EAPI void
+efl_future_use(Efl_Future **storage, Efl_Future *future)
+{
+ unsigned int count = 0;
+ Efl_Future ***tmp;
+
+ if (!efl_future_check(f)) return NULL;
+
+ if (future->wrefs)
+ {
+ for (; future->wrefs[count]; count++)
+ ;
+ }
+ count++; /* New wref */
+
+ tmp = realloc(future->wrefs, sizeof (Efl_Future **) * (count + 1));
+ if (tmp)
+ {
+ future->wrefs = tmp;
+ future->wrefs[count - 1] = storage;
+ future->wrefs[count] = NULL;
+ *storage = future;
+ }
+}
+
+EAPI void
+efl_future_propagate(Efl_Future *f)
+{
+ Efl_Future_Chain *fc;
+
+ EINA_INLIST_FREE(f->chains_start, fc)
+ {
+ if (f->error) fc->failure(fc->data, fc->next, f->hold.error);
+ else fc->success(fc->data, fc->next, f->hold.value->data);
+ eina_mempool_free(mpfc, fc);
+ }
+
+ if (f->stealer)
+ {
+ if (EINA_REFCOUNT_GET(f->hold.value->data) > 1)
+ {
+ ERR("Future %p should have been called to propagate value the last, but hasn't.", f);
+ goto on_error;
+ }
+
+ if (f->error) f->stealer->failure(f->stealer->data, f->stealer->next, f->hold.error);
+ else f->stealer->success(f->stealer->data, f->stealer->next, f->hold.value->data);
+
+ eina_mempool_free(mpfs, f->stealer);
+ f->stealer = NULL;
+
+ // No need to free the value has it has been stolen.
+ }
+ else
+ {
+ on_error:
+ EINA_REFCOUNT_UNREF(f->hold.value)
+ {
+ }
+ }
+}
+
+EAPI Efl_Future_Value *
+efl_future_value_new(void *data, Eina_Free_Cb cb)
+{
+
+}
+
+EAPI void
+efl_future_value_free(Efl_Future_Value *value)
+{
+ if (value->cb)
+ value->cb(value->data);
+ eina_mempool_free(mpv, value);
+ value = NULL;
+}
+
+EAPI Eina_Bool
+efl_future_loop_iteration(Efl_Future *f)
+{
+ f->loop_iterated = EINA_TRUE;
+
+ if (f->data || f->error) return EINA_TRUE;
+ return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+efl_future_data_set(Efl_Future *f, Efl_Future_Value *value)
+{
+ if (f->data || f->error)
+ {
+ ERR("Failed to set data on %f which is already finalized.", f);
+ return EINA_FALSE;
+ }
+
+ f->data = EINA_TRUE;
+ f->hold.value = value;
+ EINA_REFCOUNT_REF(f->hold.value);
+
+ if (!f->loop_iterated) return EINA_FALSE;
+ return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+efl_future_error_set(Efl_Future *f, Eina_Error error)
+{
+ f->error = EINA_TRUE;
+ f->hold.error = error;
+
+ if (!f->loop_iterated) return EINA_FALSE;
+ return EINA_TRUE;
+}
+
+EAPI void
+efl_future_prepare(Efl_Future *f)
+{
+ unsigned int i;
+
+ if (f->wrefs == NULL) return ;
+
+ // Clears up all reference
+ for (i = 0; f->wrefs[i]; i++)
+ *f->wrefs[i] = NULL;
+}
+
+EAPI void
+efl_future_promise_class_set(Efl_Class *p)
+{
+ promise = p;
+}
+
Eina_Bool
efl_future_init(void)
{
EINA_ERROR_FUTURE_CANCEL = eina_error_msg_static_register(EINA_ERROR_FUTURE_CANCEL_STR);
+ mpf = eina_mempool_add("chained_mempool", "test", NULL, sizeof (Efl_Future), 64);
+ mpfc = eina_mempool_add("chained_mempool", "test", NULL, sizeof (Efl_Future_Chain), 64);
+ mpfs = eina_mempool_add("chained_mempool", "test", NULL, sizeof (Efl_Future_Steal), 64);
return EINA_TRUE;
}
Eina_Bool
efl_future_shutdown(void)
{
+ eina_mempool_del(mpf);
+ mpf = NULL;
+
+ eina_mempool_del(mpfc);
+ mpfc = NULL;
+
+ eina_mempool_del(mpfs);
+ mpfs = NULL;
+
return EINA_TRUE;
}
diff --git a/src/lib/eo/efl_future.h b/src/lib/eo/efl_future.h
index 34c5d2dcaf..ce55228dbc 100644
--- a/src/lib/eo/efl_future.h
+++ b/src/lib/eo/efl_future.h
@@ -13,75 +13,51 @@
typedef Eo Efl_Promise;
#define _EFL_PROMISE_EO_CLASS_TYPE
-#define EFL_FUTURE_CLASS efl_future_class_get()
-EWAPI const Efl_Class *efl_future_class_get(void); /**< @since 1.19 */
+typedef struct _Efl_Future Efl_Future;
-/**
- * @var EINA_ERROR_FUTURE_CANCEL
- * @brief The error identifier corresponding to a future being canceled.
- */
EAPI extern Eina_Error EINA_ERROR_FUTURE_CANCEL; /**< @since 1.19 */
-/** Parameter passed in event callbacks in case of future failure to proceed.
- *
- * @ingroup Efl_Future
- */
-typedef struct _Efl_Future_Event_Failure Efl_Future_Event_Failure;
-struct _Efl_Future_Event_Failure
-{
- Efl_Promise *next; /** The promise to the next future. Allowing to send a processed value down the chain. */
- Eina_Error error; /** The error generated trying to process the request. */
-};
+typedef void (*Efl_Future_Success_Cb)(void *data, Efl_Promise *next, const void *value);
+typedef void (*Efl_Future_Success_Steal_Cb)(void *data, Efl_Promise *next, void *value);
+typedef void (*Efl_Future_Failure_Cb)(void *data, Efl_Promise *next, Eina_Error error);
+typedef void (*Efl_Future_Progress_Cb)(void *data, Efl_Promise *next, const void *progress);
-/** Parameter passed in event callbacks in case of future succeeding to proceed.
+/**
+ * @brief Add sets of callbacks to handle the progress and result of a future.
*
- * @ingroup Efl_Future
- */
-typedef struct _Efl_Future_Event_Success Efl_Future_Event_Success;
-struct _Efl_Future_Event_Success
-{
- Efl_Promise *next; /** The promise to the next future. Allowing to send a processed value down the chain. */
- void *value; /** The value return by the processed request. The type is defined by the function executing the request. */
-};
-
-/** Parameter passed in event callbacks while a future is progressing a request.
+ * callbacks are called depending on the outcome of the promise related to the future.
*
- * @ingroup Efl_Future
- */
-typedef struct _Efl_Future_Event_Progress Efl_Future_Event_Progress;
-struct _Efl_Future_Event_Progress
-{
- Efl_Promise *next; /** The promise to the next future. Allowing to send a processed progress down the chain. */
- const void *progress; /** The progress status updated by the processed request. The type is defined by the function executing the request. */
-};
-
-EOAPI extern const Efl_Event_Description _EFL_FUTURE_EVENT_FAILURE;
-EOAPI extern const Efl_Event_Description _EFL_FUTURE_EVENT_SUCCESS;
-EOAPI extern const Efl_Event_Description _EFL_FUTURE_EVENT_PROGRESS;
-
-/** A future failed
+ * @param[in] f the future to track
+ * @param[in] success the callback to call in case of a succesful computation from the promise
+ * @param[in] failure the callback to call in case of a failure to deliver from the promise
+ * @param[in] progress the callback to call during the progression of the the promise, this is optional
+ * @param[in] data additional data to pass to the callback
*
- * @ingroup Efl_Future
- */
-#define EFL_FUTURE_EVENT_FAILURE (&(_EFL_FUTURE_EVENT_FAILURE))
-
-/** A future succeeded
+ * @return Return a new future when the callback has been successfully added pointing to the next request
+ * being processed during the future success, failure or progress callback (You can reference count the next
+ * promise to defer the result and make it asynchronous too). This future can be ignored.
*
- * @ingroup Efl_Future
- */
-#define EFL_FUTURE_EVENT_SUCCESS (&(_EFL_FUTURE_EVENT_SUCCESS))
-
-/** A future progressed
+ * It is assumed that you are going to steal the value of this future and will
+ * deal by yourself of its life. There can only be one steal and it will be
+ * called last, once all the other then have been processed (It will technically
+ * wait for the next loop iteration to be propagated).
+ *
+ * @note except if you do reference count the Efl.Future object, you can only call once this function.
*
* @ingroup Efl_Future
*/
-#define EFL_FUTURE_EVENT_PROGRESS (&(_EFL_FUTURE_EVENT_PROGRESS))
+EAPI Efl_Future *efl_future_steal_then(Efl_Future *f,
+ Efl_Future_Success_Steal_Cb success,
+ Efl_Future_Failure_Cb failure,
+ Efl_Future_Progress_Cb progress,
+ void *data);
/**
- * @brief Add sets of callbacks to handle the progress and the result of a future.
+ * @brief Add sets of callbacks to handle the progress and result of a future.
*
* callbacks are called depending on the outcome of the promise related to the future.
*
+ * @param[in] f the future to track
* @param[in] success the callback to call in case of a succesful computation from the promise
* @param[in] failure the callback to call in case of a failure to deliver from the promise
* @param[in] progress the callback to call during the progression of the the promise, this is optional
@@ -93,9 +69,15 @@ EOAPI extern const Efl_Event_Description _EFL_FUTURE_EVENT_PROGRESS;
*
* @note except if you do reference count the Efl.Future object, you can only call once this function.
*
+ * @since 1.20
+ *
* @ingroup Efl_Future
*/
-EOAPI Efl_Future *efl_future_then(Eo *obj, Efl_Event_Cb success, Efl_Event_Cb failure, Efl_Event_Cb progress, const void *data);
+EAPI Efl_Future *efl_future_then(Efl_Future *f,
+ Efl_Future_Success_Cb success,
+ Efl_Future_Failure_Cb failure,
+ Efl_Future_Progress_Cb progress,
+ void *data);
/**
* @brief Cancel the need for that specific future.
@@ -107,9 +89,9 @@ EOAPI Efl_Future *efl_future_then(Eo *obj, Efl_Event_Cb success, Efl_Event_Cb fa
*
* @ingroup Efl_Future
*
- * @since 1.19
+ * @since 1.20
*/
-EOAPI void efl_future_cancel(Eo *obj);
+EAPI void efl_future_cancel(Efl_Future *f);
/**
* @brief To be used in conjunction with when you plan to use efl_future_cancel
@@ -125,11 +107,7 @@ EOAPI void efl_future_cancel(Eo *obj);
*
* @ingroup Efl_Future
*/
-static inline void
-efl_future_use(Efl_Future **storage, Eo *future)
-{
- efl_wref_add(future, storage);
-}
+EAPI void efl_future_use(Efl_Future **storage, Efl_Future *future);
/**
* @}