diff options
author | Mike Blumenkrantz <zmike@samsung.com> | 2019-02-04 10:42:25 -0500 |
---|---|---|
committer | Marcel Hollerbach <mail@marcel-hollerbach.de> | 2019-02-04 19:31:17 +0100 |
commit | c946b1477dcaf35830ed66c409615f926ef0931b (patch) | |
tree | ebd998660ace6cbd4b77592947616daee555a4b1 /src | |
parent | 305f77607cdd5e089424fc68ffa888df70f269ce (diff) | |
download | efl-c946b1477dcaf35830ed66c409615f926ef0931b.tar.gz |
eo: implement class overriding (+unit tests)
this enables an app or a platform to add an override for a given class,
then return a different object when that class is created. the benefit is
that a class can be internally customized by the app without needing to
modify upstream versions of that class
@feature
fix T7516
Reviewed-by: Marcel Hollerbach <marcel-hollerbach@t-online.de>
Differential Revision: https://phab.enlightenment.org/D7702
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/eo/Eo.h | 27 | ||||
-rw-r--r-- | src/lib/eo/eo.c | 34 | ||||
-rw-r--r-- | src/tests/eo/suite/eo_test_general.c | 27 |
3 files changed, 88 insertions, 0 deletions
diff --git a/src/lib/eo/Eo.h b/src/lib/eo/Eo.h index de71a698b3..b86a556fe9 100644 --- a/src/lib/eo/Eo.h +++ b/src/lib/eo/Eo.h @@ -1517,6 +1517,33 @@ EAPI Eo * _efl_add_internal_start(const char *file, int line, const Efl_Class *k EAPI void efl_del(const Eo *obj); /** + * @brief Set an override for a class + * + * This can be used to override a class with another class such that when @p klass is added + * with efl_add(), an object of type @p override is returned. + * + * @param[in] klass The class to be overridden + * @param[in] override The class to override with; must inherit from or implement @p klass + * @return Return @c true if the override was successfully set + * + * @ingroup Efl_Object + */ +EAPI Eina_Bool efl_class_override_register(const Efl_Class *klass, const Efl_Class *override); + +/** + * @brief Unset an override for a class + * + * This is used to unset a previously-set override on a given class. It will only succeed if + * @p override is the currently-set override for @p klass. + * + * @param[in] klass The class to unset the override from + * @param[in] override The class override to be removed + * @return Return @c true if the override was successfully unset + * + * @ingroup Efl_Object + */ +EAPI Eina_Bool efl_class_override_unregister(const Efl_Class *klass, const Efl_Class *override); +/** * @brief Get a pointer to the data of an object for a specific class. * * The data reference count is not incremented. The pointer must be used only diff --git a/src/lib/eo/eo.c b/src/lib/eo/eo.c index 8f711d8e4a..c39777b14c 100644 --- a/src/lib/eo/eo.c +++ b/src/lib/eo/eo.c @@ -44,6 +44,7 @@ int _eo_log_dom = -1; Eina_Thread _efl_object_main_thread; static unsigned int efl_del_api_generation = 0; static Efl_Object_Op _efl_del_api_op_id = 0; +static Eina_Hash *class_overrides; typedef enum _Eo_Ref_Op { EO_REF_OP_NONE, @@ -868,6 +869,12 @@ _efl_add_internal_start(const char *file, int line, const Efl_Class *klass_id, E if (is_fallback) fptr = _efl_add_fallback_stack_push(NULL); + if (class_overrides) + { + const Efl_Class *override = eina_hash_find(class_overrides, &klass_id); + if (override) klass_id = override; + } + EO_CLASS_POINTER_GOTO_PROXY(klass_id, klass, err_klass); // Check that in the case of efl_add we do pass a parent. @@ -2597,6 +2604,33 @@ efl_compatible(const Eo *obj, const Eo *obj_target) } EAPI Eina_Bool +efl_class_override_register(const Efl_Class *klass, const Efl_Class *override) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(klass, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(override, EINA_FALSE); + EINA_SAFETY_ON_TRUE_RETURN_VAL(!efl_isa(override, klass), EINA_FALSE); + if (!class_overrides) + class_overrides = eina_hash_pointer_new(NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(class_overrides, EINA_FALSE); + + eina_hash_set(class_overrides, &klass, override); + return EINA_TRUE; +} + +EAPI Eina_Bool +efl_class_override_unregister(const Efl_Class *klass, const Efl_Class *override) +{ + const Efl_Class *set; + EINA_SAFETY_ON_NULL_RETURN_VAL(klass, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(override, EINA_FALSE); + if (!class_overrides) return EINA_TRUE; + + set = eina_hash_find(class_overrides, &klass); + if (set != override) return EINA_FALSE; + return eina_hash_del_by_key(class_overrides, &klass); +} + +EAPI Eina_Bool efl_destructed_is(const Eo *obj_id) { Eina_Bool is; diff --git a/src/tests/eo/suite/eo_test_general.c b/src/tests/eo/suite/eo_test_general.c index a8e6391b2e..fac8c70bb5 100644 --- a/src/tests/eo/suite/eo_test_general.c +++ b/src/tests/eo/suite/eo_test_general.c @@ -1798,11 +1798,38 @@ EFL_START_TEST(efl_object_size) } EFL_END_TEST +EFL_START_TEST(eo_test_class_replacement) +{ + Eo *obj; + + /* test basic override */ + ck_assert(efl_class_override_register(SIMPLE_CLASS, SIMPLE3_CLASS)); + obj = efl_add_ref(SIMPLE_CLASS, NULL); + fail_if(!obj); + ck_assert_ptr_eq(efl_class_get(obj), SIMPLE3_CLASS); + efl_unref(obj); + + /* test overriding with non-inheriting class */ + ck_assert(!efl_class_override_register(SIMPLE_CLASS, SIMPLE2_CLASS)); + + /* test removing an invalid override */ + ck_assert(!efl_class_override_unregister(SIMPLE_CLASS, SIMPLE2_CLASS)); + + /* test removing an override */ + ck_assert(efl_class_override_unregister(SIMPLE_CLASS, SIMPLE3_CLASS)); + obj = efl_add_ref(SIMPLE_CLASS, NULL); + fail_if(!obj); + ck_assert_ptr_eq(efl_class_get(obj), SIMPLE_CLASS); + efl_unref(obj); +} +EFL_END_TEST + void eo_test_general(TCase *tc) { tcase_add_test(tc, eo_simple); tcase_add_test(tc, eo_singleton); tcase_add_test(tc, efl_object_override_tests); + tcase_add_test(tc, eo_test_class_replacement); tcase_add_test(tc, eo_signals); tcase_add_test(tc, efl_data_fetch); tcase_add_test(tc, efl_data_safe_fetch); |