more efficient model properties based on struct.
authorbarbieri <barbieri@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Tue, 24 Jan 2012 22:17:57 +0000 (22:17 +0000)
committerbarbieri <barbieri@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Tue, 24 Jan 2012 22:17:57 +0000 (22:17 +0000)
this is a killer, should be very efficient in memory and speed to
set/get items: instead of a hash of properties, keep them in a C
struct!

The constraint is that properties have fixed types defined at compile
time and cannot be deleted, but this is expected in many cases (ie:
esql rows).

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/eina@67517 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/include/eina_model.h
src/lib/eina_model.c
src/tests/eina_test_model.c

index 958b31c..640e697 100644 (file)
@@ -714,11 +714,32 @@ EAPI extern const Eina_Model_Type *EINA_MODEL_TYPE_MIXIN;
  * Should be generic enough to hold lots of items with runtime
  * configurable properties of any type.
  *
+ * @see #EINA_MODEL_TYPE_STRUCT
+ *
  * @since 1.2
  */
 EAPI extern const Eina_Model_Type *EINA_MODEL_TYPE_GENERIC;
 
 /**
+ * @var EINA_MODEL_TYPE_STRUCT
+ *
+ * Subclass of #EINA_MODEL_TYPE_MIXIN that uses
+ * #EINA_MODEL_INTERFACE_PROPERTIES_STRUCT and
+ * #EINA_MODEL_INTERFACE_CHILDREN_INARRAY.
+ *
+ * Should be struct enough to hold lots of items with compile time
+ * configurable properties of any type.
+ *
+ * @see #EINA_MODEL_TYPE_GENERIC
+ *
+ * @since 1.2
+ */
+EAPI extern const Eina_Model_Type *EINA_MODEL_TYPE_STRUCT;
+
+EAPI Eina_Model *eina_model_struct_new(const Eina_Value_Struct_Desc *desc) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT EINA_MALLOC;
+
+
+/**
  * @var EINA_MODEL_INTERFACE_NAME_PROPERTIES
  *
  * Interface that uses #Eina_Model_Interface_Properties as
@@ -775,10 +796,66 @@ EAPI Eina_List *eina_model_interface_properties_names_list_get(const Eina_Model_
  *       hash data type. For huge number of elements it's better to
  *       use custom implementation instead.
  *
+ * @see EINA_MODEL_INTERFACE_PROPERTIES_STRUCT
+ *
  * @since 1.2
  */
 EAPI extern const Eina_Model_Interface *EINA_MODEL_INTERFACE_PROPERTIES_HASH;
 
+/**
+ * @var EINA_MODEL_INTERFACE_PROPERTIES_STRUCT
+ *
+ * Implements #Eina_Model_Interface_Properties
+ * (#EINA_MODEL_INTERFACE_NAME_PROPERTIES) using #Eina_Value_Struct.
+ *
+ * The interface private data is #Eina_Value of type
+ * #EINA_VALUE_TYPE_STRUCT. Properties will be accessed using
+ * #Eina_Value_Struct::desc information that can be set by types such
+ * as #EINA_MODEL_TYPE_STRUCT
+ *
+ * @see EINA_MODEL_INTERFACE_PROPERTIES_HASH
+ *
+ * @since 1.2
+ */
+EAPI extern const Eina_Model_Interface *EINA_MODEL_INTERFACE_PROPERTIES_STRUCT;
+
+/**
+ * @brief Configure the internal properties of model implementing #EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.
+ *
+ * @param model The model instance to configure.
+ * @param desc The structure description to use.
+ * @param memory If not @c NULL, will be adopted by model.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This will setup the internal pointers so that the given @a desc is
+ * used to manage the properties of this struct.
+ *
+ * If a given memory is provided, it will be adopted (not copied!),
+ * being free'd when the model is gone.
+ *
+ * @see #EINA_VALUE_TYPE_STRUCT
+ *
+ * @since 1.2
+ */
+EAPI Eina_Bool eina_model_struct_set(Eina_Model *model,
+                                     const Eina_Value_Struct_Desc *desc,
+                                     void *memory) EINA_ARG_NONNULL(1, 2);
+/**
+ * @brief Get the internal properties of model implementing #EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.
+ *
+ * @param model the model instance.
+ * @param p_desc where to return the structure description in use.
+ * @param p_memory where to return the structure memory in use.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * No copies are made! The memory and description may be invalidaded
+ * by calls to eina_model_struct_set() or eina_model_del().
+ *
+ * @since 1.2
+ */
+EAPI Eina_Bool eina_model_struct_get(const Eina_Model *model,
+                                     const Eina_Value_Struct_Desc **p_desc,
+                                     void **p_memory) EINA_ARG_NONNULL(1, 2);
 
 /**
  * @var EINA_MODEL_INTERFACE_NAME_CHILDREN
index d9452cb..fc37203 100644 (file)
@@ -2493,13 +2493,189 @@ static const Eina_Model_Interface _EINA_MODEL_INTERFACE_PROPERTIES_HASH = {
   &_EINA_MODEL_INTERFACE_PROPERTIES_HASH_VALUE
 };
 
-/* TODO: properties using Eina_Value_Type_Struct
- *
- * Would be bit more cumbersome to do, as the user still needs to
- * derivate the interface to specify the Eina_Value_Struct_Desc, but
- * given this struct everything should be easy to do (query it for
- * valid properties and their type, covert type if needed).
- */
+/* EINA_MODEL_INTERFACE_PROPERTIES_STRUCT ******************************/
+
+static Eina_Value_Struct *
+_eina_model_interface_properties_struct_private_get(const Eina_Model *model)
+{
+   Eina_Value *val = eina_model_interface_private_data_get
+     (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT);
+   return val->value.ptr;
+}
+
+#define EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_GET(model)         \
+  Eina_Value_Struct *priv =                                       \
+    _eina_model_interface_properties_struct_private_get(model)
+
+static Eina_Bool
+_eina_model_interface_properties_struct_setup(Eina_Model *model)
+{
+   Eina_Value *val = eina_model_interface_private_data_get
+     (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT);
+
+   DBG("setup interface properties (struct) at %p model %p (%s)",
+       val, model, model->desc->cache.types[0]->name);
+
+   return eina_value_setup(val, EINA_VALUE_TYPE_STRUCT);
+}
+
+static Eina_Bool
+_eina_model_interface_properties_struct_flush(Eina_Model *model)
+{
+   Eina_Value *val = eina_model_interface_private_data_get
+     (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT);
+
+   DBG("flush interface properties (struct) at %p model %p (%s)",
+       val, model, model->desc->cache.types[0]->name);
+
+   if (val->type)
+     {
+        ERR("interface properties flushed with values! val=%p, model %p (%s)",
+            val, model, model->desc->cache.types[0]->name);
+        eina_value_flush(val);
+     }
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_eina_model_interface_properties_struct_constructor(Eina_Model *model)
+{
+   EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_GET(model);
+
+   DBG("construct interface properties (struct) at %p model %p (%s)",
+       priv, model, model->desc->cache.types[0]->name);
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_eina_model_interface_properties_struct_destructor(Eina_Model *model)
+{
+   Eina_Value *val = eina_model_interface_private_data_get
+     (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT);
+
+   DBG("destroy interface properties (struct) at %p model %p (%s)",
+       val, model, model->desc->cache.types[0]->name);
+
+   eina_value_flush(val);
+   val->type = NULL;
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_eina_model_interface_properties_struct_get(const Eina_Model *model, const char *name, Eina_Value *val)
+{
+   EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_GET(model);
+   const Eina_Value_Struct_Member *m;
+   const void *p;
+
+   /* highly optimized, but duplicates code from eina_inline_value.x */
+
+   m = eina_value_struct_member_find(priv, name);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(m, EINA_FALSE);
+
+   p = eina_value_struct_member_memory_get(priv, m);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(p, EINA_FALSE);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_setup(val, m->type), EINA_FALSE);
+   EINA_SAFETY_ON_FALSE_GOTO(eina_value_pset(val, p), error);
+   return EINA_TRUE;
+
+ error:
+   eina_value_flush(val);
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_eina_model_interface_properties_struct_set(Eina_Model *model, const char *name, const Eina_Value *val)
+{
+   EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_GET(model);
+   const Eina_Value_Struct_Member *m;
+   const void *src;
+   void *dst;
+
+   /* highly optimized, but duplicates code from eina_inline_value.x */
+
+   m = eina_value_struct_member_find(priv, name);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(m, EINA_FALSE);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(val->type == m->type, EINA_FALSE);
+
+   dst = eina_value_struct_member_memory_get(priv, m);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(dst, EINA_FALSE);
+   src = eina_value_memory_get(val);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(src, EINA_FALSE);
+
+   eina_value_type_flush(m->type, dst);
+   if (!eina_value_type_setup(m->type, dst)) goto error_setup;
+   if (!eina_value_type_pset(m->type, dst, src)) goto error_set;
+   return EINA_TRUE;
+
+ error_set:
+   eina_value_type_flush(m->type, dst);
+ error_setup:
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_eina_model_interface_properties_struct_del(Eina_Model *model __UNUSED__, const char *name __UNUSED__)
+{
+   return EINA_FALSE; /* not allowed */
+}
+
+static Eina_List *
+_eina_model_interface_properties_struct_names_list(const Eina_Model *model)
+{
+   EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_GET(model);
+   const Eina_Value_Struct_Member *itr;
+   Eina_List *list = NULL;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(priv, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(priv->desc, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(priv->desc->members, NULL);
+
+   itr = priv->desc->members;
+   if (priv->desc->member_count)
+     {
+        const Eina_Value_Struct_Member *end = itr + priv->desc->member_count;
+        for (; itr < end; itr++)
+          list = eina_list_append(list, eina_stringshare_add(itr->name));
+     }
+   else
+     {
+        for (; itr->name != NULL; itr++)
+          list = eina_list_append(list, eina_stringshare_add(itr->name));
+     }
+
+   return list;
+}
+#undef EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_GET
+
+static const Eina_Model_Interface_Properties _EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_VALUE = {
+  EINA_MODEL_INTERFACE_PROPERTIES_VERSION,
+  NULL, /* no compare */
+  NULL, /* no load */
+  NULL, /* no unload */
+  _eina_model_interface_properties_struct_get,
+  _eina_model_interface_properties_struct_set,
+  _eina_model_interface_properties_struct_del,
+  _eina_model_interface_properties_struct_names_list
+};
+
+static const Eina_Model_Interface _EINA_MODEL_INTERFACE_PROPERTIES_STRUCT = {
+  EINA_MODEL_INTERFACE_VERSION,
+  sizeof(Eina_Value),
+  _EINA_MODEL_INTERFACE_NAME_PROPERTIES,
+  NULL, /* no parent interfaces */
+  NULL, /* no extra events */
+  _eina_model_interface_properties_struct_setup,
+  _eina_model_interface_properties_struct_flush,
+  _eina_model_interface_properties_struct_constructor,
+  _eina_model_interface_properties_struct_destructor,
+  NULL,
+  NULL,
+  &_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_VALUE
+};
 
 /* EINA_MODEL_INTERFACE_CHILDREN_INARRAY ******************************/
 
@@ -2720,6 +2896,50 @@ static const Eina_Model_Type _EINA_MODEL_TYPE_GENERIC = {
   NULL  /* inherit from mix-in */
 };
 
+/* EINA_MODEL_TYPE_STRUCT ********************************************/
+
+static const Eina_Model_Interface *_EINA_MODEL_TYPE_STRUCT_IFACES[] = {
+  &_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT,
+  &_EINA_MODEL_INTERFACE_CHILDREN_INARRAY,
+  NULL
+};
+
+static const Eina_Model_Type _EINA_MODEL_TYPE_STRUCT = {
+  EINA_MODEL_TYPE_VERSION,
+  0,
+  "Eina_Model_Type_Struct",
+  &_EINA_MODEL_TYPE_MIXIN,
+  _EINA_MODEL_TYPE_STRUCT_IFACES,
+  NULL, /* inherit from mix-in */
+  NULL, /* inherit from mix-in */
+  NULL, /* inherit from mix-in */
+  NULL, /* inherit from mix-in */
+  NULL, /* inherit from mix-in */
+  NULL, /* inherit from mix-in */
+  NULL, /* inherit from mix-in */
+  NULL, /* inherit from mix-in */
+  NULL, /* inherit from mix-in */
+  NULL, /* inherit from mix-in */
+  NULL, /* inherit from mix-in */
+  NULL, /* inherit from mix-in */
+  NULL, /* inherit from mix-in */
+  NULL, /* inherit from mix-in */
+  NULL, /* inherit from mix-in */
+  NULL, /* inherit from mix-in */
+  NULL, /* inherit from mix-in */
+  NULL, /* inherit from mix-in */
+  NULL, /* inherit from mix-in */
+  NULL, /* inherit from mix-in */
+  NULL, /* inherit from mix-in */
+  NULL, /* inherit from mix-in */
+  NULL, /* inherit from mix-in */
+  NULL, /* inherit from mix-in */
+  NULL, /* inherit from mix-in */
+  NULL, /* inherit from mix-in */
+  NULL, /* inherit from mix-in */
+  NULL  /* inherit from mix-in */
+};
+
 /**
  */
 
@@ -2799,8 +3019,10 @@ eina_model_init(void)
    EINA_MODEL_TYPE_BASE = &_EINA_MODEL_TYPE_BASE;
    EINA_MODEL_TYPE_MIXIN = &_EINA_MODEL_TYPE_MIXIN;
    EINA_MODEL_TYPE_GENERIC = &_EINA_MODEL_TYPE_GENERIC;
+   EINA_MODEL_TYPE_STRUCT = &_EINA_MODEL_TYPE_STRUCT;
 
    EINA_MODEL_INTERFACE_PROPERTIES_HASH = &_EINA_MODEL_INTERFACE_PROPERTIES_HASH;
+   EINA_MODEL_INTERFACE_PROPERTIES_STRUCT = &_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT;
 
    EINA_MODEL_INTERFACE_CHILDREN_INARRAY = &_EINA_MODEL_INTERFACE_CHILDREN_INARRAY;
 
@@ -2881,8 +3103,10 @@ EAPI Eina_Error EINA_ERROR_MODEL_METHOD_MISSING = 0;
 EAPI const Eina_Model_Type *EINA_MODEL_TYPE_BASE = NULL;
 EAPI const Eina_Model_Type *EINA_MODEL_TYPE_MIXIN = NULL;
 EAPI const Eina_Model_Type *EINA_MODEL_TYPE_GENERIC = NULL;
+EAPI const Eina_Model_Type *EINA_MODEL_TYPE_STRUCT = NULL;
 
 EAPI const Eina_Model_Interface *EINA_MODEL_INTERFACE_PROPERTIES_HASH = NULL;
+EAPI const Eina_Model_Interface *EINA_MODEL_INTERFACE_PROPERTIES_STRUCT = NULL;
 EAPI const Eina_Model_Interface *EINA_MODEL_INTERFACE_CHILDREN_INARRAY = NULL;
 
 EAPI const char *EINA_MODEL_INTERFACE_NAME_PROPERTIES = "Eina_Model_Interface_Properties";
@@ -4846,3 +5070,68 @@ eina_model_interface_children_sort(const Eina_Model_Interface *iface, Eina_Model
    EINA_SAFETY_ON_NULL_RETURN(sort);
    return sort(model, compare);
 }
+
+static Eina_Bool
+_eina_model_struct_set(Eina_Model *m, const Eina_Value_Struct_Desc *desc, void *memory)
+{
+   Eina_Value_Struct st = {desc, memory};
+   Eina_Value *val = eina_model_interface_private_data_get
+     (m, &_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT);
+   return eina_value_pset(val, &st);
+}
+
+EAPI Eina_Model *
+eina_model_struct_new(const Eina_Value_Struct_Desc *desc)
+{
+   Eina_Model *m;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(desc, NULL);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL
+     (desc->version == EINA_VALUE_STRUCT_DESC_VERSION, NULL);
+
+   m = eina_model_new(EINA_MODEL_TYPE_STRUCT);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
+
+   EINA_SAFETY_ON_FALSE_GOTO(_eina_model_struct_set(m, desc, NULL), error);
+   return m;
+
+ error:
+   eina_model_del(m);
+   return NULL;
+}
+
+EAPI Eina_Bool
+eina_model_struct_set(Eina_Model *model, const Eina_Value_Struct_Desc *desc, void *memory)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(desc, EINA_FALSE);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL
+     (desc->version == EINA_VALUE_STRUCT_DESC_VERSION, EINA_FALSE);
+   EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL
+     (&_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT, model, EINA_FALSE);
+
+   return _eina_model_struct_set(model, desc, memory);
+}
+
+EAPI Eina_Bool
+eina_model_struct_get(const Eina_Model *model, const Eina_Value_Struct_Desc **p_desc, void **p_memory)
+{
+   const Eina_Value *val;
+   Eina_Value_Struct st;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(p_desc, EINA_FALSE);
+
+   *p_desc = NULL;
+   if (p_memory) *p_memory = NULL;
+
+   EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL
+     (&_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT, model, EINA_FALSE);
+
+   val = eina_model_interface_private_data_get
+     (model, &_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT);
+
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_pget(val, &st), EINA_FALSE);
+
+   *p_desc = st.desc;
+   if (p_memory) *p_memory = st.memory;
+   return EINA_FALSE;
+}
index 90b0bb3..0eb516d 100644 (file)
@@ -51,6 +51,30 @@ _eina_test_model_check_safety_null(const Eina_Log_Domain *d, Eina_Log_Level leve
 }
 
 static void
+_eina_test_model_check_safety_false(const Eina_Log_Domain *d, Eina_Log_Level level, const char *file, const char *fnc, int line, const char *fmt, void *data, va_list args)
+{
+   Eina_Bool *ck = data;
+
+   if ((level == EINA_LOG_LEVEL_ERR) && (strcmp(fmt, "%s") == 0))
+     {
+        const char *str;
+        va_list cp_args;
+
+        va_copy(cp_args, args);
+        str = va_arg(cp_args, const char *);
+        va_end(cp_args);
+        if (eina_str_has_prefix(str, "safety check failed: ") &&
+            eina_str_has_suffix(str, " is false"))
+          {
+             *ck = EINA_TRUE;
+             return;
+          }
+     }
+   *ck = EINA_FALSE;
+   eina_log_print_cb_stderr(d, level, file, fnc, line, fmt, NULL, args);
+}
+
+static void
 _eina_test_model_cb_count(void *data, Eina_Model *model, const Eina_Model_Event_Description *desc, void *event_info)
 {
    unsigned *count = data;
@@ -213,7 +237,6 @@ START_TEST(eina_model_test_children)
    char *s;
    int i;
 
-   printf("eina_model_test_children: BEGIN\n");
    eina_init();
 
    m = eina_model_new(EINA_MODEL_TYPE_GENERIC);
@@ -321,7 +344,6 @@ START_TEST(eina_model_test_children)
    ck_assert_int_eq(count_cdel, 2);
 
    eina_shutdown();
-   printf("eina_model_test_children: END\n");
 }
 END_TEST
 
@@ -717,6 +739,120 @@ START_TEST(eina_model_test_child_filtered_iterator)
 }
 END_TEST
 
+START_TEST(eina_model_test_struct)
+{
+   unsigned int count_del = 0, count_pset = 0, count_pdel = 0;
+   Eina_Model *m;
+   struct myst {
+      int i;
+      char c;
+   };
+   const Eina_Value_Struct_Member myst_members[] = {
+     {"i", EINA_VALUE_TYPE_INT, 0},
+     {"c", EINA_VALUE_TYPE_CHAR, 4},
+     {NULL, NULL, 0}
+   };
+   const Eina_Value_Struct_Desc myst_desc = {
+     EINA_VALUE_STRUCT_DESC_VERSION,
+     NULL, myst_members, 2, sizeof(struct myst)
+   };
+   Eina_Value inv, outv;
+   int i;
+   char c;
+   Eina_List *lst;
+   Eina_Bool ck;
+
+   eina_init();
+
+   m = eina_model_struct_new(&myst_desc);
+   fail_unless(m != NULL);
+
+   eina_model_event_callback_add
+     (m, "deleted", _eina_test_model_cb_count, &count_del);
+   eina_model_event_callback_add
+     (m, "property,set", _eina_test_model_cb_count, &count_pset);
+   eina_model_event_callback_add
+     (m, "property,deleted", _eina_test_model_cb_count, &count_pdel);
+
+   fail_unless(eina_value_setup(&inv, EINA_VALUE_TYPE_INT));
+   fail_unless(eina_value_set(&inv, 1234));
+   fail_unless(eina_value_get(&inv, &i));
+   ck_assert_int_eq(i, 1234);
+   fail_unless(eina_model_property_set(m, "i", &inv));
+
+   eina_value_flush(&inv);
+   fail_unless(eina_value_setup(&inv, EINA_VALUE_TYPE_CHAR));
+   fail_unless(eina_value_set(&inv, 33));
+   fail_unless(eina_value_get(&inv, &c));
+   ck_assert_int_eq(c, 33);
+   fail_unless(eina_model_property_set(m, "c", &inv));
+
+   lst = eina_model_properties_names_list_get(m);
+   ck_assert_int_eq(eina_list_count(lst), 2);
+
+   lst = eina_list_sort(lst, 0, EINA_COMPARE_CB(strcmp));
+   ck_assert_str_eq("c", eina_list_nth(lst, 0));
+   ck_assert_str_eq("i", eina_list_nth(lst, 1));
+
+   eina_model_properties_names_list_free(lst);
+
+   fail_unless(eina_model_property_get(m, "i", &outv));
+   fail_unless(outv.type == EINA_VALUE_TYPE_INT);
+   fail_unless(eina_value_get(&outv, &i));
+   ck_assert_int_eq(i, 1234);
+   eina_value_flush(&outv);
+
+   fail_unless(eina_model_property_get(m, "c", &outv));
+   fail_unless(outv.type == EINA_VALUE_TYPE_CHAR);
+   fail_unless(eina_value_get(&outv, &c));
+   ck_assert_int_eq(c, 33);
+   eina_value_flush(&outv);
+
+   eina_value_flush(&inv);
+
+   /* negative test (check safety was displayed by using print_cb) */
+   eina_log_print_cb_set(_eina_test_model_check_safety_null, &ck);
+
+   ck = EINA_FALSE;
+   fail_if(eina_model_property_get(m, "non-existent", &outv));
+   fail_unless(ck == EINA_TRUE);
+
+   ck = EINA_FALSE;
+   fail_if(eina_model_property_get(m, NULL, &outv));
+   fail_unless(ck == EINA_TRUE);
+
+   fail_unless(eina_value_setup(&inv, EINA_VALUE_TYPE_STRING));
+   fail_unless(eina_value_set(&inv, "hello world"));
+
+   eina_log_print_cb_set(_eina_test_model_check_safety_false, &ck);
+
+   ck = EINA_FALSE;
+   fail_if(eina_model_property_set(m, "i", &inv));
+   fail_unless(ck == EINA_TRUE);
+
+   ck = EINA_FALSE;
+   fail_if(eina_model_property_set(m, "c", &inv));
+   fail_unless(ck == EINA_TRUE);
+
+   /* revert print_cb to default */
+   eina_log_print_cb_set(eina_log_print_cb_stderr, NULL);
+
+   fail_if(eina_model_property_del(m, "value"));
+   fail_if(eina_model_property_del(m, "i"));
+   fail_if(eina_model_property_del(m, "c"));
+
+   eina_value_flush(&inv);
+
+   ck_assert_int_eq(eina_model_refcount(m), 1);
+
+   eina_model_unref(m);
+   ck_assert_int_eq(count_del, 1);
+   ck_assert_int_eq(count_pset, 2);
+   ck_assert_int_eq(count_pdel, 0);
+   eina_shutdown();
+}
+END_TEST
+
 void
 eina_test_model(TCase *tc)
 {
@@ -728,4 +864,5 @@ eina_test_model(TCase *tc)
    tcase_add_test(tc, eina_model_test_child_reversed_iterator);
    tcase_add_test(tc, eina_model_test_child_sorted_iterator);
    tcase_add_test(tc, eina_model_test_child_filtered_iterator);
+   tcase_add_test(tc, eina_model_test_struct);
 }