summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Hollerbach <mail@marcel-hollerbach.de>2019-02-05 15:40:41 +0100
committerMarcel Hollerbach <mail@marcel-hollerbach.de>2019-02-07 14:43:25 +0100
commit0f32bb90476703f81fd08800eda0a0d89321f80f (patch)
tree97f71bd6fedc72e0609e0e807527de0da4a54072
parent0709bdea6f94149b6b319461edd27b7a0035552d (diff)
downloadefl-0f32bb90476703f81fd08800eda0a0d89321f80f.tar.gz
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
-rw-r--r--src/Makefile_Eo.am3
-rw-r--r--src/lib/eo/Eo.h58
-rw-r--r--src/lib/eo/eo.c64
-rw-r--r--src/lib/eo/eo_private.h2
-rw-r--r--src/tests/eo/suite/eo_suite.c1
-rw-r--r--src/tests/eo/suite/eo_suite.h1
-rw-r--r--src/tests/eo/suite/eo_test_class_simple.c28
-rw-r--r--src/tests/eo/suite/eo_test_reflection.c66
-rw-r--r--src/tests/eo/suite/meson.build3
9 files changed, 219 insertions, 7 deletions
diff --git a/src/Makefile_Eo.am b/src/Makefile_Eo.am
index 43778be897..5b602af246 100644
--- a/src/Makefile_Eo.am
+++ b/src/Makefile_Eo.am
@@ -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)\" \
diff --git a/src/lib/eo/Eo.h b/src/lib/eo/Eo.h
index 1406984964..d258a47df4 100644
--- a/src/lib/eo/Eo.h
+++ b/src/lib/eo/Eo.h
@@ -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.
@@ -1946,6 +1981,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.
* @{
*/
diff --git a/src/lib/eo/eo.c b/src/lib/eo/eo.c
index 0d1ae5b64c..beed05914d 100644
--- a/src/lib/eo/eo.c
+++ b/src/lib/eo/eo.c
@@ -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;
+}
diff --git a/src/lib/eo/eo_private.h b/src/lib/eo/eo_private.h
index 7145faaea2..7c7ae9e4a8 100644
--- a/src/lib/eo/eo_private.h
+++ b/src/lib/eo/eo_private.h
@@ -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;
diff --git a/src/tests/eo/suite/eo_suite.c b/src/tests/eo/suite/eo_suite.c
index 57b7c613f3..fe8e419e0f 100644
--- a/src/tests/eo/suite/eo_suite.c
+++ b/src/tests/eo/suite/eo_suite.c
@@ -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 }
};
diff --git a/src/tests/eo/suite/eo_suite.h b/src/tests/eo/suite/eo_suite.h
index 700325c465..84da2054f8 100644
--- a/src/tests/eo/suite/eo_suite.h
+++ b/src/tests/eo/suite/eo_suite.h
@@ -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 */
diff --git a/src/tests/eo/suite/eo_test_class_simple.c b/src/tests/eo/suite/eo_test_class_simple.c
index dfba73f669..8d82b1eb11 100644
--- a/src/tests/eo/suite/eo_test_class_simple.c
+++ b/src/tests/eo/suite/eo_test_class_simple.c
@@ -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),
);
-
- return efl_class_functions_set(klass, &ops, &cops, NULL);
+ 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, &ref_ops);
}
static const Efl_Class_Description class_desc = {
diff --git a/src/tests/eo/suite/eo_test_reflection.c b/src/tests/eo/suite/eo_test_reflection.c
new file mode 100644
index 0000000000..ae1e11b214
--- /dev/null
+++ b/src/tests/eo/suite/eo_test_reflection.c
@@ -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);
+}
diff --git a/src/tests/eo/suite/meson.build b/src/tests/eo/suite/meson.build
index 6e7f4ba6f7..39f73787e7 100644
--- a/src/tests/eo/suite/meson.build
+++ b/src/tests/eo/suite/meson.build
@@ -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',