eo: here comes reflection API
this adds support in eo to generate a reflection API. To get the actaul reflection to the klass, the API efl_class_reflection_table_set needs to be called, the table in the end can be generated by eolian. Reflection API is inherited by the extended class. This means, if you have two reflection tables, first, the most upperst is called, then the next lower one is called. For now this API accepts NULL setter or getter, and will ignore them silently when they are called. fix T7681 Differential Revision: https://phab.enlightenment.org/D7879
This commit is contained in:
parent
0709bdea6f
commit
0f32bb9047
|
@ -149,7 +149,8 @@ tests/eo/suite/eo_test_value.c \
|
|||
tests/eo/suite/eo_test_event.c \
|
||||
tests/eo/suite/eo_test_threaded_calls.c \
|
||||
tests/eo/suite/eo_test_init.c \
|
||||
tests/eo/suite/eo_test_lifecycle.c
|
||||
tests/eo/suite/eo_test_lifecycle.c \
|
||||
tests/eo/suite/eo_test_reflection.c
|
||||
|
||||
tests_eo_eo_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
|
||||
-DPACKAGE_BUILD_DIR=\"$(abs_top_builddir)\" \
|
||||
|
|
|
@ -826,6 +826,40 @@ struct _Efl_Class_Description
|
|||
void (*class_constructor)(Efl_Class *klass); /**< The constructor of the class. */
|
||||
void (*class_destructor)(Efl_Class *klass); /**< The destructor of the class. */
|
||||
};
|
||||
/**
|
||||
* Setter type which is used to set an #Eina_Value, this function should access one particular property field
|
||||
*/
|
||||
typedef void (*Efl_Object_Property_Reflection_Setter)(Eo *obj, Eina_Value value);
|
||||
|
||||
/**
|
||||
* Getter type which is used to get an #Eina_Value, this function should access one particular property field
|
||||
*/
|
||||
typedef Eina_Value (*Efl_Object_Property_Reflection_Getter)(Eo *obj);
|
||||
|
||||
/**
|
||||
* @struct _Efl_Object_Property_Reflection
|
||||
*
|
||||
* This structure holds one line of the reflection table.
|
||||
* The two fields get and set might be NULL,
|
||||
* the property_name is a normal c string containing the name of the property
|
||||
* that the get and set function changes.
|
||||
*/
|
||||
typedef struct _Efl_Object_Property_Reflection{
|
||||
const char *property_name; /**< The name of the property */
|
||||
Efl_Object_Property_Reflection_Setter set; /**< The function used to set a generic #Eina_Value on this property of the object. */
|
||||
Efl_Object_Property_Reflection_Getter get; /**< The function used to retrieve a generic #Eina_Value from this property of the object. */
|
||||
} Efl_Object_Property_Reflection;
|
||||
|
||||
/**
|
||||
* @struct _Efl_Object_Property_Reflection_Ops
|
||||
*
|
||||
* This structure holds the reflection table and the size of this table.
|
||||
*/
|
||||
typedef struct _Efl_Object_Property_Reflection_Ops
|
||||
{
|
||||
const Efl_Object_Property_Reflection *table; /**< The reflection table. */
|
||||
size_t count; /**< Number of table lines descriptions. */
|
||||
} Efl_Object_Property_Reflection_Ops;
|
||||
|
||||
/**
|
||||
* @typedef Efl_Class_Description
|
||||
|
@ -860,10 +894,11 @@ EAPI const Efl_Class *efl_class_new(const Efl_Class_Description *desc, const Efl
|
|||
* @return True on success, False otherwise.
|
||||
*
|
||||
* This should only be called from within the initializer function.
|
||||
*
|
||||
* The reflection_table contains a getter and setter per property name. Which are called when either
|
||||
* efl_property_reflection_set() or efl_property_reflection_get() is called.
|
||||
* @see #EFL_DEFINE_CLASS
|
||||
*/
|
||||
EAPI Eina_Bool efl_class_functions_set(const Efl_Class *klass_id, const Efl_Object_Ops *object_ops, const Efl_Object_Ops *class_ops, const void *reflection_table);
|
||||
EAPI Eina_Bool efl_class_functions_set(const Efl_Class *klass_id, const Efl_Object_Ops *object_ops, const Efl_Object_Ops *class_ops, const Efl_Object_Property_Reflection_Ops *reflection_table);
|
||||
|
||||
/**
|
||||
* @brief Override Eo functions of this object.
|
||||
|
@ -1945,6 +1980,25 @@ EAPI Eina_Bool efl_manual_free(Eo *obj);
|
|||
*/
|
||||
EAPI Eina_Bool efl_destructed_is(const Eo *obj);
|
||||
|
||||
/**
|
||||
* @brief Set the given #Eina_Value to the property with the specified \c property_name.
|
||||
* @param obj The object to set the property on
|
||||
* @param property_name The name of the property to modify.
|
||||
* @param value The value to set, the value passed here will be flushed by the function
|
||||
*
|
||||
*/
|
||||
EAPI void efl_property_reflection_set(Eo *obj, const char *property_name, Eina_Value value);
|
||||
|
||||
/**
|
||||
* @brief Retrieve an #Eina_Value containing the current value of the property specified with \c property_name.
|
||||
* @param obj The object to set the property on
|
||||
* @param property_name The name of the property to get.
|
||||
*
|
||||
* @return The value that got returned by the actual property in form of a generic Eina_Value. The user of this API is owning the returned Value.
|
||||
*/
|
||||
EAPI Eina_Value efl_property_reflection_get(Eo *obj, const char *property_name);
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup Efl_Class_Class Eo's Class class.
|
||||
* @{
|
||||
|
|
|
@ -819,7 +819,7 @@ _eo_class_funcs_set(Eo_Vtable *vtable, const Efl_Object_Ops *ops, const _Efl_Cla
|
|||
}
|
||||
|
||||
EAPI Eina_Bool
|
||||
efl_class_functions_set(const Efl_Class *klass_id, const Efl_Object_Ops *object_ops, const Efl_Object_Ops *class_ops, const void *reflection_table)
|
||||
efl_class_functions_set(const Efl_Class *klass_id, const Efl_Object_Ops *object_ops, const Efl_Object_Ops *class_ops, const Efl_Object_Property_Reflection_Ops *reflection_table)
|
||||
{
|
||||
EO_CLASS_POINTER_GOTO(klass_id, klass, err_klass);
|
||||
Efl_Object_Ops empty_ops = { 0 };
|
||||
|
@ -832,6 +832,8 @@ efl_class_functions_set(const Efl_Class *klass_id, const Efl_Object_Ops *object_
|
|||
|
||||
if (!class_ops) class_ops = &empty_ops;
|
||||
|
||||
klass->reflection = reflection_table;
|
||||
|
||||
klass->ops_count = object_ops->count + class_ops->count;
|
||||
|
||||
klass->base_id = _eo_ops_last_id;
|
||||
|
@ -3597,3 +3599,63 @@ static const Eina_Value_Type _EINA_VALUE_TYPE_OBJECT = {
|
|||
};
|
||||
|
||||
EOAPI const Eina_Value_Type *EINA_VALUE_TYPE_OBJECT = &_EINA_VALUE_TYPE_OBJECT;
|
||||
|
||||
static const Efl_Object_Property_Reflection*
|
||||
_efl_class_reflection_find(const _Efl_Class *klass, const char *property_name)
|
||||
{
|
||||
const _Efl_Class **klass_iter = klass->extensions;
|
||||
const Efl_Object_Property_Reflection_Ops *ref = klass->reflection;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; ref && i < ref->count; ++i)
|
||||
{
|
||||
if (eina_streq(property_name, ref->table[i].property_name))
|
||||
return &ref->table[i];
|
||||
}
|
||||
|
||||
if (klass->parent)
|
||||
{
|
||||
const Efl_Object_Property_Reflection *ref;
|
||||
|
||||
ref = _efl_class_reflection_find(klass->parent, property_name);
|
||||
if (ref) return ref;
|
||||
}
|
||||
|
||||
for (; *klass_iter; klass_iter++)
|
||||
{
|
||||
return _efl_class_reflection_find(*klass_iter, property_name);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EAPI void
|
||||
efl_property_reflection_set(Eo *obj_id, const char *property_name, Eina_Value value)
|
||||
{
|
||||
EO_OBJ_POINTER_GOTO(obj_id, obj, end);
|
||||
const Efl_Object_Property_Reflection *reflection = _efl_class_reflection_find(obj->klass, property_name);
|
||||
|
||||
if (!reflection || !reflection->set) goto end;
|
||||
|
||||
reflection->set(obj_id, value);
|
||||
EO_OBJ_DONE(obj_id);
|
||||
return;
|
||||
end:
|
||||
eina_value_flush(&value);
|
||||
EO_OBJ_DONE(obj_id);
|
||||
}
|
||||
|
||||
EAPI Eina_Value
|
||||
efl_property_reflection_get(Eo *obj_id, const char *property_name)
|
||||
{
|
||||
EO_OBJ_POINTER(obj_id, obj);
|
||||
const Efl_Object_Property_Reflection *reflection = _efl_class_reflection_find(obj->klass, property_name);
|
||||
|
||||
if (!reflection || !reflection->get) goto end;
|
||||
|
||||
return reflection->get(obj_id);
|
||||
end:
|
||||
EO_OBJ_DONE(obj_id);
|
||||
|
||||
return EINA_VALUE_EMPTY;
|
||||
}
|
||||
|
|
|
@ -185,6 +185,8 @@ struct _Efl_Class
|
|||
|
||||
const _Efl_Class **mro;
|
||||
|
||||
const Efl_Object_Property_Reflection_Ops *reflection;
|
||||
|
||||
/* cached object for faster allocation */
|
||||
struct {
|
||||
Eina_Trash *trash;
|
||||
|
|
|
@ -20,6 +20,7 @@ static const Efl_Test_Case etc[] = {
|
|||
{ "Eo threaded eo calls", eo_test_threaded_calls },
|
||||
{ "Eo event calls", eo_test_event},
|
||||
{ "Eo lifecycle", eo_test_lifecycle},
|
||||
{ "Eo Reflection", eo_test_reflection},
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
|
|
@ -12,4 +12,5 @@ void eo_test_value(TCase *tc);
|
|||
void eo_test_threaded_calls(TCase *tc);
|
||||
void eo_test_event(TCase *tc);
|
||||
void eo_test_lifecycle(TCase *tc);
|
||||
void eo_test_reflection(TCase *tc);
|
||||
#endif /* _EO_SUITE_H */
|
||||
|
|
|
@ -23,6 +23,16 @@ _a_set(Eo *obj EINA_UNUSED, void *class_data, int a)
|
|||
efl_event_callback_legacy_call(obj, EV_A_CHANGED, &pd->a);
|
||||
}
|
||||
|
||||
static void
|
||||
_a_set_reflect(Eo *obj, Eina_Value value)
|
||||
{
|
||||
int a;
|
||||
|
||||
eina_value_int_convert(&value, &a);
|
||||
simple_a_set(obj, a);
|
||||
eina_value_flush(&value);
|
||||
}
|
||||
|
||||
static int
|
||||
_a_get(Eo *obj EINA_UNUSED, void *class_data)
|
||||
{
|
||||
|
@ -31,6 +41,14 @@ _a_get(Eo *obj EINA_UNUSED, void *class_data)
|
|||
return pd->a;
|
||||
}
|
||||
|
||||
static Eina_Value
|
||||
_a_get_reflect(Eo *obj)
|
||||
{
|
||||
int a = simple_a_get(obj);
|
||||
|
||||
return eina_value_int_init(a);
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_a_print(Eo *obj EINA_UNUSED, void *class_data)
|
||||
{
|
||||
|
@ -103,8 +121,14 @@ _class_initializer(Efl_Class *klass)
|
|||
EFL_OPS_DEFINE(cops,
|
||||
EFL_OBJECT_OP_FUNC(simple_class_hi_print, _class_hi_print),
|
||||
);
|
||||
static const Efl_Object_Property_Reflection reflection_table[] = {
|
||||
{"simple_a", _a_set_reflect, _a_get_reflect},
|
||||
};
|
||||
static const Efl_Object_Property_Reflection_Ops ref_ops = {
|
||||
reflection_table, EINA_C_ARRAY_LENGTH(reflection_table)
|
||||
};
|
||||
|
||||
return efl_class_functions_set(klass, &ops, &cops, NULL);
|
||||
return efl_class_functions_set(klass, &ops, &cops, &ref_ops);
|
||||
}
|
||||
|
||||
static const Efl_Class_Description class_desc = {
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Eo.h>
|
||||
|
||||
#include "eo_suite.h"
|
||||
#include "eo_test_class_simple.h"
|
||||
|
||||
|
||||
EFL_START_TEST(eo_test_reflection_invalid)
|
||||
{
|
||||
Eina_Value numb_val = eina_value_int_init(1337);
|
||||
Eo *simple = efl_new(SIMPLE_CLASS);
|
||||
|
||||
simple_a_set(simple, 22);
|
||||
efl_property_reflection_set(simple, "simple_a_asdf", numb_val);
|
||||
fail_if(efl_property_reflection_get(simple, "simple_a_invalid").type != EINA_VALUE_EMPTY.type);
|
||||
}
|
||||
EFL_END_TEST
|
||||
|
||||
EFL_START_TEST(eo_test_reflection_inherited)
|
||||
{
|
||||
const int numb = 42;
|
||||
int number_ref;
|
||||
Eina_Value numb_val = eina_value_int_init(numb);
|
||||
Eo *simple = efl_new(SIMPLE3_CLASS);
|
||||
|
||||
simple_a_set(simple, 22);
|
||||
efl_property_reflection_set(simple, "simple_a", numb_val);
|
||||
ck_assert_int_eq(simple_a_get(simple), numb);
|
||||
|
||||
simple_a_set(simple, 22);
|
||||
Eina_Value res = efl_property_reflection_get(simple, "simple_a");
|
||||
eina_value_int_convert(&res, &number_ref);
|
||||
ck_assert_int_eq(number_ref, 22);
|
||||
|
||||
}
|
||||
EFL_END_TEST
|
||||
|
||||
EFL_START_TEST(eo_test_reflection_simple)
|
||||
{
|
||||
const int numb = 42;
|
||||
int number_ref;
|
||||
Eina_Value numb_val = eina_value_int_init(numb);
|
||||
Eo *simple = efl_new(SIMPLE_CLASS);
|
||||
|
||||
simple_a_set(simple, 22);
|
||||
efl_property_reflection_set(simple, "simple_a", numb_val);
|
||||
ck_assert_int_eq(simple_a_get(simple), numb);
|
||||
|
||||
simple_a_set(simple, 22);
|
||||
Eina_Value res = efl_property_reflection_get(simple, "simple_a");
|
||||
eina_value_int_convert(&res, &number_ref);
|
||||
ck_assert_int_eq(number_ref, 22);
|
||||
}
|
||||
EFL_END_TEST
|
||||
|
||||
void eo_test_reflection(TCase *tc)
|
||||
{
|
||||
tcase_add_test(tc, eo_test_reflection_simple);
|
||||
tcase_add_test(tc, eo_test_reflection_inherited);
|
||||
tcase_add_test(tc, eo_test_reflection_invalid);
|
||||
}
|
|
@ -17,7 +17,8 @@ eo_suite_src = [
|
|||
'eo_test_event.c',
|
||||
'eo_test_threaded_calls.c',
|
||||
'eo_test_init.c',
|
||||
'eo_test_lifecycle.c'
|
||||
'eo_test_lifecycle.c',
|
||||
'eo_test_reflection.c'
|
||||
]
|
||||
|
||||
eo_suite = executable('eo_suite',
|
||||
|
|
Loading…
Reference in New Issue