Add promise

Add a promise object that allows Eolian interface to include promises
as a way to have asynchronous value return and composibility.

The usage is like this in a .eo file:

class Foo {
   methods {
      bar {
         params {
            @inout promise: Promise<int>;
         }
      }
  }
}

Which will create the following API interface:

void foo_bar(Eo* obj, Ecore_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:

Ecore_Promise* promise; // No need to instantiate
foo_bar(obj, &promise);

int* p = ecore_promise_value_get();
or:
ecore_promise_then(promise, callback);
This commit is contained in:
Felipe Magno de Almeida 2016-03-11 18:12:39 -03:00
parent c09e43fb4f
commit e17d8e901b
11 changed files with 666 additions and 8 deletions

View File

@ -47,7 +47,8 @@ lib/ecore/Ecore.h \
lib/ecore/Ecore_Common.h \
lib/ecore/Ecore_Legacy.h \
lib/ecore/Ecore_Eo.h \
lib/ecore/Ecore_Getopt.h
lib/ecore/Ecore_Getopt.h \
lib/ecore/ecore_promise.h
nodist_installed_ecoremainheaders_DATA = \
$(ecore_eolian_h)
@ -72,6 +73,7 @@ lib/ecore/ecore_timer.c \
lib/ecore/ecore_thread.c \
lib/ecore/ecore_throttle.c \
lib/ecore/ecore_exe.c \
lib/ecore/ecore_promise.c \
lib/ecore/ecore_exe_private.h \
lib/ecore/ecore_private.h

View File

@ -311,6 +311,9 @@ eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid,
if (ftype != EOLIAN_PROP_GET && ftype != EOLIAN_PROP_SET) ftype = eolian_function_type_get(funcid);
Eina_Bool is_prop = (ftype == EOLIAN_PROP_GET || ftype == EOLIAN_PROP_SET);
Eina_Bool has_promise = EINA_FALSE;
const char* promise_param_name = NULL;
const char* promise_value_type = NULL;
Eina_Bool need_implementation = EINA_TRUE;
if (!impl_env && eolian_function_is_virtual_pure(funcid, ftype)) need_implementation = EINA_FALSE;
@ -375,9 +378,25 @@ eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid,
const char *ptype = eolian_type_c_type_get(ptypet);
Eolian_Parameter_Dir pdir = eolian_parameter_direction_get(param);
Eina_Bool had_star = !!strchr(ptype, '*');
if(!has_promise && !strcmp(ptype, "Ecore_Promise *") &&
(ftype == EOLIAN_UNRESOLVED || ftype == EOLIAN_METHOD) && pdir == EOLIAN_INOUT_PARAM)
{
Eina_Iterator* promise_values;
has_promise = EINA_TRUE;
promise_param_name = eina_stringshare_add(pname);
promise_values = eolian_type_subtypes_get(eolian_type_base_type_get(ptypet));
Eolian_Type* subtype;
if(eina_iterator_next(promise_values, (void**)&subtype))
promise_value_type = eolian_type_c_type_get(subtype);
}
if (ftype == EOLIAN_UNRESOLVED || ftype == EOLIAN_METHOD) add_star = (pdir == EOLIAN_OUT_PARAM || pdir == EOLIAN_INOUT_PARAM);
if (eina_strbuf_length_get(params)) eina_strbuf_append(params, ", ");
eina_strbuf_append_printf(params, "%s", pname);
if(has_promise)
eina_strbuf_append_printf(params, "%s", "&__eo_promise");
else
eina_strbuf_append_printf(params, "%s", pname);
eina_strbuf_append_printf(full_params, ", %s%s%s%s%s",
ptype, had_star?"":" ", add_star?"*":"", pname, is_empty && !dflt_value ?" EINA_UNUSED":"");
if (is_auto)
@ -511,11 +530,19 @@ eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid,
Eina_Bool ret_is_void = (!rettype || !strcmp(rettype, "void"));
_class_func_env_create(class, eolian_function_name_get(funcid), ftype, &func_env);
eina_strbuf_append_printf(eo_func_decl,
"EOAPI EO_%sFUNC_BODY%s%s(%s, _EO_EMPTY_HOOK, _EO_EMPTY_HOOK",
"EOAPI EO_%sFUNC_BODY%s%s(%s",
ret_is_void?"VOID_":"", has_params?"V":"",
(ftype == EOLIAN_PROP_GET ||
eolian_function_object_is_const(funcid) ||
eolian_function_is_class(funcid))?"_CONST":"", func_env.lower_eo_func);
if(has_promise)
{
eina_strbuf_append_printf(eo_func_decl,
", _EO_PROMISE_BEFORE_HOOK(%s) _EO_EMPTY_HOOK, _EO_PROMISE_AFTER_HOOK(%s) _EO_EMPTY_HOOK",
promise_value_type, promise_param_name);
}
else
eina_strbuf_append_printf(eo_func_decl, ", _EO_EMPTY_HOOK, _EO_EMPTY_HOOK");
if (!ret_is_void)
{
const char *val_str = NULL;

View File

@ -356,6 +356,7 @@ extern "C" {
#endif
#ifdef EFL_EO_API_SUPPORT
#include "Ecore_Eo.h"
#include "ecore_promise.h"
#endif
#ifdef __cplusplus

View File

@ -42,6 +42,9 @@
static Ecore_Version _version = { VMAJ, VMIN, VMIC, VREV };
EAPI Ecore_Version *ecore_version = &_version;
void _ecore_promise_init();
void _ecore_promise_shutdown();
#if defined(HAVE_MALLINFO) || defined(HAVE_MALLOC_INFO)
#define KEEP_MAX(Global, Local) \
if (Global < (Local)) \
@ -303,6 +306,8 @@ ecore_init(void)
_ecore_init_count_threshold = _ecore_init_count;
_ecore_promise_init();
eina_log_timing(_ecore_log_dom,
EINA_LOG_STATE_STOP,
EINA_LOG_STATE_INIT);
@ -339,6 +344,8 @@ ecore_shutdown(void)
ecore_system_modules_unload();
_ecore_promise_shutdown();
eina_log_timing(_ecore_log_dom,
EINA_LOG_STATE_START,
EINA_LOG_STATE_SHUTDOWN);

View File

@ -0,0 +1,462 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <Eina.h>
#include <Ecore.h>
#include <Eo.h>
#include <assert.h>
typedef void(*Ecore_Promise_Free_Cb)(void*);
struct _Ecore_Promise_Then_Cb
{
EINA_INLIST;
Ecore_Promise_Cb callback;
void* data;
};
struct _Ecore_Promise
{
Eina_Lock lock;
Eina_Condition condition;
Eina_Bool has_finished : 1;
Eina_Bool has_errored : 1;
Eina_Bool has_pending_call : 1;
Eina_Bool is_then_calls_manual : 1;
Eina_Error error;
size_t value_size;
int ref;
struct _Ecore_Promise_Then_Cb then_callbacks;
Ecore_Promise_Free_Cb free_cb;
char value[];
};
struct _Ecore_Promise_Thread_Data
{
const void* data;
Ecore_Promise_Thread_Cb func_blocking;
Ecore_Promise* promise;
};
typedef struct _Ecore_Promise_Iterator _Ecore_Promise_Iterator;
typedef struct _Ecore_Promise_Success_Iterator _Ecore_Promise_Success_Iterator;
typedef struct _Ecore_Promise_Failure_Iterator _Ecore_Promise_Failure_Iterator;
struct _Ecore_Promise_Iterator
{
Eina_Iterator* success_iterator;
Eina_Iterator* failure_iterator;
struct _Ecore_Promise_Success_Iterator
{
Eina_Iterator success_iterator_impl;
struct _Ecore_Promise_Failure_Iterator
{
Eina_Iterator failure_iterator_impl;
unsigned int promise_index;
unsigned int num_promises;
unsigned int promises_finished;
Ecore_Promise* promises[];
} data;
} data;
};
static void _ecore_promise_lock_take(Ecore_Promise* promise);
static void _ecore_promise_lock_release(Ecore_Promise* promise);
static void _ecore_promise_finish(Ecore_Promise* promise);
static void _ecore_promise_then_calls(Ecore_Promise* promise);
static void _ecore_promise_unsafe_ref(Ecore_Promise const* promise);
static void _ecore_promise_unsafe_unref(Ecore_Promise const* promise);
static void _ecore_promise_unsafe_free_unref(Ecore_Promise const* promise);
static Eina_Bool _ecore_promise_unlock_unsafe_free_unref(Ecore_Promise const* promise);
static void _ecore_promise_iterator_setup(_Ecore_Promise_Iterator* iterator, Eina_Array* promises);
static void _ecore_promise_thread_end(void* data, Ecore_Thread* thread EINA_UNUSED)
{
struct _Ecore_Promise_Thread_Data* p = data;
_ecore_promise_lock_take(p->promise);
if(p->promise->has_finished)
{
p->promise->has_pending_call = EINA_FALSE;
if(!_ecore_promise_unlock_unsafe_free_unref(p->promise))
_ecore_promise_then_calls(p->promise);
}
else
{
p->promise->is_then_calls_manual = EINA_FALSE;
p->promise->has_pending_call = EINA_FALSE;
_ecore_promise_unlock_unsafe_free_unref(p->promise);
}
free(data);
}
static void
_ecore_promise_thread_blocking(void* data, Ecore_Thread* thread EINA_UNUSED)
{
struct _Ecore_Promise_Thread_Data* p = data;
(p->func_blocking)(p->data, p->promise);
}
static void
_ecore_promise_then_calls(Ecore_Promise* promise)
{
_ecore_promise_lock_take(promise);
struct _Ecore_Promise_Then_Cb then_callbacks = promise->then_callbacks;
memset(&promise->then_callbacks, 0, sizeof(promise->then_callbacks));
promise->has_pending_call = EINA_FALSE;
_ecore_promise_lock_release(promise);
struct _Ecore_Promise_Then_Cb* callback;
if(then_callbacks.callback)
{
(*then_callbacks.callback)(then_callbacks.data, &promise->value[0]);
_ecore_promise_unsafe_free_unref(promise);
}
if(EINA_INLIST_GET(&then_callbacks)->next)
{
Eina_Inlist* list2;
EINA_INLIST_FOREACH_SAFE(EINA_INLIST_GET(&then_callbacks)->next, list2, callback)
{
if(callback->callback)
{
(*callback->callback)(callback->data, promise);
}
_ecore_promise_unsafe_free_unref(promise);
}
}
}
Ecore_Promise* ecore_promise_thread_run(Ecore_Promise_Thread_Cb func_blocking, const void* data, size_t value_size)
{
struct _Ecore_Promise_Thread_Data *new_data = malloc(sizeof(struct _Ecore_Promise_Thread_Data));
new_data->data = data;
new_data->func_blocking = func_blocking;
new_data->promise = ecore_promise_add(value_size);
new_data->promise->is_then_calls_manual = EINA_TRUE;
new_data->promise->has_pending_call = EINA_TRUE;
ecore_promise_ref(new_data->promise);
ecore_thread_run(&_ecore_promise_thread_blocking, &_ecore_promise_thread_end, NULL, new_data);
return new_data->promise;
}
Ecore_Promise* ecore_promise_add(int value_size)
{
Ecore_Promise* p = malloc(sizeof(Ecore_Promise) + value_size);
eina_lock_new(&p->lock);
eina_condition_new(&p->condition, &p->lock);
p->has_finished = p->has_errored = p->has_pending_call = p->is_then_calls_manual = EINA_FALSE;
p->ref = 1;
memset(&p->then_callbacks, 0, sizeof(p->then_callbacks));
p->value_size = value_size;
p->free_cb = NULL;
return p;
}
static void _ecore_promise_del(Ecore_Promise* promise)
{
if(promise->free_cb)
promise->free_cb((void*)&promise->value[0]);
eina_lock_free(&promise->lock);
eina_condition_free(&promise->condition);
}
void* ecore_promise_buffer_get(Ecore_Promise* promise)
{
return &promise->value[0];
}
void* ecore_promise_value_get(Ecore_Promise const* promise)
{
_ecore_promise_lock_take((Ecore_Promise*)promise);
_ecore_promise_unsafe_ref(promise);
while(!promise->has_finished)
{
eina_condition_wait((Eina_Condition*)&promise->condition);
}
void* v = (void*)(promise->value_size && !promise->has_errored ? &promise->value[0] : NULL);
_ecore_promise_unsafe_unref(promise);
_ecore_promise_lock_release((Ecore_Promise*)promise);
return v;
}
void ecore_promise_value_set(Ecore_Promise* promise, void* data)
{
_ecore_promise_lock_take(promise);
if(data && promise->value_size)
{
memcpy(&promise->value[0], data, promise->value_size);
}
_ecore_promise_finish(promise);
}
static void _ecore_promise_all_compose_then_cb(Ecore_Promise* promise, void* value EINA_UNUSED)
{
_ecore_promise_lock_take(promise);
_Ecore_Promise_Iterator* iterator = (_Ecore_Promise_Iterator*)promise->value;
if(++iterator->data.data.promises_finished == iterator->data.data.num_promises)
{
_ecore_promise_finish(promise);
}
else
_ecore_promise_lock_release(promise);
}
static void _ecore_promise_all_free(_Ecore_Promise_Iterator* value)
{
unsigned i = 0;
eina_iterator_free(value->success_iterator);
/* eina_iterator_free(value->failure_iterator); */
for(;i != value->data.data.num_promises; ++i)
{
ecore_promise_unref(value->data.data.promises[i]);
}
}
Ecore_Promise* ecore_promise_all(Eina_Iterator* it)
{
Ecore_Promise* current, *promise;
Eina_Array* promises;
promises = eina_array_new(20);
EINA_ITERATOR_FOREACH(it, current)
{
eina_array_push(promises, current);
}
promise = ecore_promise_add(sizeof(_Ecore_Promise_Iterator) + sizeof(Ecore_Promise*)*eina_array_count_get(promises));
//promise->is_then_calls_manual = EINA_TRUE;
promise->free_cb = (Ecore_Promise_Free_Cb)_ecore_promise_all_free;
_Ecore_Promise_Iterator* internal_it = ecore_promise_buffer_get(promise);
_ecore_promise_iterator_setup(internal_it, promises);
eina_array_free(promises);
{
Ecore_Promise** cur_promise = internal_it->data.data.promises, ** last =
internal_it->data.data.promises + internal_it->data.data.num_promises;
for(;cur_promise != last; ++cur_promise)
{
ecore_promise_ref(*cur_promise);
ecore_promise_then(*cur_promise, (Ecore_Promise_Cb)&_ecore_promise_all_compose_then_cb, promise);
}
}
return promise;
}
void ecore_promise_then(Ecore_Promise* promise, Ecore_Promise_Cb callback, void* data)
{
_ecore_promise_lock_take(promise);
_ecore_promise_unsafe_ref(promise);
if(!promise->then_callbacks.callback && !EINA_INLIST_GET(&promise->then_callbacks)->next)
{
promise->then_callbacks.callback = callback;
promise->then_callbacks.data = data;
}
else
{
struct _Ecore_Promise_Then_Cb* p = malloc(sizeof(struct _Ecore_Promise_Then_Cb));
p->callback = callback;
p->data = data;
Eina_Inlist* l = eina_inlist_append(EINA_INLIST_GET(&promise->then_callbacks), EINA_INLIST_GET(p));
(void)l;
}
if(promise->has_finished && !promise->has_pending_call)
{
promise->has_pending_call = EINA_TRUE;
_ecore_promise_lock_release(promise);
ecore_job_add((Ecore_Cb)&_ecore_promise_then_calls, promise);
}
else
_ecore_promise_lock_release(promise);
}
EAPI Eina_Error ecore_promise_error_get(Ecore_Promise const* promise)
{
_ecore_promise_lock_take((Ecore_Promise*)promise);
if(promise->has_errored)
{
Eina_Error error = promise->error;
_ecore_promise_lock_release((Ecore_Promise*)promise);
return error;
}
else
{
_ecore_promise_lock_release((Ecore_Promise*)promise);
return 0;
}
}
EAPI void ecore_promise_error_set(Ecore_Promise* promise, Eina_Error error)
{
_ecore_promise_lock_take(promise);
promise->error = error;
promise->has_errored = EINA_TRUE;
_ecore_promise_finish(promise);
}
static void
_ecore_promise_finish(Ecore_Promise* promise)
{
promise->has_finished = EINA_TRUE;
eina_condition_broadcast(&promise->condition);
_ecore_promise_unsafe_unref(promise);
if(!promise->is_then_calls_manual && !promise->has_pending_call)
{
promise->has_pending_call = EINA_TRUE;
_ecore_promise_lock_release(promise);
ecore_job_add((Ecore_Cb)&_ecore_promise_then_calls, promise);
}
else
_ecore_promise_lock_release(promise);
}
static Eina_Bool
_ecore_promise_iterator_next(_Ecore_Promise_Success_Iterator *it, void **data)
{
if(it->data.promise_index == it->data.num_promises)
return EINA_FALSE;
if(ecore_promise_error_get(it->data.promises[it->data.promise_index]))
{
return EINA_FALSE;
}
else
{
*data = ecore_promise_value_get(it->data.promises[it->data.promise_index++]);
return EINA_TRUE;
}
}
static void**
_ecore_promise_iterator_get_container(_Ecore_Promise_Success_Iterator *it)
{
return (void**)it->data.promises;
}
static void
_ecore_promise_iterator_free(_Ecore_Promise_Success_Iterator *it EINA_UNUSED)
{
}
static void _ecore_promise_iterator_setup(_Ecore_Promise_Iterator* it, Eina_Array* promises_array)
{
Ecore_Promise** promises;
it->success_iterator = &it->data.success_iterator_impl;
it->failure_iterator = &it->data.data.failure_iterator_impl;
it->data.data.num_promises = eina_array_count_get(promises_array);
it->data.data.promise_index = 0;
promises = (Ecore_Promise**)promises_array->data;
memcpy(&it->data.data.promises[0], promises, it->data.data.num_promises*sizeof(Ecore_Promise*));
EINA_MAGIC_SET(&it->data.success_iterator_impl, EINA_MAGIC_ITERATOR);
EINA_MAGIC_SET(&it->data.data.failure_iterator_impl, EINA_MAGIC_ITERATOR);
it->data.success_iterator_impl.version = EINA_ITERATOR_VERSION;
it->data.success_iterator_impl.next = FUNC_ITERATOR_NEXT(_ecore_promise_iterator_next);
it->data.success_iterator_impl.get_container = FUNC_ITERATOR_GET_CONTAINER(
_ecore_promise_iterator_get_container);
it->data.success_iterator_impl.free = FUNC_ITERATOR_FREE(_ecore_promise_iterator_free);
}
EAPI int ecore_promise_value_size_get(Ecore_Promise const* promise)
{
return promise->value_size;
}
static void _ecore_promise_lock_take(Ecore_Promise* promise)
{
eina_lock_take(&promise->lock);
}
static void _ecore_promise_lock_release(Ecore_Promise* promise)
{
eina_lock_release(&promise->lock);
}
static void _ecore_promise_unsafe_ref(Ecore_Promise const* promise)
{
Ecore_Promise* p = (Ecore_Promise*)promise;
++p->ref;
}
static void _ecore_promise_free_cb(Ecore_Promise* promise)
{
_ecore_promise_lock_take(promise);
_ecore_promise_unlock_unsafe_free_unref(promise);
}
static void _ecore_promise_unsafe_unref(Ecore_Promise const* promise)
{
Ecore_Promise* p = (Ecore_Promise*)promise;
if(p->ref == 1 && !p->has_pending_call)
{
ecore_job_add((Ecore_Cb)_ecore_promise_free_cb, p);
}
else
--p->ref;
}
static void _ecore_promise_unsafe_free_unref(Ecore_Promise const* promise)
{
Ecore_Promise* p = (Ecore_Promise*)promise;
if(--p->ref == 0)
{
assert(!p->has_pending_call);
_ecore_promise_del(p);
}
}
static Eina_Bool _ecore_promise_unlock_unsafe_free_unref(Ecore_Promise const* promise)
{
Ecore_Promise* p = (Ecore_Promise*)promise;
if(--p->ref == 0)
{
assert(!p->has_pending_call);
_ecore_promise_lock_release((Ecore_Promise*)promise);
_ecore_promise_del(p);
return EINA_TRUE;
}
else
{
_ecore_promise_lock_release((Ecore_Promise*)promise);
return EINA_FALSE;
}
}
EAPI void ecore_promise_ref(Ecore_Promise* promise)
{
_ecore_promise_lock_take(promise);
_ecore_promise_unsafe_ref(promise);
_ecore_promise_lock_release(promise);
}
EAPI void ecore_promise_unref(Ecore_Promise* promise)
{
_ecore_promise_lock_take(promise);
_ecore_promise_unsafe_unref(promise);
_ecore_promise_lock_release(promise);
}
void _ecore_promise_init()
{
_eo_ecore_promise_add = &ecore_promise_add;
}
void _ecore_promise_shutdown()
{
}

View File

@ -0,0 +1,147 @@
#include <dlfcn.h>
#ifdef EFL_BETA_API_SUPPORT
struct _Ecore_Promise;
/*
* @def _Ecore_Promise
*/
typedef struct _Ecore_Promise Ecore_Promise;
/*
* @brief Function callback type for when using ecore_promise_then
*/
typedef void(*Ecore_Promise_Cb)(void* data, void* value);
/*
* @brief Function callback type for when creating Ecore_Thread that
* uses Ecore_Promise for communication
*/
typedef void(*Ecore_Promise_Thread_Cb)(const void* data, Ecore_Promise* promise);
/*
* @brief Function that instantiates a Ecore_Promise and automatically
* executes func_blocking callback function in another thread
*/
EAPI Ecore_Promise* ecore_promise_thread_run(Ecore_Promise_Thread_Cb func_blocking, const void* data, size_t value_size);
/*
* @brief Creates a Ecore_Promise with a value of size value_size.
*
* @param value_size Size of value-type that Ecore_Promise will hold
*/
EAPI Ecore_Promise* ecore_promise_add(int value_size);
/*
* @brief Appends a callback to be called when the Ecore_Promise is
* finished.
*
* @param promise The Ecore_Promise to wait for
* @param callback Callback to be called when Ecore_Promise is finished
* @param data Private data passed to the callback
*/
EAPI void ecore_promise_then(Ecore_Promise* promise, Ecore_Promise_Cb callback, void* data);
/*
* @brief Creates a new Ecore_Promise from other Ecore_Promises
*
* @param promises An Eina_Iterator for all Ecore_Promises
*/
EAPI Ecore_Promise* ecore_promise_all(Eina_Iterator* promises);
/*
* @brief Sets value for Ecore_Promise. This finishes the callback and
* calls all ecore_promise_then callbacks that have been registered on
* this Ecore_Promise. This function must be called only once per
* Ecore_Promise
*
* @param promise The promise for which to set the value
* @param value The pointer to the value that is going to be copied, or NULL.
*/
EAPI void ecore_promise_value_set(Ecore_Promise* promise, void* value);
/*
* @brief Returns the pointer to the value if the Ecore_Promise is
* finished. Waits for it to be finished, otherwise.
*
* @param promise The promise for which to get the value
*/
EAPI void* ecore_promise_value_get(Ecore_Promise const* promise);
/*
* @brief Returns the pointer to the buffer that holds the value. This
* function is useful to instantiate the value directly in the correct
* buffer, without needing to copy. The ecore_promise_value_set must
* still be called, possibly with NULL, to finish the Ecore_Promise
* and call the callbacks registered in it.
*
* @param promise The promise for which to get the buffer pointer
*/
EAPI void* ecore_promise_buffer_get(Ecore_Promise* promise);
/*
* @brief Sets an error to the Ecore_Promise, thus finishing the
* promise and calling all ecore_promise_then callbacks registered.
*
* @param promise The promise for which to set the error
* @param error Eina_Error to be set
*/
EAPI void ecore_promise_error_set(Ecore_Promise* promise, Eina_Error error);
/*
* @brief Gets an error to the Ecore_Promise if the promise is
* finished and has error'ed out. If it hasn't finished, it will wait,
* and if it has finished but otherwise not error'ed, returns 0.
*
* @param promise The promise for which to get the error
*/
EAPI Eina_Error ecore_promise_error_get(Ecore_Promise const* promise);
/*
* @brief Gets the size of the value in ecore_promise_value_get.
*
* @param promise The promise for which to get the value size
*/
EAPI int ecore_promise_value_size_get(Ecore_Promise const* promise);
/*
* @brief Returns @EINA_TRUE if the promise is ready and won't block
* on ecore_promise_value_get and @EINA_FALSE otherwise.
*
* @param promise The promise for which to get the ready status
*/
EAPI Eina_Bool ecore_promise_ready_is(Ecore_Promise const* promise);
/*
* @brief Increments the reference count for the Ecore_Promise
*
* @param promise The promise for which to increment its reference
*/
EAPI void ecore_promise_ref(Ecore_Promise* promise);
/*
* @brief Decrement the reference count for the Ecore_Promise and
* possibly schedule its destruction. The Ecore_Promise, if its
* reference count drops to zero, will only be free'd when all the
* current mainloop events have been processed. This allows the user
* to call ecore_promise_then before that happens so it can increment
* the reference back to 1 and wait for a value set or error set on
* the Ecore_Promise.
*
* @param promise The promise for which to decrement its reference
*/
EAPI void ecore_promise_unref(Ecore_Promise* promise);
#define _EO_PROMISE_BEFORE_HOOK(PromiseValue) \
typedef Ecore_Promise*(*_eo_ecore_promise_add_t)(int size); \
_eo_ecore_promise_add_t _eo_ecore_promise_add_f = (_eo_ecore_promise_add_t)_eo_ecore_promise_add; \
Ecore_Promise* __eo_promise = _eo_ecore_promise_add_f(sizeof(PromiseValue));
#define _EO_PROMISE_AFTER_HOOK(Promise) \
if(Promise) \
*Promise = __eo_promise;
#endif

View File

@ -133,6 +133,13 @@ EAPI extern Eina_Spinlock _eo_class_creation_lock;
*/
EAPI extern unsigned int _eo_init_generation;
/**
* @var _eo_ecore_promise_add
* This variable stores ecore_promise_add function pointer.
* @internal
*/
EAPI extern void* _eo_ecore_promise_add;
/**
* @internal
* An enum representing the possible types of an Op.

View File

@ -20,6 +20,7 @@
/* Used inside the class_get functions of classes, see #EO_DEFINE_CLASS */
EAPI Eina_Spinlock _eo_class_creation_lock;
EAPI unsigned int _eo_init_generation = 1;
EAPI void* _eo_ecore_promise_add;
int _eo_log_dom = -1;
static _Eo_Class **_eo_classes;

View File

@ -73,9 +73,10 @@ static const char * const ctypes[] =
"void",
"Eina_Accessor", "Eina_Array", "Eina_Iterator", "Eina_Hash", "Eina_List",
"Ecore_Promise",
"Eina_Value",
"Eo_Event_Cb"
"Eo_Event_Cb",
};
#undef KW

View File

@ -50,9 +50,12 @@ enum Tokens
\
KW(void), \
\
KW(accessor), KW(array), KW(iterator), KW(hash), KW(list), KW(generic_value), \
KW(accessor), KW(array), KW(iterator), KW(hash), KW(list), \
KW(promise), \
KW(generic_value), \
\
KW(__builtin_event_cb), KW(__undefined_type), \
KW(__builtin_event_cb), \
KW(__undefined_type), \
\
KW(true), KW(false), KW(null)
@ -206,4 +209,4 @@ void eo_lexer_context_pop (Eo_Lexer *ls);
void eo_lexer_context_restore(Eo_Lexer *ls);
void eo_lexer_context_clear (Eo_Lexer *ls);
#endif /* __EO_LEXER_H__ */
#endif /* __EO_LEXER_H__ */

View File

@ -782,7 +782,7 @@ parse_type_void_base(Eo_Lexer *ls, Eina_Bool noptr)
_fill_name(eina_stringshare_ref(ls->t.value.s), &def->full_name,
&def->name, &def->namespaces);
eo_lexer_get(ls);
if (tpid >= KW_accessor && tpid <= KW_list)
if (tpid >= KW_accessor && tpid <= KW_promise)
{
int bline = ls->line_number, bcol = ls->column;
def->type = EOLIAN_TYPE_COMPLEX;