eina_value: add struct type.
authorbarbieri <barbieri@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Thu, 12 Jan 2012 22:58:31 +0000 (22:58 +0000)
committerbarbieri <barbieri@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Thu, 12 Jan 2012 22:58:31 +0000 (22:58 +0000)
efficient storage with named access, can specify compare, alloc, free
and other operations for even better management.

no changelog/news as this is under eina_value, all new for 1.2 release.

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

src/include/eina_inline_value.x
src/include/eina_value.h
src/lib/eina_value.c
src/tests/eina_test_value.c

index 469fd50..59ec315 100644 (file)
@@ -944,14 +944,14 @@ eina_value_list_vset(Eina_Value *value, unsigned int position, va_list args)
 static inline Eina_Bool
 eina_value_list_vget(const Eina_Value *value, unsigned int position, va_list args)
 {
-   Eina_Value_List *desc;
+   const Eina_Value_List *desc;
    const Eina_List *node;
    const void *mem;
    void *ptr;
    Eina_Bool ret;
 
    EINA_VALUE_TYPE_LIST_CHECK_RETURN_VAL(value, 0);
-   desc = (Eina_Value_List *)eina_value_memory_get(value);
+   desc = (const Eina_Value_List *)eina_value_memory_get(value);
    if (!desc)
      return EINA_FALSE;
 
@@ -1120,13 +1120,13 @@ eina_value_list_pset(Eina_Value *value, unsigned int position, const void *ptr)
 static inline Eina_Bool
 eina_value_list_pget(const Eina_Value *value, unsigned int position, void *ptr)
 {
-   Eina_Value_List *desc;
+   const Eina_Value_List *desc;
    const Eina_List *node;
    const void *mem;
    Eina_Bool ret;
 
    EINA_VALUE_TYPE_LIST_CHECK_RETURN_VAL(value, 0);
-   desc = (Eina_Value_List *)eina_value_memory_get(value);
+   desc = (const Eina_Value_List *)eina_value_memory_get(value);
    if (!desc)
      return EINA_FALSE;
 
@@ -1316,14 +1316,14 @@ eina_value_hash_vset(Eina_Value *value, const char *key, va_list args)
 static inline Eina_Bool
 eina_value_hash_vget(const Eina_Value *value, const char *key, va_list args)
 {
-   Eina_Value_Hash *desc;
+   const Eina_Value_Hash *desc;
    const void *mem;
    void *ptr;
    Eina_Bool ret;
 
    EINA_VALUE_TYPE_HASH_CHECK_RETURN_VAL(value, EINA_FALSE);
    EINA_SAFETY_ON_NULL_RETURN_VAL(key, EINA_FALSE);
-   desc = (Eina_Value_Hash *)eina_value_memory_get(value);
+   desc = (const Eina_Value_Hash *)eina_value_memory_get(value);
    if (!desc)
      return EINA_FALSE;
 
@@ -1403,13 +1403,13 @@ eina_value_hash_pset(Eina_Value *value, const char *key, const void *ptr)
 static inline Eina_Bool
 eina_value_hash_pget(const Eina_Value *value, const char *key, void *ptr)
 {
-   Eina_Value_Hash *desc;
+   const Eina_Value_Hash *desc;
    const void *mem;
    Eina_Bool ret;
 
    EINA_VALUE_TYPE_HASH_CHECK_RETURN_VAL(value, 0);
    EINA_SAFETY_ON_NULL_RETURN_VAL(key, EINA_FALSE);
-   desc = (Eina_Value_Hash *)eina_value_memory_get(value);
+   desc = (const Eina_Value_Hash *)eina_value_memory_get(value);
    if (!desc)
      return EINA_FALSE;
 
@@ -1422,6 +1422,172 @@ eina_value_hash_pget(const Eina_Value *value, const char *key, void *ptr)
 }
 #undef EINA_VALUE_TYPE_HASH_CHECK_RETURN_VAL
 
+#define EINA_VALUE_TYPE_STRUCT_CHECK_RETURN_VAL(value, retval)          \
+  EINA_SAFETY_ON_NULL_RETURN_VAL(value, retval);                        \
+  EINA_SAFETY_ON_FALSE_RETURN_VAL(value->type == EINA_VALUE_TYPE_STRUCT, retval)
+
+/**
+ * @brief Find member of struct
+ * @since 1.2
+ * @internal
+ */
+EAPI const Eina_Value_Struct_Member *eina_value_struct_member_find(const Eina_Value_Struct *st, const char *name) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+
+static inline Eina_Bool
+eina_value_struct_setup(Eina_Value *value, const Eina_Value_Struct_Desc *sdesc)
+{
+   Eina_Value_Struct desc = {sdesc, NULL};
+   if (!eina_value_setup(value, EINA_VALUE_TYPE_STRUCT))
+     return EINA_FALSE;
+   if (!eina_value_pset(value, &desc))
+     {
+        eina_value_flush(value);
+        return EINA_FALSE;
+     }
+   return EINA_TRUE;
+}
+
+static inline void *
+eina_value_struct_member_memory_get(const Eina_Value_Struct *st, const Eina_Value_Struct_Member *member)
+{
+   unsigned char *base = (unsigned char *)st->memory;
+   if (!base) return NULL;
+   return base + member->offset;
+}
+
+static inline Eina_Bool
+eina_value_struct_vset(Eina_Value *value, const char *name, va_list args)
+{
+   const Eina_Value_Struct_Member *member;
+   Eina_Value_Struct *st;
+   void *mem;
+
+   EINA_VALUE_TYPE_STRUCT_CHECK_RETURN_VAL(value, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
+   st = (Eina_Value_Struct *)eina_value_memory_get(value);
+   if (!st)
+     return EINA_FALSE;
+   member = eina_value_struct_member_find(st, name);
+   if (!member)
+     return EINA_FALSE;
+   mem = eina_value_struct_member_memory_get(st, member);
+   if (!mem)
+     return EINA_FALSE;
+
+   eina_value_type_flush(member->type, mem);
+   if (!eina_value_type_setup(member->type, mem)) goto error_setup;
+   if (!eina_value_type_vset(member->type, mem, args)) goto error_set;
+   return EINA_TRUE;
+
+ error_set:
+   eina_value_type_flush(member->type, mem);
+ error_setup:
+   return EINA_FALSE;
+}
+
+static inline Eina_Bool
+eina_value_struct_vget(const Eina_Value *value, const char *name, va_list args)
+{
+   const Eina_Value_Struct_Member *member;
+   const Eina_Value_Struct *st;
+   const void *mem;
+   void *ptr;
+   Eina_Bool ret;
+
+   EINA_VALUE_TYPE_STRUCT_CHECK_RETURN_VAL(value, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
+   st = (const Eina_Value_Struct *)eina_value_memory_get(value);
+   if (!st)
+     return EINA_FALSE;
+   member = eina_value_struct_member_find(st, name);
+   if (!member)
+     return EINA_FALSE;
+   mem = eina_value_struct_member_memory_get(st, member);
+   if (!mem)
+     return EINA_FALSE;
+
+   ptr = va_arg(args, void *);
+   ret = eina_value_type_pget(member->type, mem, ptr);
+   return ret;
+}
+
+static inline Eina_Bool
+eina_value_struct_set(Eina_Value *value, const char *name, ...)
+{
+   va_list args;
+   Eina_Bool ret;
+   va_start(args, name);
+   ret = eina_value_struct_vset(value, name, args);
+   va_end(args);
+   return ret;
+}
+
+static inline Eina_Bool
+eina_value_struct_get(const Eina_Value *value, const char *name, ...)
+{
+   va_list args;
+   Eina_Bool ret;
+   va_start(args, name);
+   ret = eina_value_struct_vget(value, name, args);
+   va_end(args);
+   return ret;
+}
+
+static inline Eina_Bool
+eina_value_struct_pset(Eina_Value *value, const char *name, const void *ptr)
+{
+   const Eina_Value_Struct_Member *member;
+   Eina_Value_Struct *st;
+   void *mem;
+
+   EINA_VALUE_TYPE_STRUCT_CHECK_RETURN_VAL(value, 0);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
+   st = (Eina_Value_Struct *)eina_value_memory_get(value);
+   if (!st)
+     return EINA_FALSE;
+   member = eina_value_struct_member_find(st, name);
+   if (!member)
+     return EINA_FALSE;
+   mem = eina_value_struct_member_memory_get(st, member);
+   if (!mem)
+     return EINA_FALSE;
+
+   eina_value_type_flush(member->type, mem);
+   if (!eina_value_type_setup(member->type, mem)) goto error_setup;
+   if (!eina_value_type_pset(member->type, mem, ptr)) goto error_set;
+   return EINA_TRUE;
+
+ error_set:
+   eina_value_type_flush(member->type, mem);
+ error_setup:
+   return EINA_FALSE;
+}
+
+static inline Eina_Bool
+eina_value_struct_pget(const Eina_Value *value, const char *name, void *ptr)
+{
+   const Eina_Value_Struct_Member *member;
+   const Eina_Value_Struct *st;
+   const void *mem;
+   Eina_Bool ret;
+
+   EINA_VALUE_TYPE_STRUCT_CHECK_RETURN_VAL(value, 0);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
+   st = (const Eina_Value_Struct *)eina_value_memory_get(value);
+   if (!st)
+     return EINA_FALSE;
+   member = eina_value_struct_member_find(st, name);
+   if (!member)
+     return EINA_FALSE;
+   mem = eina_value_struct_member_memory_get(st, member);
+   if (!mem)
+     return EINA_FALSE;
+
+   ret = eina_value_type_pget(member->type, mem, ptr);
+   return ret;
+}
+#undef EINA_VALUE_TYPE_STRUCT_CHECK_RETURN_VAL
+
 
 static inline Eina_Bool
 eina_value_type_setup(const Eina_Value_Type *type, void *mem)
@@ -1460,7 +1626,7 @@ eina_value_type_copy(const Eina_Value_Type *type, const void *src, void *dst)
 }
 
 static inline int
-eina_value_type_compare(const Eina_Value_Type *type, const void *a, void *b)
+eina_value_type_compare(const Eina_Value_Type *type, const void *a, const void *b)
 {
    EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_type_check(type), EINA_FALSE);
    if (!type->compare)
index 7ecf63e..55b465a 100644 (file)
@@ -302,6 +302,28 @@ EAPI extern const Eina_Value_Type *EINA_VALUE_TYPE_TIMEVAL;
 EAPI extern const Eina_Value_Type *EINA_VALUE_TYPE_BLOB;
 
 /**
+ * @var EINA_VALUE_TYPE_STRUCT
+ *
+ * manages struct type. Use the value get/set for structs:
+ *  @li eina_value_struct_get() and eina_value_struct_set()
+ *  @li eina_value_struct_vget() and eina_value_struct_vset()
+ *  @li eina_value_struct_pget() and eina_value_struct_pset()
+ *
+ * eina_value_set() takes an #Eina_Value_Struct where just @c desc is
+ * used. If there is an @c memory, it will be adopted and its contents
+ * must be properly configurable as @c desc expects. eina_value_pset()
+ * takes a pointer to an #Eina_Value_Struct.  For your convenience, use
+ * eina_value_struct_setup().
+ *
+ * eina_value_get() and eina_value_pget() takes a pointer to
+ * #Eina_Value_Struct, it's an exact copy of the current structure in
+ * use by value, no copies are done.
+ *
+ * @since 1.2
+ */
+EAPI extern const Eina_Value_Type *EINA_VALUE_TYPE_STRUCT;
+
+/**
  * @var EINA_ERROR_VALUE_FAILED
  * Error identifier corresponding to value check failure.
  *
@@ -464,6 +486,7 @@ static inline int eina_value_compare(const Eina_Value *a,
  * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash
  * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval
  * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob
+ * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct
  *
  * @code
  *     Eina_Value *value = eina_value_new(EINA_VALUE_TYPE_INT);
@@ -524,6 +547,7 @@ static inline Eina_Bool eina_value_set(Eina_Value *value,
  * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash*
  * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval*
  * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob*
+ * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct*
  *
  * @code
  *     Eina_Value *value = eina_value_new(EINA_VALUE_TYPE_INT);
@@ -626,6 +650,7 @@ static inline Eina_Bool eina_value_vget(const Eina_Value *value,
  * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash*
  * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval*
  * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob*
+ * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct*
  *
  * @note the pointer contents are written using the size defined by
  *       type. It can be larger than void* or uint64_t.
@@ -691,6 +716,7 @@ static inline Eina_Bool eina_value_pset(Eina_Value *value,
  * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash*
  * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval*
  * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob*
+ * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob*
  *
  * @code
  *     Eina_Value *value = eina_value_new(EINA_VALUE_TYPE_INT);
@@ -898,6 +924,7 @@ static inline Eina_Bool eina_value_array_remove(Eina_Value *value,
  * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash
  * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval
  * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob
+ * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct
  *
  * @code
  *     Eina_Value *value = eina_value_array_new(EINA_VALUE_TYPE_INT, 0);
@@ -958,6 +985,7 @@ static inline Eina_Bool eina_value_array_set(Eina_Value *value,
  * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash*
  * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval*
  * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob*
+ * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct*
  *
  * @code
  *     Eina_Value *value = eina_value_array_new(EINA_VALUE_TYPE_INT, 0);
@@ -1006,6 +1034,7 @@ static inline Eina_Bool eina_value_array_get(const Eina_Value *value,
  * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash
  * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval
  * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob
+ * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct
  *
  * @code
  *     Eina_Value *value = eina_value_array_new(EINA_VALUE_TYPE_INT, 0);
@@ -1060,6 +1089,7 @@ static inline Eina_Bool eina_value_array_insert(Eina_Value *value,
  * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash
  * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval
  * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob
+ * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct
  *
  * @code
  *     Eina_Value *value = eina_value_array_new(EINA_VALUE_TYPE_INT, 0);
@@ -1200,6 +1230,7 @@ static inline Eina_Bool eina_value_array_vappend(Eina_Value *value,
  * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash*
  * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval*
  * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob*
+ * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct*
  *
  * @note the pointer contents are written using the size defined by
  *       type. It can be larger than void* or uint64_t.
@@ -1264,6 +1295,7 @@ static inline Eina_Bool eina_value_array_pset(Eina_Value *value,
  * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash*
  * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval*
  * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob*
+ * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct*
  *
  * @code
  *     Eina_Value *value = eina_value_array_new(EINA_VALUE_TYPE_INT, 0);
@@ -1313,6 +1345,7 @@ static inline Eina_Bool eina_value_array_pget(const Eina_Value *value,
  * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash*
  * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval*
  * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob*
+ * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct*
  *
  * @note the pointer contents are written using the size defined by
  *       type. It can be larger than void* or uint64_t.
@@ -1370,6 +1403,7 @@ static inline Eina_Bool eina_value_array_pinsert(Eina_Value *value,
  * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash*
  * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval*
  * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob*
+ * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct*
  *
  * @note the pointer contents are written using the size defined by
  *       type. It can be larger than void* or uint64_t.
@@ -1520,6 +1554,7 @@ static inline Eina_Bool eina_value_list_remove(Eina_Value *value,
  * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash
  * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval
  * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob
+ * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct
  *
  * @code
  *     Eina_Value *value = eina_value_list_new(EINA_VALUE_TYPE_INT);
@@ -1579,6 +1614,7 @@ static inline Eina_Bool eina_value_list_set(Eina_Value *value,
  * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash*
  * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval*
  * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob*
+ * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct*
  *
  * @code
  *     Eina_Value *value = eina_value_list_new(EINA_VALUE_TYPE_INT);
@@ -1626,6 +1662,7 @@ static inline Eina_Bool eina_value_list_get(const Eina_Value *value,
  * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash
  * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval
  * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob
+ * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct
  *
  * @code
  *     Eina_Value *value = eina_value_list_new(EINA_VALUE_TYPE_INT);
@@ -1679,6 +1716,7 @@ static inline Eina_Bool eina_value_list_insert(Eina_Value *value,
  * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash
  * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval
  * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob
+ * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct
  *
  * @code
  *     Eina_Value *value = eina_value_list_new(EINA_VALUE_TYPE_INT);
@@ -1818,6 +1856,7 @@ static inline Eina_Bool eina_value_list_vappend(Eina_Value *value,
  * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash*
  * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval*
  * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob*
+ * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct*
  *
  * @note the pointer contents are written using the size defined by
  *       type. It can be larger than void* or uint64_t.
@@ -1881,6 +1920,7 @@ static inline Eina_Bool eina_value_list_pset(Eina_Value *value,
  * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash*
  * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval*
  * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob*
+ * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct*
  *
  * @code
  *     Eina_Value *value = eina_value_list_new(EINA_VALUE_TYPE_INT);
@@ -1929,6 +1969,7 @@ static inline Eina_Bool eina_value_list_pget(const Eina_Value *value,
  * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash*
  * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval*
  * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob*
+ * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct*
  *
  * @note the pointer contents are written using the size defined by
  *       type. It can be larger than void* or uint64_t.
@@ -1985,6 +2026,7 @@ static inline Eina_Bool eina_value_list_pinsert(Eina_Value *value,
  * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash*
  * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval*
  * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob*
+ * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct*
  *
  * @note the pointer contents are written using the size defined by
  *       type. It can be larger than void* or uint64_t.
@@ -2118,7 +2160,7 @@ static inline Eina_Bool eina_value_hash_del(Eina_Value *value,
  * @param key key to find the member
  * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
  *
- * The variable argument is dependent on chosen subtype. The hash for
+ * The variable argument is dependent on chosen subtype. The list for
  * basic types:
  *
  * @li EINA_VALUE_TYPE_UCHAR: unsigned char
@@ -2138,6 +2180,7 @@ static inline Eina_Bool eina_value_hash_del(Eina_Value *value,
  * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash
  * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval*
  * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob*
+ * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct*
  *
  * @code
  *     Eina_Value *value = eina_value_hash_new(EINA_VALUE_TYPE_INT, 0);
@@ -2170,7 +2213,7 @@ static inline Eina_Bool eina_value_hash_set(Eina_Value *value,
  * stored inside the object. There shouldn't be any memory allocation,
  * thus the contents should @b not be freed.
  *
- * The variable argument is dependent on chosen subtype. The hash for
+ * The variable argument is dependent on chosen subtype. The list for
  * basic types:
  *
  * @li EINA_VALUE_TYPE_UCHAR: unsigned char*
@@ -2190,6 +2233,7 @@ static inline Eina_Bool eina_value_hash_set(Eina_Value *value,
  * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash*
  * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval*
  * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob*
+ * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct*
  *
  * @code
  *     Eina_Value *value = eina_value_hash_new(EINA_VALUE_TYPE_INT, 0);
@@ -2255,7 +2299,7 @@ static inline Eina_Bool eina_value_hash_vget(const Eina_Value *value,
  * @param ptr pointer to specify the contents.
  * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
  *
- * The pointer type is dependent on chosen value type. The hash for
+ * The pointer type is dependent on chosen value type. The list for
  * basic types:
  *
  * @li EINA_VALUE_TYPE_UCHAR: unsigned char*
@@ -2275,6 +2319,7 @@ static inline Eina_Bool eina_value_hash_vget(const Eina_Value *value,
  * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash*
  * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval*
  * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob*
+ * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct*
  *
  * @note the pointer contents are written using the size defined by
  *       type. It can be larger than void* or uint64_t.
@@ -2310,7 +2355,7 @@ static inline Eina_Bool eina_value_hash_pset(Eina_Value *value,
  * object. There shouldn't be any memory allocation, thus the contents
  * should @b not be freed.
  *
- * The pointer type is dependent on chosen value type. The hash for
+ * The pointer type is dependent on chosen value type. The list for
  * basic types:
  *
  * @li EINA_VALUE_TYPE_UCHAR: unsigned char*
@@ -2330,6 +2375,7 @@ static inline Eina_Bool eina_value_hash_pset(Eina_Value *value,
  * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash*
  * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval*
  * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob*
+ * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct*
  *
  * @code
  *     Eina_Value *value = eina_value_hash_new(EINA_VALUE_TYPE_INT, 0);
@@ -2415,6 +2461,475 @@ struct _Eina_Value_Blob
  */
 
 /**
+ * @defgroup Eina_Value_Struct_Group Generic Value Struct management
+ *
+ * @{
+ */
+
+/**
+ * @typedef Eina_Value_Struct_Operations
+ * How to manage struct. Any @c NULL callback is ignored.
+ * @since 1.2
+ */
+typedef struct _Eina_Value_Struct_Operations Eina_Value_Struct_Operations;
+
+/**
+ * @typedef Eina_Value_Struct_Member
+ * Describes a single member of struct.
+ * @since 1.2
+ */
+typedef struct _Eina_Value_Struct_Member Eina_Value_Struct_Member;
+
+/**
+ * @typedef Eina_Value_Struct_Desc
+ * Describes the struct by listing its size, members and operations.
+ * @since 1.2
+ */
+typedef struct _Eina_Value_Struct_Desc Eina_Value_Struct_Desc;
+
+/**
+ * @typedef Eina_Value_Struct
+ * @since 1.2
+ */
+typedef struct _Eina_Value_Struct Eina_Value_Struct;
+
+/**
+ * @struct _Eina_Value_Struct_Operations
+ * How to manage struct. Any @c NULL callback is ignored.
+ * @since 1.2
+ */
+struct _Eina_Value_Struct_Operations
+{
+#define EINA_VALUE_STRUCT_OPERATIONS_VERSION (1)
+   unsigned int version; /**< must be EINA_VALUE_STRUCT_OPERATIONS_VERSION */
+   void *(*alloc)(const Eina_Value_Struct_Operations *ops, const Eina_Value_Struct_Desc *desc);
+   void (*free)(const Eina_Value_Struct_Operations *ops, const Eina_Value_Struct_Desc *desc, void *memory);
+   void *(*copy)(const Eina_Value_Struct_Operations *ops, const Eina_Value_Struct_Desc *desc, const void *memory);
+   int (*compare)(const Eina_Value_Struct_Operations *ops, const Eina_Value_Struct_Desc *desc, const void *data1, const void *data2);
+   const Eina_Value_Struct_Member *(*find_member)(const Eina_Value_Struct_Operations *ops, const Eina_Value_Struct_Desc *desc, const char *name); /**< replace the function to find description for member. For huge structures consider using binary search, stringshared, hash or gperf. The default function does linear search using strcmp(). */
+};
+
+/**
+ * @var EINA_VALUE_STRUCT_OPERATIONS_BINSEARCH
+ *
+ * Assumes @c members is sorted by name and applies binary search for
+ * names.
+ *
+ * Ideally the @c member_count field is set to speed it up.
+ *
+ * No other methods are set (alloc, free, copy, compare), then it uses
+ * the default operations.
+ */
+EAPI extern const Eina_Value_Struct_Operations *EINA_VALUE_STRUCT_OPERATIONS_BINSEARCH;
+
+/**
+ * @var EINA_VALUE_STRUCT_OPERATIONS_STRINGSHARE
+ *
+ * Assumes @c members name are stringshared and can be compared for
+ * equality without using its contents (simple pointer comparison).
+ *
+ * Ideally the search @c name will be stringshared as well, but it
+ * will do a second loop with a forced stringshare if it did not find
+ * the member.
+ *
+ * No other methods are set (alloc, free, copy, compare), then it uses
+ * the default operations.
+ */
+EAPI extern const Eina_Value_Struct_Operations *EINA_VALUE_STRUCT_OPERATIONS_STRINGSHARE;
+
+/**
+ * @struct _Eina_Value_Struct_Member
+ * @since 1.2
+ */
+struct _Eina_Value_Struct_Member
+{
+   const char *name;
+   const Eina_Value_Type *type;
+   unsigned int offset;
+};
+
+/**
+ * @struct _Eina_Value_Struct_Desc
+ * @since 1.2
+ */
+struct _Eina_Value_Struct_Desc
+{
+#define EINA_VALUE_STRUCT_DESC_VERSION (1)
+   unsigned int version; /**< must be EINA_VALUE_STRUCT_DESC_VERSION */
+   const Eina_Value_Struct_Operations *ops; /**< operations, if @c NULL defaults will be used. You may use operations to optimize member lookup using binary search or gperf hash. */
+   const Eina_Value_Struct_Member *members; /**< array of member descriptions, if @c member_count is zero, then it must be @c NULL terminated. */
+   unsigned int member_count; /**< if > 0, specifies number of members. If zero then @c members must be NULL terminated. */
+   unsigned int size; /**< byte size to allocate, may be bigger than sum of members */
+};
+
+/**
+ * @struct _Eina_Value_Struct
+ * @since 1.2
+ */
+struct _Eina_Value_Struct
+{
+   const Eina_Value_Struct_Desc *desc;
+   void *memory;
+};
+
+/**
+ * @brief Create generic value storage of type struct.
+ * @param desc how to manage this struct members.
+ * @return The new value or @c NULL on failure.
+ *
+ * Create a new generic value storage of type struct. The members are
+ * managed using the description specified by @a desc.
+ *
+ * On failure, @c NULL is returned and #EINA_ERROR_OUT_OF_MEMORY or
+ * #EINA_ERROR_VALUE_FAILED is set.
+ *
+ * @note this creates from mempool and then uses
+ *       eina_value_struct_setup().
+ *
+ * @see eina_value_free()
+ * @see eina_value_struct_setup()
+ *
+ * @since 1.2
+ */
+EAPI Eina_Value *eina_value_struct_new(const Eina_Value_Struct_Desc *desc) EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Initialize generic value storage of type struct.
+ * @param value value object
+ * @param desc how to manage this struct members.
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * Initializes new generic value storage of type struct with the given
+ * @a desc.
+ *
+ * This is the same as calling eina_value_set() with
+ * #EINA_VALUE_TYPE_STRUCT followed by eina_value_pset() with the
+ * #Eina_Value_Struct description configured.
+ *
+ * @note Existing contents are ignored! If the value was previously used, then
+ *       use eina_value_flush() first.
+ *
+ * On failure, #EINA_FALSE is returned and #EINA_ERROR_OUT_OF_MEMORY
+ * or #EINA_ERROR_VALUE_FAILED is set.
+ *
+ * @see eina_value_flush()
+ *
+ * @since 1.2
+ */
+static inline Eina_Bool eina_value_struct_setup(Eina_Value *value,
+                                                const Eina_Value_Struct_Desc *desc) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @brief Set the generic value in an struct member.
+ * @param value source value object
+ * @param name name to find the member
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * The variable argument is dependent on chosen member type. The list
+ * for basic types:
+ *
+ * @li EINA_VALUE_TYPE_UCHAR: unsigned char
+ * @li EINA_VALUE_TYPE_USHORT: unsigned short
+ * @li EINA_VALUE_TYPE_UINT: unsigned int
+ * @li EINA_VALUE_TYPE_ULONG: unsigned long
+ * @li EINA_VALUE_TYPE_UINT64: uint64_t
+ * @li EINA_VALUE_TYPE_CHAR: char
+ * @li EINA_VALUE_TYPE_SHORT: short
+ * @li EINA_VALUE_TYPE_INT: int
+ * @li EINA_VALUE_TYPE_LONG: long
+ * @li EINA_VALUE_TYPE_INT64: int64_t
+ * @li EINA_VALUE_TYPE_FLOAT: float
+ * @li EINA_VALUE_TYPE_DOUBLE: double
+ * @li EINA_VALUE_TYPE_STRINGSHARE: const char *
+ * @li EINA_VALUE_TYPE_STRING: const char *
+ * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash
+ * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval*
+ * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob*
+ * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct*
+ *
+ * @code
+ *     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 *value = eina_value_struct_new(&my_desc);
+ *     int x;
+ *     char y;
+ *
+ *     eina_value_struct_set(value, "i", 5678);
+ *     eina_value_struct_get(value, "i", &x);
+ *     eina_value_struct_set(value, "c", 0xf);
+ *     eina_value_struct_get(value, "c", &y);
+ *     eina_value_free(value);
+ * @endcode
+ *
+ * @see eina_value_struct_get()
+ * @see eina_value_struct_vset()
+ * @see eina_value_struct_pset()
+ *
+ * @since 1.2
+ */
+static inline Eina_Bool eina_value_struct_set(Eina_Value *value,
+                                              const char *name,
+                                              ...) EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Get the generic value from an struct member.
+ * @param value source value object
+ * @param name name to find the member
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * The value is returned in the variable argument parameter, the
+ * actual value is type-dependent, but usually it will be what is
+ * stored inside the object. There shouldn't be any memory allocation,
+ * thus the contents should @b not be freed.
+ *
+ * The variable argument is dependent on chosen member type. The list
+ * for basic types:
+ *
+ * @li EINA_VALUE_TYPE_UCHAR: unsigned char*
+ * @li EINA_VALUE_TYPE_USHORT: unsigned short*
+ * @li EINA_VALUE_TYPE_UINT: unsigned int*
+ * @li EINA_VALUE_TYPE_ULONG: unsigned long*
+ * @li EINA_VALUE_TYPE_UINT64: uint64_t*
+ * @li EINA_VALUE_TYPE_CHAR: char*
+ * @li EINA_VALUE_TYPE_SHORT: short*
+ * @li EINA_VALUE_TYPE_INT: int*
+ * @li EINA_VALUE_TYPE_LONG: long*
+ * @li EINA_VALUE_TYPE_INT64: int64_t*
+ * @li EINA_VALUE_TYPE_FLOAT: float*
+ * @li EINA_VALUE_TYPE_DOUBLE: double*
+ * @li EINA_VALUE_TYPE_STRINGSHARE: const char **
+ * @li EINA_VALUE_TYPE_STRING: const char **
+ * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash*
+ * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval*
+ * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob*
+ * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct*
+ *
+ * @code
+ *     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 *value = eina_value_struct_new(&my_desc);
+ *     int x;
+ *     char y;
+ *
+ *     eina_value_struct_set(value, "i", 5678);
+ *     eina_value_struct_get(value, "i", &x);
+ *     eina_value_struct_set(value, "c", 0xf);
+ *     eina_value_struct_get(value, "c", &y);
+ *     eina_value_free(value);
+ * @endcode
+ *
+ * @see eina_value_struct_set()
+ * @see eina_value_struct_vset()
+ * @see eina_value_struct_pset()
+ *
+ * @since 1.2
+ */
+static inline Eina_Bool eina_value_struct_get(const Eina_Value *value,
+                                              const char *name,
+                                              ...) EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Set the generic value in an struct member.
+ * @param value source value object
+ * @param name name to find the member
+ * @param args variable argument
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ * @see eina_value_struct_set()
+ * @see eina_value_struct_get()
+ * @see eina_value_struct_pset()
+ *
+ * @since 1.2
+ */
+static inline Eina_Bool eina_value_struct_vset(Eina_Value *value,
+                                               const char *name,
+                                               va_list args) EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Get the generic value from an struct member.
+ * @param value source value object
+ * @param name name to find the member
+ * @param args variable argument
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * The value is returned in the variable argument parameter, the
+ * actual value is type-dependent, but usually it will be what is
+ * stored inside the object. There shouldn't be any memory allocation,
+ * thus the contents should @b not be freed.
+ *
+ * @see eina_value_struct_vset()
+ * @see eina_value_struct_get()
+ * @see eina_value_struct_pget()
+ *
+ * @since 1.2
+ */
+static inline Eina_Bool eina_value_struct_vget(const Eina_Value *value,
+                                               const char *name,
+                                               va_list args) EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Set the generic value in an struct member from pointer.
+ * @param value source value object
+ * @param name name to find the member
+ * @param ptr pointer to specify the contents.
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * The pointer type is dependent on chosen value type. The list for
+ * basic types:
+ *
+ * @li EINA_VALUE_TYPE_UCHAR: unsigned char*
+ * @li EINA_VALUE_TYPE_USHORT: unsigned short*
+ * @li EINA_VALUE_TYPE_UINT: unsigned int*
+ * @li EINA_VALUE_TYPE_ULONG: unsigned long*
+ * @li EINA_VALUE_TYPE_UINT64: uint64_t*
+ * @li EINA_VALUE_TYPE_CHAR: char*
+ * @li EINA_VALUE_TYPE_SHORT: short*
+ * @li EINA_VALUE_TYPE_INT: int*
+ * @li EINA_VALUE_TYPE_LONG: long*
+ * @li EINA_VALUE_TYPE_INT64: int64_t*
+ * @li EINA_VALUE_TYPE_FLOAT: float*
+ * @li EINA_VALUE_TYPE_DOUBLE: double*
+ * @li EINA_VALUE_TYPE_STRINGSHARE: const char **
+ * @li EINA_VALUE_TYPE_STRING: const char **
+ * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash*
+ * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval*
+ * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob*
+ * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct*
+ *
+ * @note the pointer contents are written using the size defined by
+ *       type. It can be larger than void* or uint64_t.
+ *
+ * @code
+ *     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 *value = eina_value_struct_new(&my_desc);
+ *     int x = 5678;
+ *     char y = 0xf;
+ *
+ *     eina_value_struct_pset(value, "i", &);
+ *     eina_value_struct_pget(value, "i", &x);
+ *     eina_value_struct_pset(value, "c", &y);
+ *     eina_value_struct_pget(value, "c", &y);
+ *     eina_value_free(value);
+ * @endcode
+ *
+ * @see eina_value_struct_set()
+ * @see eina_value_struct_get()
+ * @see eina_value_struct_vset()
+ *
+ * @since 1.2
+ */
+static inline Eina_Bool eina_value_struct_pset(Eina_Value *value,
+                                               const char *name,
+                                               const void *ptr) EINA_ARG_NONNULL(1, 3);
+
+/**
+ * @brief Get the generic value to pointer from an struct member.
+ * @param value source value object
+ * @param name name to find the member
+ * @param ptr pointer to receive the contents.
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * The value is returned in pointer contents, the actual value is
+ * type-dependent, but usually it will be what is stored inside the
+ * object. There shouldn't be any memory allocation, thus the contents
+ * should @b not be freed.
+ *
+ * The pointer type is dependent on chosen value type. The list for
+ * basic types:
+ *
+ * @li EINA_VALUE_TYPE_UCHAR: unsigned char*
+ * @li EINA_VALUE_TYPE_USHORT: unsigned short*
+ * @li EINA_VALUE_TYPE_UINT: unsigned int*
+ * @li EINA_VALUE_TYPE_ULONG: unsigned long*
+ * @li EINA_VALUE_TYPE_UINT64: uint64_t*
+ * @li EINA_VALUE_TYPE_CHAR: char*
+ * @li EINA_VALUE_TYPE_SHORT: short*
+ * @li EINA_VALUE_TYPE_INT: int*
+ * @li EINA_VALUE_TYPE_LONG: long*
+ * @li EINA_VALUE_TYPE_INT64: int64_t*
+ * @li EINA_VALUE_TYPE_FLOAT: float*
+ * @li EINA_VALUE_TYPE_DOUBLE: double*
+ * @li EINA_VALUE_TYPE_STRINGSHARE: const char **
+ * @li EINA_VALUE_TYPE_STRING: const char **
+ * @li EINA_VALUE_TYPE_HASH: Eina_Value_Hash*
+ * @li EINA_VALUE_TYPE_TIMEVAL: struct timeval*
+ * @li EINA_VALUE_TYPE_BLOB: Eina_Value_Blob*
+ * @li EINA_VALUE_TYPE_STRUCT: Eina_Value_Struct*
+ *
+ * @code
+ *     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 *value = eina_value_struct_new(&my_desc);
+ *     int x = 5678;
+ *     char y = 0xf;
+ *
+ *     eina_value_struct_pset(value, "i", &);
+ *     eina_value_struct_pget(value, "i", &x);
+ *     eina_value_struct_pset(value, "c", &y);
+ *     eina_value_struct_pget(value, "c", &y);
+ *     eina_value_free(value);
+ * @endcode
+ *
+ * @see eina_value_struct_set()
+ * @see eina_value_struct_vset()
+ * @see eina_value_struct_pset()
+ *
+ * @since 1.2
+ */
+static inline Eina_Bool eina_value_struct_pget(const Eina_Value *value,
+                                               const char *name,
+                                               void *ptr) EINA_ARG_NONNULL(1, 3);
+
+/**
+ * @}
+ */
+
+
+/**
  * @defgroup Eina_Value_Type_Group Generic Value Type management
  *
  * @{
@@ -2503,7 +3018,7 @@ static inline Eina_Bool eina_value_type_copy(const Eina_Value_Type *type, const
  * @return less than zero if a < b, greater than zero if a > b, zero if equal.
  * @since 1.2
  */
-static inline int eina_value_type_compare(const Eina_Value_Type *type, const void *a, void *b);
+static inline int eina_value_type_compare(const Eina_Value_Type *type, const void *a, const void *b);
 
 /**
  * @brief Convert memory using type descriptor.
index 620098a..0796462 100644 (file)
@@ -3819,6 +3819,497 @@ static const Eina_Value_Type _EINA_VALUE_TYPE_BLOB = {
   _eina_value_type_blob_pget
 };
 
+static int
+_eina_value_struct_operations_binsearch_cmp(const void *pa, const void *pb)
+{
+   const Eina_Value_Struct_Member *a = pa, *b = pb;
+   return strcmp(a->name, b->name);
+}
+
+static const Eina_Value_Struct_Member *
+_eina_value_struct_operations_binsearch_find_member(const Eina_Value_Struct_Operations *ops __UNUSED__, const Eina_Value_Struct_Desc *desc, const char *name)
+{
+   unsigned int count = desc->member_count;
+   Eina_Value_Struct_Member search;
+   if (count == 0)
+     {
+        const Eina_Value_Struct_Member *itr = desc->members;
+        for (; itr->name != NULL; itr++)
+          count++;
+     }
+
+   search.name = name;
+   return bsearch(&search, desc->members, count,
+                  sizeof(Eina_Value_Struct_Member),
+                  _eina_value_struct_operations_binsearch_cmp);
+}
+
+static Eina_Value_Struct_Operations _EINA_VALUE_STRUCT_OPERATIONS_BINSEARCH = {
+  EINA_VALUE_STRUCT_OPERATIONS_VERSION,
+  NULL, /* default alloc */
+  NULL, /* default free */
+  NULL, /* default copy */
+  NULL, /* default compare */
+  _eina_value_struct_operations_binsearch_find_member
+};
+
+static const Eina_Value_Struct_Member *
+_eina_value_struct_operations_stringshare_find_member(const Eina_Value_Struct_Operations *ops __UNUSED__, const Eina_Value_Struct_Desc *desc, const char *name)
+{
+   const Eina_Value_Struct_Member *itr = desc->members;
+
+   /* assumes name is stringshared.
+    *
+    * we do this because it's the recommended usage pattern, moreover
+    * we expect to find the member, as users shouldn't look for
+    * non-existent members!
+    */
+   if (desc->member_count > 0)
+     {
+        const Eina_Value_Struct_Member *itr_end = itr + desc->member_count;
+        for (; itr < itr_end; itr++)
+          if (itr->name == name)
+            return itr;
+     }
+   else
+     {
+        for (; itr->name != NULL; itr++)
+          if (itr->name == name)
+            return itr;
+     }
+
+   name = eina_stringshare_add(name);
+   eina_stringshare_del(name); /* we'll not use the contents, this is fine */
+   /* stringshare and look again */
+   if (desc->member_count > 0)
+     {
+        const Eina_Value_Struct_Member *itr_end = itr + desc->member_count;
+        for (; itr < itr_end; itr++)
+          if (itr->name == name)
+            return itr;
+     }
+   else
+     {
+        for (; itr->name != NULL; itr++)
+          if (itr->name == name)
+            return itr;
+     }
+
+   return NULL;
+}
+
+static Eina_Value_Struct_Operations _EINA_VALUE_STRUCT_OPERATIONS_STRINGSHARE = {
+  EINA_VALUE_STRUCT_OPERATIONS_VERSION,
+  NULL, /* default alloc */
+  NULL, /* default free */
+  NULL, /* default copy */
+  NULL, /* default compare */
+  _eina_value_struct_operations_stringshare_find_member
+};
+
+static inline const Eina_Value_Struct_Operations *
+_eina_value_type_struct_ops_get(const Eina_Value_Struct *st)
+{
+   if (!st) return NULL;
+   if (!st->desc) return NULL;
+   if (!st->desc->ops) return NULL;
+   EINA_SAFETY_ON_FALSE_RETURN_VAL
+     (st->desc->ops->version == EINA_VALUE_STRUCT_OPERATIONS_VERSION, NULL);
+   return st->desc->ops;
+}
+
+EAPI const Eina_Value_Struct_Member *
+eina_value_struct_member_find(const Eina_Value_Struct *st, const char *name)
+{
+   const Eina_Value_Struct_Operations *ops;
+   const Eina_Value_Struct_Member *itr;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(st, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(st->desc, NULL);
+
+   ops = _eina_value_type_struct_ops_get(st);
+   if ((ops) && (ops->find_member))
+     return ops->find_member(ops, st->desc, name);
+
+   itr = st->desc->members;
+   if (st->desc->member_count)
+     {
+        const Eina_Value_Struct_Member *itr_end = itr + st->desc->member_count;
+        for (; itr < itr_end; itr++)
+          {
+             if (strcmp(name, itr->name) == 0)
+               return itr;
+          }
+        return NULL;
+     }
+   else
+     {
+        for (; itr->name != NULL; itr++)
+          {
+             if (strcmp(name, itr->name) == 0)
+               return itr;
+          }
+        return NULL;
+     }
+}
+
+static Eina_Bool
+_eina_value_type_struct_setup(const Eina_Value_Type *type __UNUSED__, void *mem)
+{
+   memset(mem, 0, sizeof(Eina_Value_Struct));
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_eina_value_type_struct_flush_member(const Eina_Value_Struct_Member *member, Eina_Value_Struct *st)
+{
+   unsigned char *base = st->memory;
+   return eina_value_type_flush(member->type, base + member->offset);
+}
+
+static Eina_Bool
+_eina_value_type_struct_flush(const Eina_Value_Type *type __UNUSED__, void *mem)
+{
+   const Eina_Value_Struct_Operations *ops;
+   const Eina_Value_Struct_Member *itr;
+   Eina_Value_Struct *tmem = mem;
+   Eina_Bool ret = EINA_TRUE;
+
+   itr = tmem->desc->members;
+   if (tmem->desc->member_count > 0)
+     {
+        const Eina_Value_Struct_Member *itr_end;
+        itr_end = itr + tmem->desc->member_count;
+        for (; itr < itr_end; itr++)
+          ret &= _eina_value_type_struct_flush_member(itr, tmem);
+     }
+   else
+     {
+        for (; itr->name != NULL; itr++)
+          ret &= _eina_value_type_struct_flush_member(itr, tmem);
+     }
+
+   ops = _eina_value_type_struct_ops_get(mem);
+   if ((ops) && (ops->free))
+     ops->free(ops, tmem->desc, tmem->memory);
+   else
+     free(tmem->memory);
+
+   return ret;
+}
+
+static Eina_Bool
+_eina_value_type_struct_copy_member(const Eina_Value_Struct_Member *member, const Eina_Value_Struct *s, Eina_Value_Struct *d)
+{
+   const unsigned char *base_s = s->memory;
+   unsigned char *base_d = d->memory;
+   return eina_value_type_copy(member->type,
+                               base_s + member->offset,
+                               base_d + member->offset);
+}
+
+static Eina_Bool
+_eina_value_type_struct_copy(const Eina_Value_Type *type __UNUSED__, const void *src, void *dst)
+{
+   const Eina_Value_Struct_Operations *ops;
+   const Eina_Value_Struct_Member *itr;
+   const Eina_Value_Struct *s = src;
+   Eina_Value_Struct *d = dst;
+
+   *d = *s;
+
+   ops = _eina_value_type_struct_ops_get(src);
+   if ((ops) && (ops->copy))
+     {
+        d->memory = ops->copy(ops, s->desc, s->memory);
+        if (d->memory == NULL)
+          return EINA_FALSE;
+        return EINA_TRUE;
+     }
+
+   d->memory = malloc(s->desc->size);
+   if (!d->memory)
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return EINA_FALSE;
+     }
+
+   itr = s->desc->members;
+   if (s->desc->member_count > 0)
+     {
+        const Eina_Value_Struct_Member *itr_end = itr + s->desc->member_count;
+        for (; itr < itr_end; itr++)
+          if (!_eina_value_type_struct_copy_member(itr, s, d))
+            goto error;
+     }
+   else
+     {
+        for (; itr->name != NULL; itr++)
+          if (!_eina_value_type_struct_copy_member(itr, s, d))
+            goto error;
+     }
+
+
+   return EINA_TRUE;
+
+ error:
+   itr--;
+   for (; itr >= s->desc->members; itr--)
+     _eina_value_type_struct_flush_member(itr, d);
+   free(d->memory);
+   return EINA_FALSE;
+}
+
+static inline int
+_eina_value_type_struct_compare_member(const Eina_Value_Struct_Member *member, const Eina_Value_Struct *ta, const Eina_Value_Struct *tb)
+{
+   const unsigned char *base_a = ta->memory;
+   const unsigned char *base_b = tb->memory;
+   return eina_value_type_compare(member->type,
+                                  base_a + member->offset,
+                                  base_b + member->offset);
+}
+
+static int
+_eina_value_type_struct_compare(const Eina_Value_Type *type __UNUSED__, const void *a, const void *b)
+{
+   const Eina_Value_Struct_Operations *ops = _eina_value_type_struct_ops_get(a);
+   const Eina_Value_Struct *ta = a, *tb = b;
+   const Eina_Value_Struct_Member *itr;
+   int cmp = 0;
+
+   if (ta->desc != tb->desc)
+     {
+        eina_error_set(EINA_ERROR_VALUE_FAILED);
+        return -1;
+     }
+   if (ta->desc->ops != tb->desc->ops)
+     {
+        eina_error_set(EINA_ERROR_VALUE_FAILED);
+        return -1;
+     }
+   if ((!ta->memory) && (!tb->memory))
+     return 0;
+   else if (!ta->memory)
+     return -1;
+   else if (!tb->memory)
+     return 1;
+
+   if ((ops) && (ops->compare))
+     return ops->compare(ops, ta->desc, ta->memory, tb->memory);
+
+   itr = ta->desc->members;
+   if (ta->desc->member_count > 0)
+     {
+        const Eina_Value_Struct_Member *itr_end = itr + ta->desc->member_count;
+        for (; (cmp == 0) && (itr < itr_end); itr++)
+          cmp = _eina_value_type_struct_compare_member(itr, ta, tb);
+     }
+   else
+     {
+        for (; (cmp == 0) && (itr->name != NULL); itr++)
+          cmp = _eina_value_type_struct_compare_member(itr, ta, tb);
+     }
+   return cmp;
+}
+
+static void
+_eina_value_type_struct_convert_to_string_member(const Eina_Value_Struct *st, const Eina_Value_Struct_Member *member, Eina_Strbuf *str)
+{
+   const unsigned char *p = st->memory;
+   Eina_Bool first = st->desc->members == member;
+   Eina_Bool r = EINA_FALSE;
+
+   if (first) eina_strbuf_append_printf(str, "%s: ", member->name);
+   else eina_strbuf_append_printf(str, ", %s: ", member->name);
+
+   if ((member->type) && (member->type->convert_to))
+     {
+        const Eina_Value_Type *type = member->type;
+        char *conv = NULL;
+
+        r = eina_value_type_convert_to(type, EINA_VALUE_TYPE_STRING,
+                                       p + member->offset, &conv);
+        if (r)
+          {
+             eina_strbuf_append(str, conv);
+             free(conv);
+          }
+     }
+
+   if (!r)
+     eina_strbuf_append_char(str, '?');
+}
+
+static Eina_Bool
+_eina_value_type_struct_convert_to(const Eina_Value_Type *type __UNUSED__, const Eina_Value_Type *convert, const void *type_mem, void *convert_mem)
+{
+   const Eina_Value_Struct *tmem = type_mem;
+
+   eina_error_set(0);
+   if (convert == EINA_VALUE_TYPE_STRINGSHARE ||
+       convert == EINA_VALUE_TYPE_STRING)
+     {
+        Eina_Strbuf *str = eina_strbuf_new();
+        const char *s;
+        Eina_Bool ret;
+
+        if (!tmem->memory) eina_strbuf_append(str, "{}");
+        else
+          {
+             const Eina_Value_Struct_Member *itr = tmem->desc->members;
+
+             eina_strbuf_append_char(str, '{');
+
+             if (tmem->desc->member_count > 0)
+               {
+                  const Eina_Value_Struct_Member *itr_end;
+
+                  itr_end = itr + tmem->desc->member_count;
+                  for (; itr < itr_end; itr++)
+                    _eina_value_type_struct_convert_to_string_member
+                      (tmem, itr, str);
+               }
+             else
+               {
+                  for (; itr->name != NULL; itr++)
+                    _eina_value_type_struct_convert_to_string_member
+                      (tmem, itr, str);
+               }
+
+             eina_strbuf_append_char(str, '}');
+          }
+        s = eina_strbuf_string_get(str);
+        ret = eina_value_type_pset(convert, convert_mem, &s);
+        eina_strbuf_free(str);
+        return ret;
+     }
+   else
+     {
+        eina_error_set(EINA_ERROR_VALUE_FAILED);
+        return EINA_FALSE;
+     }
+}
+
+static Eina_Bool
+_eina_value_type_struct_desc_check(const Eina_Value_Struct_Desc *desc)
+{
+   unsigned int minsize = 0;
+   const Eina_Value_Struct_Member *itr;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(desc, EINA_FALSE);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL
+     (desc->version == EINA_VALUE_STRUCT_DESC_VERSION, EINA_FALSE);
+
+   itr = desc->members;
+   if (desc->member_count > 0)
+     {
+        const Eina_Value_Struct_Member *itr_end = itr + desc->member_count;
+        for (; itr < itr_end; itr++)
+          {
+             unsigned int member_end;
+
+             EINA_SAFETY_ON_FALSE_RETURN_VAL
+               (eina_value_type_check(itr->type), EINA_FALSE);
+             EINA_SAFETY_ON_FALSE_RETURN_VAL
+               (itr->type->value_size > 0, EINA_FALSE);
+
+             member_end = itr->offset + itr->type->value_size;
+             if (minsize < member_end)
+               minsize = member_end;
+          }
+     }
+   else
+     {
+        for (; itr->name != NULL; itr++)
+          {
+             unsigned int member_end;
+
+             EINA_SAFETY_ON_FALSE_RETURN_VAL
+               (eina_value_type_check(itr->type), EINA_FALSE);
+             EINA_SAFETY_ON_FALSE_RETURN_VAL
+               (itr->type->value_size > 0, EINA_FALSE);
+
+             member_end = itr->offset + itr->type->value_size;
+             if (minsize < member_end)
+               minsize = member_end;
+          }
+     }
+
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(minsize > 0, EINA_FALSE);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(desc->size >= minsize, EINA_FALSE);
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_eina_value_type_struct_pset(const Eina_Value_Type *type __UNUSED__, void *mem, const void *ptr)
+{
+   const Eina_Value_Struct_Operations *ops = _eina_value_type_struct_ops_get(mem);
+   Eina_Value_Struct *tmem = mem;
+   const Eina_Value_Struct *desc = ptr;
+
+   if (!_eina_value_type_struct_desc_check(desc->desc))
+     {
+        eina_error_set(EINA_ERROR_VALUE_FAILED);
+        return EINA_FALSE;
+     }
+
+   if ((ops) && (ops->free))
+     ops->free(ops, tmem->desc, tmem->memory);
+   else
+     free(tmem->memory);
+
+   *tmem = *desc;
+
+   ops = _eina_value_type_struct_ops_get(desc);
+   if (!tmem->memory)
+     {
+        if ((ops) && (ops->alloc))
+          tmem->memory = ops->alloc(ops, tmem->desc);
+        else
+          tmem->memory = malloc(tmem->desc->size);
+
+        if (!tmem->memory)
+          {
+             eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+             return EINA_FALSE;
+          }
+     }
+
+   eina_error_set(0);
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_eina_value_type_struct_vset(const Eina_Value_Type *type, void *mem, va_list args)
+{
+   const Eina_Value_Struct desc = va_arg(args, Eina_Value_Struct);
+   _eina_value_type_struct_pset(type, mem, &desc);
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_eina_value_type_struct_pget(const Eina_Value_Type *type __UNUSED__, const void *mem, void *ptr)
+{
+   memcpy(ptr, mem, sizeof(Eina_Value_Struct));
+   return EINA_TRUE;
+}
+
+static const Eina_Value_Type _EINA_VALUE_TYPE_STRUCT = {
+  EINA_VALUE_TYPE_VERSION,
+  sizeof(Eina_Value_Struct),
+  "Eina_Value_Struct",
+  _eina_value_type_struct_setup,
+  _eina_value_type_struct_flush,
+  _eina_value_type_struct_copy,
+  _eina_value_type_struct_compare,
+  _eina_value_type_struct_convert_to,
+  NULL, /* no convert from */
+  _eina_value_type_struct_vset,
+  _eina_value_type_struct_pset,
+  _eina_value_type_struct_pget
+};
+
 /* keep all basic types inlined in an array so we can compare if it's
  * a basic type using pointer arithmetic.
  *
@@ -4249,9 +4740,13 @@ eina_value_init(void)
    EINA_VALUE_TYPE_HASH = &_EINA_VALUE_TYPE_HASH;
    EINA_VALUE_TYPE_TIMEVAL = &_EINA_VALUE_TYPE_TIMEVAL;
    EINA_VALUE_TYPE_BLOB = &_EINA_VALUE_TYPE_BLOB;
+   EINA_VALUE_TYPE_STRUCT = &_EINA_VALUE_TYPE_STRUCT;
 
    EINA_VALUE_BLOB_OPERATIONS_MALLOC = &_EINA_VALUE_BLOB_OPERATIONS_MALLOC;
 
+   EINA_VALUE_STRUCT_OPERATIONS_BINSEARCH = &_EINA_VALUE_STRUCT_OPERATIONS_BINSEARCH;
+   EINA_VALUE_STRUCT_OPERATIONS_STRINGSHARE = &_EINA_VALUE_STRUCT_OPERATIONS_STRINGSHARE;
+
    return EINA_TRUE;
 
  on_init_fail_hash:
@@ -4326,9 +4821,13 @@ EAPI const Eina_Value_Type *EINA_VALUE_TYPE_LIST = NULL;
 EAPI const Eina_Value_Type *EINA_VALUE_TYPE_HASH = NULL;
 EAPI const Eina_Value_Type *EINA_VALUE_TYPE_TIMEVAL = NULL;
 EAPI const Eina_Value_Type *EINA_VALUE_TYPE_BLOB = NULL;
+EAPI const Eina_Value_Type *EINA_VALUE_TYPE_STRUCT = NULL;
 
 EAPI const Eina_Value_Blob_Operations *EINA_VALUE_BLOB_OPERATIONS_MALLOC = NULL;
 
+EAPI const Eina_Value_Struct_Operations *EINA_VALUE_STRUCT_OPERATIONS_BINSEARCH = NULL;
+EAPI const Eina_Value_Struct_Operations *EINA_VALUE_STRUCT_OPERATIONS_STRINGSHARE = NULL;
+
 EAPI Eina_Error EINA_ERROR_VALUE_FAILED = 0;
 
 EAPI const unsigned int eina_prime_table[] =
@@ -4445,13 +4944,13 @@ eina_value_array_new(const Eina_Value_Type *subtype, unsigned int step)
 
    EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_type_check(subtype), EINA_FALSE);
 
-   value = calloc(1, sizeof(Eina_Value));
+   value = eina_mempool_malloc(_eina_value_mp, sizeof(Eina_Value));;
    if (!value)
      return NULL;
 
    if (!eina_value_array_setup(value, subtype, step))
      {
-        free(value);
+        eina_mempool_free(_eina_value_mp, value);
         return NULL;
      }
 
@@ -4465,13 +4964,13 @@ eina_value_list_new(const Eina_Value_Type *subtype)
 
    EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_type_check(subtype), EINA_FALSE);
 
-   value = calloc(1, sizeof(Eina_Value));
+   value = eina_mempool_malloc(_eina_value_mp, sizeof(Eina_Value));;
    if (!value)
      return NULL;
 
    if (!eina_value_list_setup(value, subtype))
      {
-        free(value);
+        eina_mempool_free(_eina_value_mp, value);
         return NULL;
      }
 
@@ -4485,13 +4984,31 @@ eina_value_hash_new(const Eina_Value_Type *subtype, unsigned int buckets_power_s
 
    EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_type_check(subtype), EINA_FALSE);
 
-   value = calloc(1, sizeof(Eina_Value));
+   value = eina_mempool_malloc(_eina_value_mp, sizeof(Eina_Value));;
    if (!value)
      return NULL;
 
    if (!eina_value_hash_setup(value, subtype, buckets_power_size))
      {
-        free(value);
+        eina_mempool_free(_eina_value_mp, value);
+        return NULL;
+     }
+
+   return value;
+}
+
+EAPI Eina_Value *
+eina_value_struct_new(const Eina_Value_Struct_Desc *desc)
+{
+   Eina_Value *value;
+
+   value = eina_mempool_malloc(_eina_value_mp, sizeof(Eina_Value));;
+   if (!value)
+     return NULL;
+
+   if (!eina_value_struct_setup(value, desc))
+     {
+        eina_mempool_free(_eina_value_mp, value);
         return NULL;
      }
 
index 2a81994..bdf279f 100644 (file)
@@ -1538,6 +1538,180 @@ START_TEST(eina_value_test_blob)
 }
 END_TEST
 
+
+START_TEST(eina_value_test_struct)
+{
+   struct mybigst {
+      int a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, x;
+   };
+#define EINA_VALUE_STRUCT_MEMBER(eina_value_type, type, member) \
+   {#member, eina_value_type, offsetof(type, member)}
+#define EINA_VALUE_STRUCT_MEMBER_SENTINEL {NULL, NULL, 0}
+   const Eina_Value_Struct_Member mybigst_members[] = {
+     EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, a),
+     EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, b),
+     EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, c),
+     EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, d),
+     EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, e),
+     EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, f),
+     EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, g),
+     EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, h),
+     EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, i),
+     EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, j),
+     EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, k),
+     EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, l),
+     EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, m),
+     EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, n),
+     EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, o),
+     EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, p),
+     EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, q),
+     EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, r),
+     EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, s),
+     EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, t),
+     EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, u),
+     EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, v),
+     EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct mybigst, x),
+     EINA_VALUE_STRUCT_MEMBER_SENTINEL
+   };
+   const Eina_Value_Struct_Desc mybigst_desc = {
+     EINA_VALUE_STRUCT_DESC_VERSION,
+     EINA_VALUE_STRUCT_OPERATIONS_BINSEARCH,
+     mybigst_members, 23, sizeof(struct mybigst)
+   };
+   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 *value, other;
+   int i;
+   char c;
+   char *str;
+
+   eina_init();
+
+   value = eina_value_struct_new(&myst_desc);
+   fail_unless(value != NULL);
+
+   fail_unless(eina_value_struct_set(value, "i", 5678));
+   fail_unless(eina_value_struct_set(value, "c", 0xf));
+
+   fail_unless(eina_value_struct_get(value, "i", &i));
+   fail_unless(i == 5678);
+   fail_unless(eina_value_struct_get(value, "c", &c));
+   fail_unless(c == 0xf);
+
+   str = eina_value_to_string(value);
+   fail_unless(str != NULL);
+   fail_unless(strcmp(str, "{i: 5678, c: 15}") == 0);
+   free(str);
+
+   fail_if(eina_value_struct_get(value, "x", 1234));
+
+   i = 0x11223344;
+   fail_unless(eina_value_struct_pset(value, "i", &i));
+   i = -1;
+   fail_unless(eina_value_struct_pget(value, "i", &i));
+   fail_unless(i == 0x11223344);
+
+   fail_unless(eina_value_copy(value, &other));
+   str = eina_value_to_string(&other);
+   fail_unless(str != NULL);
+   fail_unless(strcmp(str, "{i: 287454020, c: 15}") == 0);
+   free(str);
+
+   eina_value_flush(&other);
+
+   fail_unless(eina_value_struct_setup(&other, &mybigst_desc));
+   fail_unless(eina_value_struct_set(&other, "a",  1) );
+   fail_unless(eina_value_struct_set(&other, "b",  2));
+   fail_unless(eina_value_struct_set(&other, "c",  3));
+   fail_unless(eina_value_struct_set(&other, "d",  4));
+   fail_unless(eina_value_struct_set(&other, "e",  5));
+   fail_unless(eina_value_struct_set(&other, "f",  6));
+   fail_unless(eina_value_struct_set(&other, "g",  7));
+   fail_unless(eina_value_struct_set(&other, "h",  8));
+   fail_unless(eina_value_struct_set(&other, "i",  9));
+   fail_unless(eina_value_struct_set(&other, "j", 10));
+   fail_unless(eina_value_struct_set(&other, "k", 12));
+   fail_unless(eina_value_struct_set(&other, "l", 13));
+   fail_unless(eina_value_struct_set(&other, "m", 14));
+   fail_unless(eina_value_struct_set(&other, "n", 15));
+   fail_unless(eina_value_struct_set(&other, "o", 16));
+   fail_unless(eina_value_struct_set(&other, "p", 17));
+   fail_unless(eina_value_struct_set(&other, "q", 18));
+   fail_unless(eina_value_struct_set(&other, "r", 19));
+   fail_unless(eina_value_struct_set(&other, "s", 20));
+   fail_unless(eina_value_struct_set(&other, "t", 21));
+   fail_unless(eina_value_struct_set(&other, "u", 22));
+   fail_unless(eina_value_struct_set(&other, "v", 23));
+   fail_unless(eina_value_struct_set(&other, "x", 24));
+
+   fail_unless(eina_value_struct_get(&other, "a", &i));
+   fail_unless(i ==  1);
+   fail_unless(eina_value_struct_get(&other, "b", &i));
+   fail_unless(i ==  2);
+   fail_unless(eina_value_struct_get(&other, "c", &i));
+   fail_unless(i ==  3);
+   fail_unless(eina_value_struct_get(&other, "d", &i));
+   fail_unless(i ==  4);
+   fail_unless(eina_value_struct_get(&other, "e", &i));
+   fail_unless(i ==  5);
+   fail_unless(eina_value_struct_get(&other, "f", &i));
+   fail_unless(i ==  6);
+   fail_unless(eina_value_struct_get(&other, "g", &i));
+   fail_unless(i ==  7);
+   fail_unless(eina_value_struct_get(&other, "h", &i));
+   fail_unless(i ==  8);
+   fail_unless(eina_value_struct_get(&other, "i", &i));
+   fail_unless(i ==  9);
+   fail_unless(eina_value_struct_get(&other, "j", &i));
+   fail_unless(i == 10);
+   fail_unless(eina_value_struct_get(&other, "k", &i));
+   fail_unless(i == 12);
+   fail_unless(eina_value_struct_get(&other, "l", &i));
+   fail_unless(i == 13);
+   fail_unless(eina_value_struct_get(&other, "m", &i));
+   fail_unless(i == 14);
+   fail_unless(eina_value_struct_get(&other, "n", &i));
+   fail_unless(i == 15);
+   fail_unless(eina_value_struct_get(&other, "o", &i));
+   fail_unless(i == 16);
+   fail_unless(eina_value_struct_get(&other, "p", &i));
+   fail_unless(i == 17);
+   fail_unless(eina_value_struct_get(&other, "q", &i));
+   fail_unless(i == 18);
+   fail_unless(eina_value_struct_get(&other, "r", &i));
+   fail_unless(i == 19);
+   fail_unless(eina_value_struct_get(&other, "s", &i));
+   fail_unless(i == 20);
+   fail_unless(eina_value_struct_get(&other, "t", &i));
+   fail_unless(i == 21);
+   fail_unless(eina_value_struct_get(&other, "u", &i));
+   fail_unless(i == 22);
+   fail_unless(eina_value_struct_get(&other, "v", &i));
+   fail_unless(i == 23);
+   fail_unless(eina_value_struct_get(&other, "x", &i));
+   fail_unless(i == 24);
+
+   str = eina_value_to_string(&other);
+   fail_unless(str != NULL);
+   fail_unless(strcmp(str, "{a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10, k: 12, l: 13, m: 14, n: 15, o: 16, p: 17, q: 18, r: 19, s: 20, t: 21, u: 22, v: 23, x: 24}") == 0);
+   free(str);
+
+   eina_value_free(value);
+   eina_shutdown();
+}
+END_TEST
+
 void
 eina_test_value(TCase *tc)
 {
@@ -1554,4 +1728,5 @@ eina_test_value(TCase *tc)
    tcase_add_test(tc, eina_value_test_hash);
    tcase_add_test(tc, eina_value_test_timeval);
    tcase_add_test(tc, eina_value_test_blob);
+   tcase_add_test(tc, eina_value_test_struct);
 }