eolian: add Eolian support for Eina Promises

Add a promise object to 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, Eina_Promise** promise);

and a Eina_Promise_Owner for the implementation, like this:

void _foo_bar(Eo* obj, Private_Data* pdata, Eina_Promise_Owner* promise);

Signed-off-by: Cedric Bail <cedric@osg.samsung.com>
This commit is contained in:
Felipe Magno de Almeida 2016-04-01 22:50:28 -03:00 committed by Cedric Bail
parent 944e11559c
commit dc954d8dba
8 changed files with 170 additions and 13 deletions

View File

@ -111,19 +111,24 @@ tests/eolian/eolian_suite
tests_eolian_eolian_suite_SOURCES = \
tests/eolian/eolian_parsing.c \
tests/eolian/eolian_generation.c \
tests/eolian/eolian_generated_promise.c \
tests/eolian/eolian_suite.c \
tests/eolian/eolian_suite.h
tests_eolian_eolian_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
tests/eolian/tests_eolian_eolian_suite-eolian_generated_promise.$(OBJEXT): tests/eolian/generated_promise.eo.h tests/eolian/generated_promise.eo.c
CLEANFILES += tests/eolian/generated_promise.eo.h tests/eolian/generated_promise.eo.c
tests_eolian_eolian_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl -I$(top_builddir)/src/tests/eolian \
-DTESTS_BUILD_DIR=\"$(top_builddir)/src/tests/eolian\" \
-DPACKAGE_DATA_DIR=\"$(top_srcdir)/src/tests/eolian\" \
-DPACKAGE_BUILD_DIR=\"$(abs_top_builddir)\" \
@CHECK_CFLAGS@ \
@EOLIAN_CFLAGS@
@EOLIAN_CFLAGS@ @EO_CFLAGS@
TESTS += tests/eolian/eolian_suite
tests_eolian_eolian_suite_LDADD = @CHECK_LIBS@ @USE_EOLIAN_LIBS@
tests_eolian_eolian_suite_DEPENDENCIES = @USE_EOLIAN_INTERNAL_LIBS@
tests_eolian_eolian_suite_LDADD = @CHECK_LIBS@ @USE_EOLIAN_LIBS@ @USE_EO_LIBS@
tests_eolian_eolian_suite_DEPENDENCIES = @USE_EOLIAN_INTERNAL_LIBS@ @USE_EO_INTERNAL_LIBS@
tests_eolian_eolian_suite.$(OBJEXT): $(EOLIAN_TESTS_EOS_GENERATED)
endif

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;
@ -318,6 +321,7 @@ eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid,
Eina_Strbuf *va_args = eina_strbuf_new();
Eina_Strbuf *params = eina_strbuf_new(); /* only variables names */
Eina_Strbuf *full_params = eina_strbuf_new(); /* variables types + names */
Eina_Strbuf *impl_full_params = eina_strbuf_new(); /* variables types + names */
Eina_Strbuf *params_init = eina_strbuf_new(); /* init of variables to default */
rettypet = eolian_function_return_type_get(funcid, ftype);
@ -360,6 +364,8 @@ eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid,
eina_strbuf_append_printf(params, "%s", pname);
eina_strbuf_append_printf(full_params, ", %s %s%s",
ptype, pname, is_empty || is_auto?" EINA_UNUSED":"");
eina_strbuf_append_printf(impl_full_params, ", %s %s%s",
ptype, pname, is_empty || is_auto?" EINA_UNUSED":"");
eina_stringshare_del(ptype);
}
eina_iterator_free(itr);
@ -375,9 +381,33 @@ 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 (ftype == EOLIAN_UNRESOLVED || ftype == EOLIAN_METHOD) add_star = (pdir == EOLIAN_OUT_PARAM || pdir == EOLIAN_INOUT_PARAM);
if(!has_promise && !strcmp(ptype, "Eina_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);
eina_strbuf_append_printf(impl_full_params, ", Eina_Promise_Owner *%s%s",
pname, is_empty && !dflt_value ?" EINA_UNUSED":"");
}
else
{
eina_strbuf_append_printf(impl_full_params, ", %s%s%s%s%s",
ptype, had_star?"":" ", add_star?"*":"", pname, is_empty && !dflt_value ?" EINA_UNUSED":"");
}
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)
@ -439,7 +469,7 @@ eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid,
impl_env?impl_env->lower_classname:"",
eolian_function_name_get(funcid), suffix,
eolian_function_object_is_const(funcid)?"const ":"",
eina_strbuf_string_get(full_params));
eina_strbuf_string_get(impl_full_params));
}
if (is_empty || is_auto || eina_strbuf_length_get(params_init))
@ -457,7 +487,7 @@ eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid,
eolian_function_object_is_const(funcid)?"const ":"",
is_empty || is_auto?" EINA_UNUSED":"",
is_empty || (is_auto && !eina_strbuf_length_get(params_init))?" EINA_UNUSED":"",
eina_strbuf_string_get(full_params));
eina_strbuf_string_get(impl_full_params));
}
if (eina_strbuf_length_get(params_init))
{
@ -511,11 +541,21 @@ 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,
", _EINA_PROMISE_BEFORE_HOOK(%s, %s%s) _EO_EMPTY_HOOK, _EINA_PROMISE_AFTER_HOOK(%s) _EO_EMPTY_HOOK",
promise_value_type, !rettype ? "void" : rettype,
eina_strbuf_string_get(impl_full_params),
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

@ -438,4 +438,24 @@ 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);
/*
* @internal
*/
#define _EINA_PROMISE_BEFORE_HOOK(PromiseValue, Ret, ...) \
Eina_Promise_Owner* __eo_promise = eina_promise_default_add(sizeof(PromiseValue)); \
typedef Ret (*_Eo__Promise_func_)(Eo*, void *obj_data, ##__VA_ARGS__); \
_Eo__Promise_func_ const _promise_func = (_Eo__Promise_func_)_func_; \
{ \
_Eo__Promise_func_ const _func_ = _promise_func;
/*
* @internal
*/
#define _EINA_PROMISE_AFTER_HOOK(Promise) \
} \
if(Promise) \
*Promise = eina_promise_owner_promise_get(__eo_promise);
#endif

View File

@ -73,9 +73,10 @@ static const char * const ctypes[] =
"void",
"Eina_Accessor", "Eina_Array", "Eina_Iterator", "Eina_Hash", "Eina_List",
"Eina_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;

View File

@ -0,0 +1,46 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <Eina.h>
#include <Eo.h>
#include <check.h>
struct Generated_Promise_Data {};
typedef struct Generated_Promise_Data Generated_Promise_Data;
static Eina_Promise * _generated_promise_prop1_get(Eo *obj EINA_UNUSED, Generated_Promise_Data *pd EINA_UNUSED)
{
return NULL;
}
static void _generated_promise_prop2_get(Eo *obj EINA_UNUSED, Generated_Promise_Data *pd EINA_UNUSED, int *i EINA_UNUSED,
Eina_Promise **promise1 EINA_UNUSED)
{
}
static void _generated_promise_prop3_set(Eo *obj EINA_UNUSED, Generated_Promise_Data *pd EINA_UNUSED,
Eina_Promise *promise1 EINA_UNUSED)
{
}
static void _generated_promise_method1(Eo *obj EINA_UNUSED, Generated_Promise_Data *pd EINA_UNUSED,
Eina_Promise_Owner *promise1 EINA_UNUSED)
{
}
static void _generated_promise_method2(Eo *obj EINA_UNUSED, Generated_Promise_Data *pd EINA_UNUSED,
Eina_Promise **promise1 EINA_UNUSED)
{
}
static void _generated_promise_method3(Eo *obj EINA_UNUSED, Generated_Promise_Data *pd EINA_UNUSED,
Eina_Promise *promise1 EINA_UNUSED)
{
ck_assert(promise1 != NULL);
}
#include "generated_promise.eo.h"
#include "generated_promise.eo.c"

View File

@ -0,0 +1,42 @@
class Generated_Promise (Eo.Base)
{
legacy_prefix: null;
methods {
method1 {
params {
@inout promise1: promise<int>*;
}
}
method2 {
params {
@out promise1: promise<int>*;
}
}
method3 {
params {
@in promise1: promise<int>*;
}
}
@property prop1 {
get {}
values {
promise1: promise<int>*;
}
}
@property prop2 {
get {}
values {
i: int;
promise1: promise<int>*;
}
}
@property prop3 {
set {}
values {
promise1: promise<int>*;
}
}
}
}