diff --git a/src/Makefile_Eo.am b/src/Makefile_Eo.am index bd5dcba9d4..80460ef791 100644 --- a/src/Makefile_Eo.am +++ b/src/Makefile_Eo.am @@ -17,7 +17,7 @@ BUILT_SOURCES += \ lib_LTLIBRARIES += lib/eo/libeo.la installed_eomainheadersdir = $(includedir)/eo-@VMAJ@ -dist_installed_eomainheaders_DATA = lib/eo/Eo.h +dist_installed_eomainheaders_DATA = lib/eo/Eo.h lib/eo/efl_future.h nodist_installed_eomainheaders_DATA = \ $(eo_eolian_h) @@ -30,7 +30,8 @@ lib/eo/eo_base_class.c \ lib/eo/eo_class_class.c \ lib/eo/eo_add_fallback.c \ lib/eo/eo_add_fallback.h \ -lib/eo/eo_private.h +lib/eo/eo_private.h \ +lib/eo/efl_future.c lib_eo_libeo_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl @EO_CFLAGS@ lib_eo_libeo_la_LIBADD = @EO_LIBS@ diff --git a/src/lib/eo/Eo.h b/src/lib/eo/Eo.h index 8fd5ca7c93..f1ce4c150d 100644 --- a/src/lib/eo/Eo.h +++ b/src/lib/eo/Eo.h @@ -167,6 +167,12 @@ typedef enum _Efl_Object_Op_Type Efl_Object_Op_Type; */ typedef void (*Efl_Del_Intercept) (Eo *obj_id); +/** + * @typedef Efl_Future + * The type of Efl Future used in asynchronous operation, the read side of a promise. + */ +typedef Eo Efl_Future; + #include "efl_object_override.eo.h" #include "efl_object.eo.h" #include "efl_interface.eo.h" @@ -1321,9 +1327,7 @@ EAPI int efl_callbacks_cmp(const Efl_Callback_Array_Item *a, const Efl_Callback_ * @} */ -/** - * @} - */ +#include "efl_future.h" /** * @} diff --git a/src/lib/eo/efl_future.c b/src/lib/eo/efl_future.c new file mode 100644 index 0000000000..5f37f7afd9 --- /dev/null +++ b/src/lib/eo/efl_future.c @@ -0,0 +1,56 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#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); +} + +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 +}; + +EFL_DEFINE_CLASS(efl_future_class_get, &_efl_future_class_desc, EFL_OBJECT_CLASS, NULL); + +static const char EINA_ERROR_FUTURE_CANCEL_STR[] = "Future cancelled"; +EAPI Eina_Error EINA_ERROR_FUTURE_CANCEL; + +Eina_Bool +efl_future_init(void) +{ + EINA_ERROR_FUTURE_CANCEL = eina_error_msg_static_register(EINA_ERROR_FUTURE_CANCEL_STR); + + return EINA_TRUE; +} + +Eina_Bool +efl_future_shutdown(void) +{ + return EINA_TRUE; +} diff --git a/src/lib/eo/efl_future.h b/src/lib/eo/efl_future.h new file mode 100644 index 0000000000..243d660979 --- /dev/null +++ b/src/lib/eo/efl_future.h @@ -0,0 +1,107 @@ +#ifndef EFL_FUTURE_H_ +# define EFL_FUTURE_H_ + +/** + * @addtogroup Efl_Future Efl future and promise. + * @{ + */ + +/** + * @typedef Efl_Promise + * The type of Efl Promise used in asynchronous operation, the write side of a promise. + */ +typedef Eo Efl_Promise; + +#define EFL_FUTURE_CLASS efl_future_class_get() +EWAPI const Efl_Class *efl_future_class_get(void); + +EAPI extern Eina_Error EINA_ERROR_FUTURE_CANCEL; + +typedef struct _Efl_Future_Event_Failure Efl_Future_Event_Failure; +struct _Efl_Future_Event_Failure +{ + Efl_Promise *next; + Eina_Error error; +}; + +typedef struct _Efl_Future_Event_Success Efl_Future_Event_Success; +struct _Efl_Future_Event_Success +{ + Efl_Promise *next; + void *value; +}; + +typedef struct _Efl_Future_Event_Progress Efl_Future_Event_Progress; +struct _Efl_Future_Event_Progress +{ + Efl_Promise *next; + void *progress; +}; + +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; + + // FIXME: documentation +#define EFL_FUTURE_EVENT_FAILURE (&(_EFL_FUTURE_EVENT_FAILURE)) +#define EFL_FUTURE_EVENT_SUCCESS (&(_EFL_FUTURE_EVENT_SUCCESS)) +#define EFL_FUTURE_EVENT_PROGRESS (&(_EFL_FUTURE_EVENT_PROGRESS)) + +/** + * @brief Add sets of callbacks to handle the progress and the result of a future. + * + * callbacks are called depending on the outcome of the promise related to the future. + * + * @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 + * + * @return Return a new future when the callback has been successfully added. This future can be ignored. + * + * @note except if you do reference count the Efl.Future object, you can only call once this function. + * + * @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); + +/** + * @brief Cancel the need for that specific future. + * + * This will trigger the failure of the future and may result in the promise stopping its computation. + * + * @see efl_future_use + * + * @ingroup Efl_Future + */ +EOAPI void efl_future_cancel(Eo *obj); + +/** + * @brief To be used in conjunction with when you plan to use efl_future_cancel + * + * This function will store in *wref, obj and make sure that on failure or success of the future, it + * will be reset to NULL. This guarantee that the pointer you are using will always be correct and + * that you do not have to worry about passing a dead pointer to efl_future_cancel. + * + * @param[out] storage Will be set to obj and tracked during all the lifetime of the future. + * @param[in] future The future to remember about. + * + * @see efl_future_cancel + * + * @ingroup Efl_Future + */ +static inline void +efl_future_use(Efl_Future **storage, Eo *future) +{ + efl_wref_add(future, storage); +} + +/** + * @} + */ + +/** + * @} + */ + +#endif diff --git a/src/lib/eo/eo.c b/src/lib/eo/eo.c index fa8a7f7d51..d90d417628 100644 --- a/src/lib/eo/eo.c +++ b/src/lib/eo/eo.c @@ -1862,6 +1862,7 @@ efl_object_init(void) EO_FREED_EINA_MAGIC_STR); eina_magic_string_static_set(EO_CLASS_EINA_MAGIC, EO_CLASS_EINA_MAGIC_STR); + efl_future_init(); #ifndef _WIN32 _ops_storage = eina_hash_pointer_new(NULL); @@ -1923,6 +1924,8 @@ efl_object_shutdown(void) _efl_add_fallback_shutdown(); + efl_future_shutdown(); + for (i = 0 ; i < _eo_classes_last_id ; i++, cls_itr--) { if (*cls_itr) diff --git a/src/lib/eo/eo_private.h b/src/lib/eo/eo_private.h index 4fd2eeece9..1cbddf2ccf 100644 --- a/src/lib/eo/eo_private.h +++ b/src/lib/eo/eo_private.h @@ -369,4 +369,7 @@ _efl_unref(_Eo_Object *obj) } } +Eina_Bool efl_future_init(void); +Eina_Bool efl_future_shutdown(void); + #endif