EFL 1.7 svn doobies
[profile/ivi/eina.git] / src / lib / eina_model.c
1 /* EINA - EFL data type library
2  * Copyright (C) 2012 ProFUSION embedded systems
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library;
16  * if not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22
23 #ifdef HAVE_ALLOCA_H
24 # include <alloca.h>
25 #elif defined __GNUC__
26 # define alloca __builtin_alloca
27 #elif defined _AIX
28 # define alloca __alloca
29 #elif defined _MSC_VER
30 # include <malloc.h>
31 # define alloca _alloca
32 #else
33 # include <stddef.h>
34 # ifdef  __cplusplus
35 extern "C"
36 # endif
37 void *alloca (size_t);
38 #endif
39
40 #ifdef HAVE_EXECINFO_H
41 #include <execinfo.h>
42 #endif
43
44 #include "eina_config.h"
45 #include "eina_private.h"
46 #include "eina_error.h"
47 #include "eina_log.h"
48 #include "eina_mempool.h"
49 #include "eina_lock.h"
50 #include "eina_inlist.h"
51 #include "eina_strbuf.h"
52
53 /* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
54 #include "eina_safety_checks.h"
55 #include "eina_value.h" /* eina-safety used in inline.x */
56 #include "eina_model.h"
57
58 /*============================================================================*
59  *                                  Local                                     *
60  *============================================================================*/
61
62 /**
63  * @cond LOCAL
64  */
65
66 static Eina_Mempool *_eina_model_mp = NULL;
67 static Eina_Hash *_eina_model_inner_mps = NULL;
68 static Eina_Lock _eina_model_inner_mps_lock;
69 static char *_eina_model_mp_choice = NULL;
70 static Eina_Hash *_eina_model_descriptions = NULL;
71 static Eina_Lock _eina_model_descriptions_lock;
72 static int _eina_model_log_dom = -1;
73 static enum {
74   EINA_MODEL_DEBUG_NONE = 0,
75   EINA_MODEL_DEBUG_CHECK = 1,
76   EINA_MODEL_DEBUG_BACKTRACE = 2,
77 } _eina_model_debug = EINA_MODEL_DEBUG_NONE;
78 static Eina_Lock _eina_model_debug_list_lock;
79 static Eina_List *_eina_model_debug_list = NULL;
80
81 static const char _eina_model_str_deleted[] = "deleted";
82 static const char _eina_model_str_freed[] = "freed";
83 static const char _eina_model_str_property_set[] =  "property,set";
84 static const char _eina_model_str_property_del[] =  "property,deleted";
85 static const char _eina_model_str_children_changed[] =  "children,changed";
86 static const char _eina_model_str_child_inserted[] =  "child,inserted";
87 static const char _eina_model_str_child_set[] =  "child,set";
88 static const char _eina_model_str_child_del[] =  "child,deleted";
89 static const char _eina_model_str_loaded[] = "loaded";
90 static const char _eina_model_str_unloaded[] = "unloaded";
91 static const char _eina_model_str_properties_loaded[] = "properties,loaded";
92 static const char _eina_model_str_properties_unloaded[] = "properties,unloaded";
93 static const char _eina_model_str_children_loaded[] = "children,loaded";
94 static const char _eina_model_str_children_unloaded[] = "children,unloaded";
95
96 #ifdef CRITICAL
97 #undef CRITICAL
98 #endif
99 #define CRITICAL(...) EINA_LOG_DOM_CRIT(_eina_model_log_dom, __VA_ARGS__)
100
101 #ifdef ERR
102 #undef ERR
103 #endif
104 #define ERR(...) EINA_LOG_DOM_ERR(_eina_model_log_dom, __VA_ARGS__)
105
106 #ifdef WRN
107 #undef WRN
108 #endif
109 #define WRN(...) EINA_LOG_DOM_WARN(_eina_model_log_dom, __VA_ARGS__)
110
111 #ifdef INF
112 #undef INF
113 #endif
114 #define INF(...) EINA_LOG_DOM_INFO(_eina_model_log_dom, __VA_ARGS__)
115
116 #ifdef DBG
117 #undef DBG
118 #endif
119 #define DBG(...) EINA_LOG_DOM_DBG(_eina_model_log_dom, __VA_ARGS__)
120
121
122 /* convenience sort array of Eina_Model* giving compare Eina_Model* instead of
123  * Eina_Model**
124  */
125 static unsigned int
126 _eina_model_array_partition(Eina_Model **array, unsigned int start, unsigned int last, unsigned int pivot, Eina_Compare_Cb compare)
127 {
128    Eina_Model **itr, **itr_end, *tmp, *pivot_value;
129
130    pivot_value = tmp = array[pivot];
131    array[pivot] = array[last];
132    array[last] = tmp;
133
134    pivot = start;
135    itr = array + start;
136    itr_end = array + last;
137    for (; itr < itr_end; itr++)
138      {
139         if (compare(*itr, pivot_value) < 0)
140           {
141              tmp = *itr;
142              *itr = array[pivot];
143              array[pivot] = tmp;
144              pivot++;
145           }
146      }
147
148    tmp = array[last];
149    array[last] = array[pivot];
150    array[pivot] = tmp;
151
152    return pivot;
153 }
154
155 static void
156 _eina_model_array_sort(Eina_Model **array, unsigned int start, unsigned int last, Eina_Compare_Cb compare)
157 {
158    unsigned int pivot, new_pivot;
159
160    if (last <= start)
161      return;
162
163    pivot = start + (last - start) / 2; /* avoid overflow */
164    new_pivot = _eina_model_array_partition(array, start, last, pivot, compare);
165
166    if (start + 1 < new_pivot)
167      _eina_model_array_sort(array, start, new_pivot - 1, compare);
168
169    if (new_pivot + 1 < last)
170      _eina_model_array_sort(array, new_pivot + 1, last, compare);
171 }
172
173 /*
174  * Most of inner allocations are made with internal mempools, types
175  * and thus instace private data will repeat and it's good to use them.
176  *
177  * To save on the number of mempools, they are kept per size, not per
178  * type.
179  *
180  * This is done by means of _eina_model_inner_alloc() and
181  * _eina_model_inner_free(), both at thread safe.
182  *
183  */
184 typedef struct _Eina_Model_Inner_Mp Eina_Model_Inner_Mp;
185 struct _Eina_Model_Inner_Mp
186 {
187    Eina_Mempool *mempool;
188    int refcount;
189 };
190
191 static inline void
192 _eina_model_inner_mp_dispose(int size, Eina_Model_Inner_Mp *imp)
193 {
194    EINA_SAFETY_ON_FALSE_RETURN(imp->refcount == 0);
195
196    eina_hash_del_by_key(_eina_model_inner_mps, &size);
197    eina_mempool_del(imp->mempool);
198    free(imp);
199 }
200
201 static inline Eina_Model_Inner_Mp *
202 _eina_model_inner_mp_get(int size)
203 {
204    Eina_Model_Inner_Mp *imp = eina_hash_find(_eina_model_inner_mps, &size);
205    if (imp) return imp;
206
207    imp = malloc(sizeof(Eina_Model_Inner_Mp));
208    if (!imp)
209      return NULL;
210
211    imp->refcount = 0;
212
213    imp->mempool = eina_mempool_add(_eina_model_mp_choice,
214                                    "Eina_Model_Inner_Mp", NULL, size, 16);
215    if (!imp->mempool)
216      {
217         free(imp);
218         return NULL;
219      }
220
221    if (!eina_hash_add(_eina_model_inner_mps, &size, imp))
222      {
223         eina_mempool_del(imp->mempool);
224         free(imp);
225         return NULL;
226      }
227
228    return imp;
229 }
230
231 static inline void *
232 _eina_model_inner_alloc_internal(int size)
233 {
234    Eina_Model_Inner_Mp *imp;
235    void *mem;
236
237    imp = _eina_model_inner_mp_get(size);
238    if (!imp) return NULL;
239
240    mem = eina_mempool_malloc(imp->mempool, size);
241    if (mem) imp->refcount++;
242    else if (imp->refcount == 0) _eina_model_inner_mp_dispose(size, imp);
243
244    return mem;
245 }
246
247 static inline void
248 _eina_model_inner_free_internal(int size, void *mem)
249 {
250    Eina_Model_Inner_Mp *imp = eina_hash_find(_eina_model_inner_mps, &size);
251    EINA_SAFETY_ON_NULL_RETURN(imp);
252
253    eina_mempool_free(imp->mempool, mem);
254
255    imp->refcount--;
256    if (imp->refcount > 0) return;
257    _eina_model_inner_mp_dispose(size, imp);
258 }
259
260 static void *
261 _eina_model_inner_alloc(size_t size)
262 {
263    void *mem;
264
265    if (size > 512) return malloc(size);
266
267    eina_lock_take(&_eina_model_inner_mps_lock);
268    mem = _eina_model_inner_alloc_internal(size);
269    eina_lock_release(&_eina_model_inner_mps_lock);
270
271    return mem;
272 }
273
274 static void
275 _eina_model_inner_free(size_t size, void *mem)
276 {
277    if (size > 512)
278      {
279         free(mem);
280         return;
281      }
282
283    eina_lock_take(&_eina_model_inner_mps_lock);
284    _eina_model_inner_free_internal(size, mem);
285    eina_lock_release(&_eina_model_inner_mps_lock);
286 }
287
288
289 typedef union _Eina_Model_Provider Eina_Model_Provider;
290 union _Eina_Model_Provider
291 {
292    const Eina_Model_Type *type;
293    const Eina_Model_Interface *iface;
294 };
295
296 /* store event name to aid searching */
297 typedef struct _Eina_Model_Event_Description_Cache Eina_Model_Event_Description_Cache;
298 struct _Eina_Model_Event_Description_Cache
299 {
300    const char *name;
301    const Eina_Model_Event_Description *desc;
302    Eina_Model_Provider provider;
303 };
304
305 /* description is an optimized structure for type. It's built at runtime
306  * to avoid user input errors and help declaration.
307  *
308  * lookups (ifaces, events) are sorted for binary search.
309  *
310  * recursion is avoided by expansion of every possible value in "cache"
311  * struct.
312  *
313  * the first usable operation is stopred for type at "ops" struct,
314  * avoiding usage of _eina_model_type_find_offset().
315  *
316  * Get a model type description using _eina_model_description_get(),
317  * when it's not used anymore use
318  * _eina_model_description_dispose(). These operations are thread
319  * safe.
320  */
321 typedef struct _Eina_Model_Description Eina_Model_Description;
322 struct _Eina_Model_Description
323 {
324    struct {
325       const Eina_Model_Type **types; /* size = total.types */
326       const Eina_Model_Interface **ifaces; /* sorted, size = total.ifaces */
327       Eina_Model_Provider *privates; /* size = total.privates (types + ifaces) */
328       Eina_Model_Event_Description_Cache *events; /* size = total.events */
329    } cache;
330    struct {
331       /* ops are the topmost operation to use for type/interface */
332       struct {
333          Eina_Bool (*setup)(Eina_Model *model);
334          Eina_Bool (*flush)(Eina_Model *model);
335          Eina_Bool (*constructor)(Eina_Model *model);
336          Eina_Bool (*destructor)(Eina_Model *model);
337          Eina_Bool (*copy)(const Eina_Model *src, Eina_Model *dst);
338          Eina_Bool (*deep_copy)(const Eina_Model *src, Eina_Model *dst);
339          Eina_Bool (*compare)(const Eina_Model *a, const Eina_Model *b, int *cmp);
340          Eina_Bool (*load)(Eina_Model *model);
341          Eina_Bool (*unload)(Eina_Model *model);
342          Eina_Bool (*property_get)(const Eina_Model *model, const char *name, Eina_Value *value);
343          Eina_Bool (*property_set)(Eina_Model *model, const char *name, const Eina_Value *value);
344          Eina_Bool (*property_del)(Eina_Model *model, const char *name);
345          Eina_List *(*properties_names_list_get)(const Eina_Model *model);
346          int (*child_count)(const Eina_Model *model);
347          Eina_Model *(*child_get)(const Eina_Model *model, unsigned int position);
348          Eina_Bool (*child_set)(Eina_Model *model, unsigned int position, Eina_Model *child);
349          Eina_Bool (*child_del)(Eina_Model *model, unsigned int position);
350          Eina_Bool (*child_insert_at)(Eina_Model *model, unsigned int position, Eina_Model *child);
351          int (*child_find)(const Eina_Model *model, unsigned int start_position, const Eina_Model *other);
352          int (*child_criteria_match)(const Eina_Model *model, unsigned int start_position, Eina_Each_Cb match, const void *data);
353          void (*child_sort)(Eina_Model *model, Eina_Compare_Cb compare);
354          Eina_Iterator *(*child_iterator_get)(Eina_Model *model, unsigned int start, unsigned int count);
355          Eina_Iterator *(*child_reversed_iterator_get)(Eina_Model *model, unsigned int start, unsigned int count);
356          Eina_Iterator *(*child_sorted_iterator_get)(Eina_Model *model, unsigned int start, unsigned int count, Eina_Compare_Cb compare);
357          Eina_Iterator *(*child_filtered_iterator_get)(Eina_Model *model, unsigned int start, unsigned int count, Eina_Each_Cb match, const void *data);
358          char *(*to_string)(const Eina_Model *model); /**< used to represent model as string, usually for debug purposes or user convenience */
359          const void **extension;
360       } type;
361    } ops;
362    struct {
363       unsigned int types;
364       unsigned int ifaces;
365       unsigned int privates;
366       unsigned int size; /* sum of all private sizes */
367       unsigned int events;
368    } total;
369    int refcount;
370 };
371
372 static Eina_Bool
373 _eina_model_description_type_fill(Eina_Model_Description *desc, const Eina_Model_Type *type)
374 {
375    const Eina_Model_Type *itr, *last_itr = NULL;
376    unsigned int count, child_size = 0;
377
378    for (count = 0, itr = type; itr != NULL; itr = itr->parent, count++)
379      {
380         if (itr->version != EINA_MODEL_TYPE_VERSION)
381           {
382              CRITICAL("Type %p version is %u, expected %u instead.",
383                       itr, itr->version, EINA_MODEL_TYPE_VERSION);
384              return EINA_FALSE;
385           }
386         if (!itr->name)
387           {
388              CRITICAL("Type %p provides no name!", itr);
389              return EINA_FALSE;
390           }
391         if (itr->type_size < sizeof(Eina_Model_Type))
392           {
393              CRITICAL("Type %p %s size must be >= sizeof(Eina_Model_Type)!",
394                       itr, itr->name);
395              return EINA_FALSE;
396           }
397         if (child_size == 0) child_size = itr->type_size;
398         else if (child_size < itr->type_size)
399           {
400              CRITICAL("Type %p %s size is bigger than its child type %p %s!",
401                       itr, itr->name, last_itr, last_itr->name);
402              return EINA_FALSE;
403           }
404         last_itr = itr;
405
406 #define DEF_METH(meth)                                                  \
407         if (!desc->ops.type.meth) desc->ops.type.meth = itr->meth
408         DEF_METH(setup);
409         DEF_METH(flush);
410         DEF_METH(constructor);
411         DEF_METH(destructor);
412         DEF_METH(copy);
413         DEF_METH(deep_copy);
414         DEF_METH(compare);
415         DEF_METH(load);
416         DEF_METH(unload);
417         DEF_METH(property_get);
418         DEF_METH(property_set);
419         DEF_METH(property_del);
420         DEF_METH(properties_names_list_get);
421         DEF_METH(child_count);
422         DEF_METH(child_get);
423         DEF_METH(child_set);
424         DEF_METH(child_del);
425         DEF_METH(child_insert_at);
426         DEF_METH(child_find);
427         DEF_METH(child_criteria_match);
428         DEF_METH(child_sort);
429         DEF_METH(child_iterator_get);
430         DEF_METH(child_reversed_iterator_get);
431         DEF_METH(child_sorted_iterator_get);
432         DEF_METH(child_filtered_iterator_get);
433         DEF_METH(to_string);
434 #undef DEF_METH
435
436         if ((!itr->parent) && (itr != EINA_MODEL_TYPE_BASE))
437           {
438              CRITICAL("Type %p (%s) does not inherit from EINA_MODEL_TYPE_BASE!",
439                       type, type->name);
440              return EINA_FALSE;
441           }
442      }
443
444 #define CK_METH(meth)                                           \
445    if (!desc->ops.type.meth)                                    \
446      {                                                          \
447         CRITICAL("Mandatory method "#meth                       \
448                  "() was not provided by type %p (%s).",        \
449                  type, type->name);                             \
450         return EINA_FALSE;                                      \
451      }
452    CK_METH(setup);
453    CK_METH(flush);
454    CK_METH(constructor);
455    CK_METH(destructor);
456    CK_METH(property_get);
457 #undef CK_METH
458
459    if (child_size <= sizeof(Eina_Model_Type))
460      desc->ops.type.extension = NULL;
461    else
462      {
463         unsigned ext_size = child_size - sizeof(Eina_Model_Type);
464         unsigned ext_count = ext_size / sizeof(void *);
465
466         if (ext_size % sizeof(void *) != 0)
467           {
468              CRITICAL("Extension size %u is not multiple of sizeof(void*)",
469                       ext_size);
470              return EINA_FALSE;
471           }
472
473         desc->ops.type.extension = calloc(ext_count, sizeof(void *));
474         EINA_SAFETY_ON_NULL_RETURN_VAL(desc->ops.type.extension, EINA_FALSE);
475
476         for (itr = type; itr != NULL; itr = itr->parent)
477           {
478              unsigned cur_size = itr->type_size - sizeof(Eina_Model_Type);
479              unsigned i, cur_count = cur_size / sizeof(void *);
480              const void * const *ptr = (const void **)((const char *)itr + sizeof(Eina_Model_Type));
481
482              if (cur_size == 0) break;
483
484              for (i = 0; i < cur_count; i++)
485                {
486                   if (desc->ops.type.extension[i]) continue;
487                   desc->ops.type.extension[i] = ptr[i];
488                }
489           }
490      }
491
492    desc->cache.types = malloc(count * sizeof(Eina_Model_Type *));
493    EINA_SAFETY_ON_NULL_GOTO(desc->cache.types, cache_types_failed);
494    desc->total.types = count;
495
496    for (count = 0, itr = type; itr != NULL; itr = itr->parent, count++)
497      desc->cache.types[count] = itr;
498
499    return EINA_TRUE;
500
501  cache_types_failed:
502    free(desc->ops.type.extension);
503    return EINA_FALSE;
504 }
505
506 static inline Eina_Bool
507 _eina_model_interface_implements(const Eina_Model_Interface *iface, const Eina_Model_Interface *query)
508 {
509    const Eina_Model_Interface **itr;
510
511    if (iface == query)
512      return EINA_TRUE;
513
514    if (!iface->interfaces)
515      return EINA_FALSE;
516
517    for (itr = iface->interfaces; *itr != NULL; itr++)
518      if (_eina_model_interface_implements(*itr, query))
519        return EINA_TRUE;
520
521    return EINA_FALSE;
522 }
523
524 /* apply topological sort and remove duplicates */
525 /*
526  * TODO: Topological sort will only work for linked interfaces, but
527  *       will ignore original ordering provided by types. Consider the
528  *       following:
529  *
530  *         - A_Type -> X_Iface (name: "MyIface")
531  *         - B_Type -> Y_Iface (name: "MyIface")
532  *
533  *       Both X_Iface and Y_Iface are different implementations of the
534  *       "MyIface".
535  *
536  *       B_Type inherits from A_Type, then Y_Iface must be looked up
537  *       first, even though there is no link between Y_Iface and
538  *       X_Iface.
539  *
540  *       However, the way the current topological sort behaves, the
541  *       roots may come out in any order. We need a stable version
542  *       that sorts roots before removing them from graph.
543  *
544  * Thanks to Tasn to report it :-)
545  */
546 static Eina_Bool
547 _eina_model_description_ifaces_fix(Eina_Model_Description *desc)
548 {
549    struct node {
550       const Eina_Model_Interface *iface;
551       unsigned int users;
552       Eina_List *deps;
553    } *nodes, **pending, **roots;
554    unsigned int n_nodes = desc->total.ifaces, n_pending = 0, n_roots = 0, i, j;
555    Eina_Bool ret = EINA_TRUE;
556
557    nodes = alloca(n_nodes * sizeof(struct node));
558    pending = alloca(n_nodes * sizeof(struct node *));
559    roots = alloca(n_nodes * sizeof(struct node *));
560
561    /* populate */
562    for (i = 0, j = 0; i < n_nodes; i++)
563      {
564         unsigned int k;
565         for (k = 0; k < j; k++)
566           {
567              if (nodes[k].iface == desc->cache.ifaces[i])
568                break;
569           }
570         if (k < j)
571           continue; /* already exists */
572
573         nodes[j].iface = desc->cache.ifaces[i];
574         nodes[j].users = 0;
575         nodes[j].deps = NULL;
576         j++;
577      }
578    n_nodes = j;
579
580    for (i = 0; i < n_nodes; i++)
581      {
582         for (j = 0; j < n_nodes; j++)
583           {
584              if (i == j) continue;
585              if (!_eina_model_interface_implements(nodes[j].iface,
586                                                    nodes[i].iface))
587                continue;
588
589              nodes[i].users++;
590              nodes[j].deps = eina_list_append(nodes[j].deps, nodes + i);
591           }
592      }
593    for (i = 0; i < n_nodes; i++)
594      {
595         if (nodes[i].users == 0)
596           {
597              roots[n_roots] = nodes + i;
598              n_roots++;
599           }
600         else
601           {
602              pending[n_pending] = nodes + i;
603              n_pending++;
604           }
605      }
606
607    /* topological sort */
608    desc->total.ifaces = 0;
609    while (n_roots > 0)
610      {
611         struct node *r, *d;
612
613         /* TODO: sort roots using input order?  Or at least study if
614          * it's enough to change roots append to prepend.
615          *
616          * See comments above.
617          */
618         n_roots--;
619         r = roots[n_roots];
620
621         desc->cache.ifaces[desc->total.ifaces] = r->iface;
622         desc->total.ifaces++;
623
624         EINA_LIST_FREE(r->deps, d)
625           {
626              d->users--;
627              if (d->users > 0) continue;
628
629              roots[n_roots] = d;
630              n_roots++;
631
632              /* remove node, it became a root */
633              for (j = 0; j < n_pending; j++)
634                {
635                   if (pending[j] == d)
636                     {
637                        n_pending--;
638                        if (j < n_pending)
639                          pending[j] = pending[n_pending];
640                        break;
641                     }
642                }
643           }
644      }
645
646    if (n_pending > 0)
647      {
648         ERR("Dependency loop found for interfaces!");
649         for (i = 0; i < n_pending; i++)
650           ERR("%p (%s) is part of dependency loop!",
651               pending[i]->iface, pending[i]->iface->name);
652         CRITICAL("Cannot use type %p (%s) with broken interfaces!",
653                  desc->cache.types[0], desc->cache.types[0]->name);
654         free(desc->cache.ifaces);
655         ret = EINA_FALSE;
656      }
657
658    /* likely from still pending (dependency loops) */
659    for (i = 0; i < n_nodes; i++)
660      eina_list_free(nodes[i].deps);
661
662    return ret;
663 }
664
665 static Eina_Bool
666 _eina_model_description_ifaces_validate_and_count(const Eina_Model_Interface *iface, unsigned int *count)
667 {
668    if (iface->version != EINA_MODEL_INTERFACE_VERSION)
669      {
670         CRITICAL("Interface %p version is %u, expected %u instead.",
671                  iface, iface->version, EINA_MODEL_INTERFACE_VERSION);
672         return EINA_FALSE;
673      }
674
675    if (!iface->name)
676      {
677         CRITICAL("Interface %p provides no name!", iface);
678         return EINA_FALSE;
679      }
680
681    if (iface->interfaces)
682      {
683         const Eina_Model_Interface **itr = iface->interfaces;
684         for (; *itr != NULL; itr++)
685           if (!_eina_model_description_ifaces_validate_and_count(*itr, count))
686             return EINA_FALSE;
687      }
688
689    (*count)++;
690    return EINA_TRUE;
691 }
692
693 static void
694 _eina_model_description_ifaces_populate(Eina_Model_Description *desc, const Eina_Model_Interface *iface)
695 {
696    desc->cache.ifaces[desc->total.ifaces] = iface;
697    desc->total.ifaces++;
698
699    if (iface->interfaces)
700      {
701         const Eina_Model_Interface **itr = iface->interfaces;
702         for (; *itr != NULL; itr++)
703           _eina_model_description_ifaces_populate(desc, *itr);
704      }
705 }
706
707 static Eina_Bool
708 _eina_model_description_ifaces_fill(Eina_Model_Description *desc)
709 {
710    const Eina_Model_Type **titr, **titr_end;
711    unsigned int count;
712
713    titr = desc->cache.types;
714    titr_end = titr + desc->total.types;
715
716    /* naively count all interfaces, remove duplicates later */
717    for (count = 0; titr < titr_end; titr++)
718      {
719         const Eina_Model_Type *type = *titr;
720         const Eina_Model_Interface **iitr = type->interfaces;
721         if (!type->interfaces) continue;
722
723         for (; *iitr != NULL; iitr++)
724           if (!_eina_model_description_ifaces_validate_and_count(*iitr, &count))
725             return EINA_FALSE;
726      }
727    if (count == 0)
728      {
729         desc->cache.ifaces = NULL;
730         desc->total.ifaces = 0;
731         return EINA_TRUE;
732      }
733
734    desc->cache.ifaces = malloc(count * sizeof(Eina_Model_Interface *));
735    EINA_SAFETY_ON_NULL_RETURN_VAL(desc->cache.ifaces, EINA_FALSE);
736
737    titr = desc->cache.types;
738    desc->total.ifaces = 0;
739    for (; titr < titr_end; titr++)
740      {
741         const Eina_Model_Type *type = *titr;
742         const Eina_Model_Interface **iitr = type->interfaces;
743
744         if (!type->interfaces) continue;
745
746         for (; *iitr != NULL; iitr++)
747           _eina_model_description_ifaces_populate(desc, *iitr);
748      }
749
750    return _eina_model_description_ifaces_fix(desc);
751 }
752
753 static Eina_Bool
754 _eina_model_description_privates_fill(Eina_Model_Description *desc)
755 {
756    unsigned int i;
757
758    desc->total.privates = desc->total.types + desc->total.ifaces;
759    desc->cache.privates = malloc(desc->total.privates *
760                                  sizeof(Eina_Model_Provider));
761    EINA_SAFETY_ON_NULL_RETURN_VAL(desc->cache.privates, EINA_FALSE);
762
763    desc->total.size = 0;
764
765    for (i = 0; i < desc->total.types; i++)
766      {
767         const Eina_Model_Type *type = desc->cache.types[i];
768         desc->cache.privates[i].type = type;
769         if (type->private_size > 0)
770           {
771              unsigned int size = type->private_size;
772              if (size % sizeof(void *) != 0)
773                size += sizeof(void *) - (size % sizeof(void *));
774              desc->total.size += size;
775           }
776      }
777
778    for (i = 0; i < desc->total.ifaces; i++)
779      {
780         const Eina_Model_Interface *iface = desc->cache.ifaces[i];
781         desc->cache.privates[desc->total.types + i].iface = iface;
782         if (iface->private_size > 0)
783           {
784              unsigned int size = iface->private_size;
785              if (size % sizeof(void *) != 0)
786                size += sizeof(void *) - (size % sizeof(void *));
787              desc->total.size += size;
788           }
789      }
790
791    return EINA_TRUE;
792 }
793
794 static int
795 _eina_model_description_events_cmp(const void *pa, const void *pb)
796 {
797    const Eina_Model_Event_Description_Cache *a = pa, *b = pb;
798    return strcmp(a->name, b->name);
799 }
800
801 static int
802 _eina_model_description_events_find(const Eina_Model_Description *desc, const Eina_Model_Event_Description *query)
803 {
804    unsigned int i;
805    for (i = 0; i < desc->total.events; i++)
806      {
807         const Eina_Model_Event_Description_Cache *itr = desc->cache.events + i;
808         if ((itr->name == query->name) || (strcmp(itr->name, query->name) == 0))
809           return i;
810      }
811
812    return -1;
813 }
814
815 /* warn and remove duplicates, sort items to speed up lookups */
816 static Eina_Bool
817 _eina_model_description_events_fill(Eina_Model_Description *desc)
818 {
819    unsigned int i, count = 0, type_events;
820
821    for (i = 0; i < desc->total.types; i++)
822      {
823         const Eina_Model_Event_Description *itr = desc->cache.types[i]->events;
824         if (!itr) continue;
825         for (; itr->name != NULL; itr++)
826           {
827              count++;
828           }
829      }
830    type_events = count;
831
832    for (i = 0; i < desc->total.ifaces; i++)
833      {
834         const Eina_Model_Event_Description *itr = desc->cache.ifaces[i]->events;
835         if (!itr) continue;
836         for (; itr->name != NULL; itr++)
837           count++;
838      }
839
840    if (count == 0)
841      {
842         desc->cache.events = NULL;
843         desc->total.events = 0;
844         return EINA_TRUE;
845      }
846
847    desc->cache.events = malloc(count *
848                                sizeof(Eina_Model_Event_Description_Cache));
849    EINA_SAFETY_ON_NULL_RETURN_VAL(desc->cache.events, EINA_FALSE);
850    desc->total.events = 0;
851
852    for (i = 0; i < desc->total.types; i++)
853      {
854         const Eina_Model_Type *mtype = desc->cache.types[i];
855         const Eina_Model_Event_Description *itr = mtype->events;
856         if (!itr) continue;
857         for (; itr->name != NULL; itr++)
858           {
859              int j = _eina_model_description_events_find(desc, itr);
860              if (j >= 0)
861                {
862                   const Eina_Model_Event_Description_Cache *o = desc->cache.events + j;
863                   const Eina_Model_Type *omtype = o->provider.type;
864                   WRN("Ignored duplicated event '%s' (type: '%s') from "
865                       "model type %p (%s): already exists with type '%s' "
866                       "from model type %p (%s)",
867                       itr->name,
868                       itr->type ? itr->type : "",
869                       mtype, mtype->name,
870                       o->desc->type ? o->desc->type : "",
871                       omtype, omtype->name);
872                   continue;
873                }
874
875              desc->cache.events[desc->total.events].name = itr->name;
876              desc->cache.events[desc->total.events].desc = itr;
877              desc->cache.events[desc->total.events].provider.type = mtype;
878              desc->total.events++;
879           }
880      }
881
882    for (i = 0; i < desc->total.ifaces; i++)
883      {
884         const Eina_Model_Interface *miface = desc->cache.ifaces[i];
885         const Eina_Model_Event_Description *itr = desc->cache.ifaces[i]->events;
886         if (!itr) continue;
887         for (; itr->name != NULL; itr++)
888           {
889              int j = _eina_model_description_events_find(desc, itr);
890              if (j >= 0)
891                {
892                   const Eina_Model_Event_Description_Cache *o = desc->cache.events + j;
893                   if ((unsigned)j < type_events)
894                     {
895                        const Eina_Model_Type *omtype = o->provider.type;
896                        WRN("Ignored duplicated event '%s' (type: '%s') from "
897                            "model interface %p (%s): already exists with "
898                            "type '%s' from model interface %p (%s)",
899                            itr->name,
900                            itr->type ? itr->type : "",
901                            miface, miface->name,
902                            o->desc->type ? o->desc->type : "",
903                            omtype, omtype->name);
904                     }
905                   else
906                     {
907                        const Eina_Model_Interface *omiface = o->provider.iface;
908                        WRN("Ignored duplicated event '%s' (iface: '%s') from "
909                            "model interface %p (%s): already exists with "
910                            "interface '%s' from model interface %p (%s)",
911                            itr->name,
912                            itr->type ? itr->type : "",
913                            miface, miface->name,
914                            o->desc->type ? o->desc->type : "",
915                            omiface, omiface->name);
916                     }
917                   continue;
918                }
919
920              desc->cache.events[desc->total.events].name = itr->name;
921              desc->cache.events[desc->total.events].desc = itr;
922              desc->cache.events[desc->total.events].provider.iface = miface;
923              desc->total.events++;
924           }
925      }
926
927    qsort(desc->cache.events, desc->total.events,
928          sizeof(Eina_Model_Event_Description_Cache),
929          _eina_model_description_events_cmp);
930
931    return EINA_TRUE;
932 }
933
934 static const Eina_Model_Description *
935 _eina_model_description_get_internal(const Eina_Model_Type *type)
936 {
937    Eina_Model_Description *desc;
938
939    desc = eina_hash_find(_eina_model_descriptions, &type);
940    if (desc)
941      {
942         desc->refcount++;
943         return desc;
944      }
945
946    desc = calloc(1, sizeof(Eina_Model_Description));
947    EINA_SAFETY_ON_NULL_RETURN_VAL(desc, NULL);
948
949    if (!_eina_model_description_type_fill(desc, type)) goto failed_type;
950    if (!_eina_model_description_ifaces_fill(desc)) goto failed_ifaces;
951    if (!_eina_model_description_privates_fill(desc)) goto failed_privates;
952    if (!_eina_model_description_events_fill(desc)) goto failed_events;
953    if (!eina_hash_add(_eina_model_descriptions, &type, desc)) goto failed_hash;
954
955    desc->refcount = 1;
956    return desc;
957
958  failed_hash:
959    free(desc->cache.events);
960  failed_events:
961    free(desc->cache.privates);
962  failed_privates:
963    free(desc->cache.ifaces);
964  failed_ifaces:
965    free(desc->cache.types);
966    free(desc->ops.type.extension);
967  failed_type:
968    free(desc);
969    return NULL;
970 }
971
972 static void
973 _eina_model_description_dispose_internal(Eina_Model_Description *desc)
974 {
975    const Eina_Model_Type *type;
976
977    EINA_SAFETY_ON_FALSE_RETURN(desc->refcount > 0);
978    desc->refcount--;
979    if (desc->refcount > 0) return;
980
981    type = desc->cache.types[0];
982    if (!eina_hash_del_by_key(_eina_model_descriptions, &type))
983      ERR("Cannot find type %p (%s) in descriptions hash!",
984          type, type->name);
985
986    INF("Disposed model description for type %p (%s)", type, type->name);
987
988    free(desc->ops.type.extension);
989    free(desc->cache.types);
990    free(desc->cache.ifaces);
991    free(desc->cache.privates);
992    free(desc->cache.events);
993    free(desc);
994 }
995
996 static const Eina_Model_Description *
997 _eina_model_description_get(const Eina_Model_Type *type)
998 {
999    const Eina_Model_Description *desc;
1000
1001    eina_lock_take(&_eina_model_descriptions_lock);
1002    desc = _eina_model_description_get_internal(type);
1003    eina_lock_release(&_eina_model_descriptions_lock);
1004
1005    return desc;
1006 }
1007
1008 static void
1009 _eina_model_description_dispose(const Eina_Model_Description *desc)
1010 {
1011    eina_lock_take(&_eina_model_descriptions_lock);
1012    _eina_model_description_dispose_internal((Eina_Model_Description *)desc);
1013    eina_lock_release(&_eina_model_descriptions_lock);
1014 }
1015
1016 static inline int
1017 _eina_model_description_event_id_find(const Eina_Model_Description *desc, const char *event_name)
1018 {
1019    const Eina_Model_Event_Description_Cache *cache;
1020    Eina_Model_Event_Description_Cache criteria_match;
1021
1022    criteria_match.name = event_name;
1023    cache = bsearch(&criteria_match, desc->cache.events, desc->total.events,
1024                    sizeof(Eina_Model_Event_Description_Cache),
1025                    _eina_model_description_events_cmp);
1026    if (!cache)
1027      {
1028         ERR("No event named %s for type %p (%s)", event_name,
1029             desc->cache.types[0], desc->cache.types[0]->name);
1030         return -1;
1031      }
1032
1033    return cache - desc->cache.events;
1034 }
1035
1036 /*
1037  * Model management and book keeping
1038  */
1039 typedef struct _Eina_Model_Event_Listener Eina_Model_Event_Listener;
1040 struct _Eina_Model_Event_Listener
1041 {
1042    EINA_INLIST;
1043    Eina_Model_Event_Cb cb;
1044    const void *data;
1045    Eina_Bool deleted:1;
1046 };
1047
1048 struct _Eina_Model
1049 {
1050    const Eina_Model_Description *desc; /**< optimized model description */
1051    struct {
1052       Eina_Inlist **entries; /**< connected/listeners for each event, array of lists of Eina_Model_Event_Listener */
1053       Eina_List **deleted; /**< deleted listeners while was walking. array of lists of Eina_Model_Event_Listener with deleted flag */
1054       int *freeze; /**< freeze count for each event */
1055       int walking; /**< increased while walking entries lists */
1056    } listeners;
1057    void **privates; /**< private data per type and interface, each level gets its own stuff */
1058    Eina_Inlist *xrefs; /**< if EINA_MODEL_DEBUG and eina_model_xref() is used */
1059    int refcount; /**< number of users of this model instance */
1060    Eina_Bool deleted:1; /**< if deleted but still have references */
1061    EINA_MAGIC
1062 };
1063
1064 static inline Eina_Bool
1065 _eina_model_type_check(const Eina_Model_Type *type)
1066 {
1067    EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE);
1068    EINA_SAFETY_ON_FALSE_RETURN_VAL(type->version == EINA_MODEL_TYPE_VERSION,
1069                                    EINA_FALSE);
1070    return EINA_TRUE;
1071 }
1072
1073 /* find in type hierarchy the first one that the given offset is not a null
1074  * pointer. Use this to discover which method to call on a parent.
1075  */
1076 static const void *
1077 _eina_model_type_find_offset(const Eina_Model_Type *type, unsigned int offset)
1078 {
1079    const unsigned char *ptr = (const unsigned char *)type;
1080    const void **addr = (const void **)(ptr + offset);
1081
1082    if (*addr) return *addr;
1083    if (!type->parent) return NULL;
1084    return _eina_model_type_find_offset(type->parent, offset);
1085 }
1086
1087 /* find in interface hierarchy the first one that the given offset is
1088  * not a null pointer. Use this to discover which method to call on a
1089  * parent.
1090  *
1091  * TODO: Keep Eina_Model_Interface_Description with topological sorted
1092  *       entries for each interface?
1093  *       I smell problems with the current code in more complex
1094  *       situations (k-s)
1095  *
1096  *             iface1
1097  *               ^
1098  *               |
1099  *     .---------+---------.
1100  *     |         |         |
1101  *   iface2    iface3    iface4
1102  *     ^         ^         ^
1103  *     |         |         |
1104  *     `---------+---------'
1105  *               |
1106  *             iface5
1107  *
1108  * It should look: iface5 -> iface2 -> iface3 -> iface4 -> iface1
1109  * Now it does: iface5 -> iface2 -> iface1 -> iface3 -> iface1 -> iface4 -> iface1
1110  *
1111  *
1112  *             iface1
1113  *               ^
1114  *               |
1115  *             iface2
1116  *               ^
1117  *               |
1118  *     .---------+---------.
1119  *     |                   |
1120  *   iface3              iface4
1121  *     ^                   ^
1122  *     |                   |
1123  *     `---------+---------'
1124  *               |
1125  *             iface5
1126  *
1127  * It should look: iface5 -> iface3 -> iface4 -> iface2 -> iface1
1128  * Now it does: iface5 -> iface3 -> iface2 -> iface1 -> iface4 -> iface2 -> iface1
1129  *
1130  *
1131  *   iface1              iface2
1132  *     ^                   ^
1133  *     |                   |
1134  *     `---------+---------'
1135  *               |
1136  *             iface3
1137  *
1138  * It should look: iface3 -> iface1 -> iface2
1139  * Now it does: iface3 -> iface1 -> iface2
1140  *
1141  * For the common case it should work, let's see.
1142  */
1143 static const void *
1144 _eina_model_interface_find_offset(const Eina_Model_Interface *iface, unsigned int offset)
1145 {
1146    const Eina_Model_Interface **itr;
1147    const unsigned char *ptr = (const unsigned char *)iface;
1148    const void **addr = (const void **)(ptr + offset);
1149
1150    if (offset + sizeof(void *) > iface->interface_size) return NULL;
1151
1152    if (*addr) return *addr;
1153    if (!iface->interfaces) return NULL;
1154
1155    for (itr = iface->interfaces; *itr != NULL; itr++)
1156      {
1157         const void *r = _eina_model_interface_find_offset(*itr, offset);
1158         if (r)
1159           return r;
1160      }
1161
1162    return NULL;
1163 }
1164
1165 static void
1166 _eina_model_event_callback_free_deleted(Eina_Model *model)
1167 {
1168    unsigned int i;
1169
1170    for (i = 0; i < model->desc->total.events; i++)
1171      {
1172         Eina_Model_Event_Listener *el;
1173         EINA_LIST_FREE(model->listeners.deleted[i], el)
1174           {
1175              model->listeners.entries[i] = eina_inlist_remove
1176                (model->listeners.entries[i], EINA_INLIST_GET(el));
1177              _eina_model_inner_free(sizeof(Eina_Model_Event_Listener), el);
1178           }
1179      }
1180
1181    _eina_model_inner_free(model->desc->total.events * sizeof(Eina_List *),
1182                           model->listeners.deleted);
1183    model->listeners.deleted = NULL;
1184 }
1185
1186 static inline Eina_Bool
1187 _eina_model_event_callback_call(Eina_Model *model, const char *name, const void *event_info)
1188 {
1189    Eina_Inlist *lst;
1190    Eina_Model_Event_Listener *el;
1191    const Eina_Model_Event_Description *ev_desc;
1192    int event_id = _eina_model_description_event_id_find(model->desc, name);
1193
1194    if (event_id < 0) return EINA_FALSE;
1195    if (!model->listeners.entries) return EINA_TRUE;
1196
1197    if ((model->listeners.freeze) && (model->listeners.freeze[event_id]))
1198      {
1199         DBG("Ignored event callback '%s' of model %p (%s): frozen",
1200             name, model, model->desc->cache.types[0]->name);
1201         return EINA_TRUE;
1202      }
1203
1204    lst = model->listeners.entries[event_id];
1205    if (!lst) return EINA_TRUE;
1206
1207    ev_desc = model->desc->cache.events[event_id].desc;
1208
1209    model->listeners.walking++;
1210    EINA_INLIST_FOREACH(lst, el)
1211      {
1212         if (el->deleted) continue;
1213         el->cb((void *)el->data, model, ev_desc, (void *)event_info);
1214      }
1215    model->listeners.walking--;
1216
1217    if ((model->listeners.walking == 0) && (model->listeners.deleted))
1218      _eina_model_event_callback_free_deleted(model);
1219
1220    return EINA_FALSE;
1221 }
1222
1223 static const char EINA_ERROR_MODEL_FAILED_STR[] = "Model check failed.";
1224 static const char EINA_ERROR_MODEL_METHOD_MISSING_STR[] = "Model method is missing.";
1225 static const char EINA_MAGIC_MODEL_STR[] = "Eina Model";
1226
1227 static void _eina_model_unref(Eina_Model *model);
1228
1229 /**
1230  * @endcond
1231  */
1232
1233 /* EINA_MODEL_TYPE_BASE: base of all other types **********************/
1234
1235 static Eina_Bool
1236 _eina_model_type_base_setup(Eina_Model *model)
1237 {
1238    DBG("base setup of %p", model);
1239    return EINA_TRUE;
1240 }
1241
1242 static Eina_Bool
1243 _eina_model_type_base_flush(Eina_Model *model)
1244 {
1245    DBG("base flush of %p", model);
1246    return EINA_TRUE;
1247 }
1248
1249 static Eina_Bool
1250 _eina_model_type_base_constructor(Eina_Model *model)
1251 {
1252    DBG("base constructor of %p", model);
1253    return EINA_TRUE;
1254 }
1255
1256 static Eina_Bool
1257 _eina_model_type_base_destructor(Eina_Model *model)
1258 {
1259    DBG("base destructor of %p", model);
1260    return EINA_TRUE;
1261 }
1262
1263 static Eina_Bool
1264 _eina_model_type_base_properties_copy(const Eina_Model *model, Eina_Model *copy)
1265 {
1266    Eina_List *l, *props = eina_model_properties_names_list_get(model);
1267    const char *name;
1268    EINA_LIST_FOREACH(props, l, name)
1269      {
1270         Eina_Value tmp;
1271         if (!eina_model_property_get(model, name, &tmp))
1272           {
1273              ERR("Could not get property %s from model %p (%s)",
1274                  name, model, model->desc->cache.types[0]->name);
1275              eina_model_properties_names_list_free(props);
1276              return EINA_FALSE;
1277           }
1278         if (!eina_model_property_set(copy, name, &tmp))
1279           {
1280              ERR("Could not set property %s on model %p (%s)",
1281                  name, copy, copy->desc->cache.types[0]->name);
1282              eina_value_flush(&tmp);
1283              eina_model_properties_names_list_free(props);
1284              return EINA_FALSE;
1285           }
1286         eina_value_flush(&tmp);
1287      }
1288    eina_model_properties_names_list_free(props);
1289    return EINA_TRUE;
1290 }
1291
1292 static Eina_Bool
1293 _eina_model_type_base_children_copy(const Eina_Model *model, Eina_Model *copy)
1294 {
1295    int i, count = eina_model_child_count(model);
1296
1297    if (count < 0)
1298      {
1299         ERR("Could not get children count of model %p (%s)",
1300             model, model->desc->cache.types[0]->name);
1301         return EINA_FALSE;
1302      }
1303
1304    for (i = 0; i < count; i++)
1305      {
1306         Eina_Model *child = eina_model_child_get(model, i);
1307         Eina_Bool ret;
1308
1309         if (!child)
1310           {
1311              ERR("Could not get child #%d from model %p (%s)",
1312                  i, model, model->desc->cache.types[0]->name);
1313              return EINA_FALSE;
1314           }
1315
1316         ret = eina_model_child_insert_at(copy, i, child);
1317         _eina_model_unref(child);
1318
1319         if (!ret)
1320           {
1321              ERR("Could not set child #%d on model %p (%s)",
1322                  i, copy, copy->desc->cache.types[0]->name);
1323              return EINA_FALSE;
1324           }
1325      }
1326
1327    return EINA_TRUE;
1328 }
1329
1330 static Eina_Bool
1331 _eina_model_type_base_copy(const Eina_Model *model, Eina_Model *copy)
1332 {
1333    DBG("base copy of %p to %p", model, copy);
1334
1335    return _eina_model_type_base_properties_copy(model, copy) &&
1336      _eina_model_type_base_children_copy(model, copy);
1337 }
1338
1339 static Eina_Bool
1340 _eina_model_type_base_children_deep_copy(const Eina_Model *model, Eina_Model *copy)
1341 {
1342    int i, count = eina_model_child_count(model);
1343
1344    if (count < 0)
1345      {
1346         ERR("Could not get children count of model %p (%s)",
1347             model, model->desc->cache.types[0]->name);
1348         return EINA_FALSE;
1349      }
1350
1351    for (i = 0; i < count; i++)
1352      {
1353         Eina_Model *child_copy, *child = eina_model_child_get(model, i);
1354         Eina_Bool ret;
1355
1356         if (!child)
1357           {
1358              ERR("Could not get child #%d from model %p (%s)",
1359                  i, model, model->desc->cache.types[0]->name);
1360              return EINA_FALSE;
1361           }
1362
1363         child_copy = eina_model_deep_copy(child);
1364         if (!child_copy)
1365           {
1366              ERR("Could not deep copy child #%d %p (%s) from model %p (%s)", i,
1367                  child, child->desc->cache.types[0]->name,
1368                  model, model->desc->cache.types[0]->name);
1369              _eina_model_unref(child);
1370              return EINA_FALSE;
1371           }
1372         _eina_model_unref(child);
1373
1374         ret = eina_model_child_insert_at(copy, i, child_copy);
1375         _eina_model_unref(child_copy);
1376
1377         if (!ret)
1378           {
1379              ERR("Could not set child #%d on model %p (%s)",
1380                  i, copy, copy->desc->cache.types[0]->name);
1381              return EINA_FALSE;
1382           }
1383      }
1384
1385    return EINA_TRUE;
1386 }
1387
1388 static Eina_Bool
1389 _eina_model_type_base_deep_copy(const Eina_Model *model, Eina_Model *copy)
1390 {
1391    DBG("base deep copy of %p to %p", model, copy);
1392
1393    return _eina_model_type_base_properties_copy(model, copy) &&
1394      _eina_model_type_base_children_deep_copy(model, copy);
1395 }
1396
1397 static Eina_Bool
1398 _eina_model_type_base_properties_compare(const Eina_Model *a, const Eina_Model *b, int *cmp)
1399 {
1400    Eina_List *al, *aprops = eina_model_properties_names_list_get(a);
1401    Eina_List *bl, *bprops = eina_model_properties_names_list_get(b);
1402    Eina_List *l, *props = NULL;
1403    const char *aname, *bname, *name;
1404    Eina_Bool ret = EINA_TRUE;
1405
1406    EINA_LIST_FOREACH(aprops, al, aname)
1407      {
1408         EINA_LIST_FOREACH(bprops, bl, bname)
1409           if (strcmp(aname, bname) == 0)
1410             {
1411                props = eina_list_append(props, aname);
1412                break;
1413             }
1414      }
1415
1416    *cmp = 0;
1417    EINA_LIST_FOREACH(props, l, name)
1418      {
1419         Eina_Value atmp, btmp;
1420
1421         if (!eina_model_property_get(a, name, &atmp))
1422           {
1423              ERR("Could not get property %s from model %p (%s)",
1424                  name, a, a->desc->cache.types[0]->name);
1425              ret = EINA_FALSE;
1426              *cmp = -1;
1427              break;
1428           }
1429
1430         if (!eina_model_property_get(b, name, &btmp))
1431           {
1432              ERR("Could not get property %s from model %p (%s)",
1433                  name, b, b->desc->cache.types[0]->name);
1434              ret = EINA_FALSE;
1435              *cmp = -1;
1436              eina_value_flush(&atmp);
1437              break;
1438           }
1439
1440         *cmp = eina_value_compare(&atmp, &btmp);
1441         if (eina_error_get() != 0)
1442           {
1443              char *astr = eina_value_to_string(&atmp);
1444              char *bstr = eina_value_to_string(&btmp);
1445              ERR("Could not compare property %s: %s=%s, %s=%s", name,
1446                  eina_value_type_name_get(eina_value_type_get(&atmp)), astr,
1447                  eina_value_type_name_get(eina_value_type_get(&btmp)), bstr);
1448              free(astr);
1449              free(bstr);
1450              ret = EINA_FALSE;
1451              *cmp = -1;
1452           }
1453
1454         eina_value_flush(&atmp);
1455         eina_value_flush(&btmp);
1456
1457         if ((!ret) || (*cmp != 0))
1458           break;
1459      }
1460
1461    if ((ret) && (*cmp == 0))
1462      {
1463         int acount = eina_list_count(aprops);
1464         int bcount = eina_list_count(bprops);
1465
1466         if (acount < bcount)
1467           *cmp = -1;
1468         else if (acount > bcount)
1469           *cmp = 1;
1470      }
1471
1472    eina_model_properties_names_list_free(aprops);
1473    eina_model_properties_names_list_free(bprops);
1474    eina_list_free(props);
1475    return ret;
1476 }
1477
1478 static Eina_Bool
1479 _eina_model_type_base_children_compare(const Eina_Model *a, const Eina_Model *b, int *cmp)
1480 {
1481    int acount = eina_model_child_count(a);
1482    int bcount = eina_model_child_count(b);
1483    int i, count;
1484    Eina_Bool ret = EINA_TRUE;
1485
1486    if (acount < 0)
1487      {
1488         ERR("Could not get children count of model %p (%s)",
1489             a, a->desc->cache.types[0]->name);
1490         return EINA_FALSE;
1491      }
1492    if (bcount < 0)
1493      {
1494         ERR("Could not get children count of model %p (%s)",
1495             b, b->desc->cache.types[0]->name);
1496         return EINA_FALSE;
1497      }
1498
1499    if (acount < bcount)
1500      count = acount;
1501    else
1502      count = bcount;
1503
1504    for (i = 0; i < count; i++)
1505      {
1506         Eina_Model *achild, *bchild;
1507
1508         achild = eina_model_child_get(a, i);
1509         if (!achild)
1510           {
1511              ERR("Could not get child #%d from model %p (%s)",
1512                  i, a, a->desc->cache.types[0]->name);
1513              *cmp = -1;
1514              return EINA_FALSE;
1515           }
1516
1517         bchild = eina_model_child_get(b, i);
1518         if (!bchild)
1519           {
1520              ERR("Could not get child #%d from model %p (%s)",
1521                  i, b, b->desc->cache.types[0]->name);
1522              *cmp = -1;
1523              _eina_model_unref(achild);
1524              return EINA_FALSE;
1525           }
1526
1527         *cmp = eina_model_compare(achild, bchild);
1528         if (eina_error_get())
1529           {
1530              ERR("Could not compare children #%d %p (%s) and %p (%s) "
1531                  "from models %p (%s) and %p (%s)", i,
1532                  achild,
1533                  eina_model_type_name_get(eina_model_type_get(achild)),
1534                  bchild,
1535                  eina_model_type_name_get(eina_model_type_get(bchild)),
1536                  a, a->desc->cache.types[0]->name,
1537                  b, b->desc->cache.types[0]->name);
1538              ret = EINA_FALSE;
1539           }
1540         _eina_model_unref(achild);
1541         _eina_model_unref(bchild);
1542
1543         if ((!ret) || (*cmp != 0))
1544           break;
1545      }
1546
1547    if ((ret) && (*cmp == 0))
1548      {
1549         if (acount < bcount)
1550           *cmp = -1;
1551         else if (acount > bcount)
1552           *cmp = 1;
1553      }
1554
1555    return ret;
1556 }
1557
1558 static Eina_Bool
1559 _eina_model_type_base_compare(const Eina_Model *a, const Eina_Model *b, int *cmp)
1560 {
1561    *cmp = 0;
1562    DBG("base compare of %p and %p", a, b);
1563
1564    if (!_eina_model_type_base_properties_compare(a, b, cmp))
1565      return EINA_FALSE;
1566
1567    if (*cmp != 0)
1568      return EINA_TRUE;
1569
1570    return _eina_model_type_base_children_compare(a, b, cmp);
1571 }
1572
1573 static int
1574 _eina_model_type_base_child_count(const Eina_Model *model)
1575 {
1576    DBG("base child_count of %p", model);
1577    return 0;
1578 }
1579
1580 static int
1581 _eina_model_type_base_child_find(const Eina_Model *model, unsigned int start_position, const Eina_Model *other)
1582 {
1583    int x = eina_model_child_count(model);
1584    unsigned int i, count;
1585
1586    DBG("base child_find of %p, %d children", model, x);
1587
1588    if (x < 0)
1589      return -1;
1590
1591    count = x;
1592    for (i = start_position; i < count; i++)
1593      {
1594         Eina_Model *current = eina_model_child_get(model, i);
1595         if (current)
1596           {
1597              _eina_model_unref(current); /* we'll not use it's value anyway */
1598              if (current == other)
1599                return i;
1600           }
1601      }
1602
1603    return -1;
1604 }
1605
1606 static int
1607 _eina_model_type_base_child_criteria_match(const Eina_Model *model, unsigned int start_position, Eina_Each_Cb match, const void *user_data)
1608 {
1609    int x = eina_model_child_count(model);
1610    unsigned int i, count;
1611
1612    DBG("base child_criteria_match of %p, %d children", model, x);
1613
1614    if (x < 0)
1615      return -1;
1616
1617    count = x;
1618    for (i = start_position; i < count; i++)
1619      {
1620         Eina_Model *current = eina_model_child_get(model, i);
1621         if (current)
1622           {
1623              Eina_Bool r = match(model, current, (void *)user_data);
1624              _eina_model_unref(current);
1625              if (r)
1626                return i;
1627           }
1628      }
1629
1630    return -1;
1631 }
1632
1633 typedef struct _Eina_Iterator_Model_Base Eina_Iterator_Model_Base;
1634 struct _Eina_Iterator_Model_Base
1635 {
1636    Eina_Iterator base;
1637    Eina_Model *model;
1638    unsigned int current;
1639    unsigned int end;
1640 };
1641
1642 static Eina_Bool
1643 _eina_model_type_base_child_iterator_next(Eina_Iterator *base, void **data)
1644 {
1645    Eina_Iterator_Model_Base *it;
1646
1647    it = (Eina_Iterator_Model_Base *)base;
1648    if (it->current >= it->end)
1649      return EINA_FALSE;
1650
1651    *data = eina_model_child_get(it->model, it->current);
1652    if (!*data)
1653      return EINA_FALSE;
1654
1655    it->current++;
1656    return EINA_TRUE;
1657 }
1658
1659 static void *
1660 _eina_model_type_base_child_iterator_get_container(Eina_Iterator *base)
1661 {
1662    Eina_Iterator_Model_Base *it;
1663    it = (Eina_Iterator_Model_Base *)base;
1664    return it->model;
1665 }
1666
1667 static void
1668 _eina_model_type_base_child_iterator_free(Eina_Iterator *base)
1669 {
1670    Eina_Iterator_Model_Base *it;
1671    it = (Eina_Iterator_Model_Base *)base;
1672    eina_model_xunref(it->model, it);
1673    free(it);
1674 }
1675
1676 static Eina_Iterator *
1677 _eina_model_type_base_child_iterator_get(Eina_Model *model, unsigned int start, unsigned int count)
1678 {
1679    Eina_Iterator_Model_Base *it = calloc(1, sizeof(*it));
1680    EINA_SAFETY_ON_NULL_RETURN_VAL(it, NULL);
1681
1682    EINA_MAGIC_SET(&it->base, EINA_MAGIC_ITERATOR);
1683    it->base.version = EINA_ITERATOR_VERSION;
1684    it->base.next = _eina_model_type_base_child_iterator_next;
1685    it->base.get_container = _eina_model_type_base_child_iterator_get_container;
1686    it->base.free = _eina_model_type_base_child_iterator_free;
1687
1688    it->model = eina_model_xref(model, it, "eina_model_child_slice_iterator_get");
1689    it->current = start;
1690    it->end = start + count;
1691
1692    return &it->base;
1693 }
1694
1695 typedef struct _Eina_Iterator_Model_Base_Reversed Eina_Iterator_Model_Base_Reversed;
1696 struct _Eina_Iterator_Model_Base_Reversed
1697 {
1698    Eina_Iterator base;
1699    Eina_Model *model;
1700    unsigned int current;
1701    unsigned int end;
1702 };
1703
1704 static Eina_Bool
1705 _eina_model_type_base_child_reversed_iterator_next(Eina_Iterator *base, void **data)
1706 {
1707    Eina_Iterator_Model_Base_Reversed *it;
1708
1709    it = (Eina_Iterator_Model_Base_Reversed *)base;
1710    if (it->current == it->end)
1711      return EINA_FALSE;
1712
1713    it->current--;
1714    *data = eina_model_child_get(it->model, it->current);
1715    if (!*data)
1716      return EINA_FALSE;
1717
1718    return EINA_TRUE;
1719 }
1720
1721 static void *
1722 _eina_model_type_base_child_reversed_iterator_get_container(Eina_Iterator *base)
1723 {
1724    Eina_Iterator_Model_Base_Reversed *it;
1725    it = (Eina_Iterator_Model_Base_Reversed *)base;
1726    return it->model;
1727 }
1728
1729 static void
1730 _eina_model_type_base_child_reversed_iterator_free(Eina_Iterator *base)
1731 {
1732    Eina_Iterator_Model_Base_Reversed *it;
1733    it = (Eina_Iterator_Model_Base_Reversed *)base;
1734    eina_model_xunref(it->model, it);
1735    free(it);
1736 }
1737
1738 static Eina_Iterator *
1739 _eina_model_type_base_child_reversed_iterator_get(Eina_Model *model, unsigned int start, unsigned int count)
1740 {
1741    Eina_Iterator_Model_Base_Reversed *it;
1742    int children_count;
1743
1744    children_count = eina_model_child_count(model);
1745    if (children_count < 0)
1746      return NULL;
1747
1748    if (start + count > (unsigned int)children_count)
1749      {
1750         if (start >= (unsigned int)children_count)
1751           count = 0;
1752         else
1753           count = children_count - start;
1754      }
1755
1756    it = calloc(1, sizeof(*it));
1757    EINA_SAFETY_ON_NULL_RETURN_VAL(it, NULL);
1758    EINA_MAGIC_SET(&it->base, EINA_MAGIC_ITERATOR);
1759    it->base.version = EINA_ITERATOR_VERSION;
1760    it->base.next = _eina_model_type_base_child_reversed_iterator_next;
1761    it->base.get_container = _eina_model_type_base_child_reversed_iterator_get_container;
1762    it->base.free = _eina_model_type_base_child_reversed_iterator_free;
1763
1764    it->model = eina_model_xref(model, it, "eina_model_child_slice_reversed_iterator_get");
1765    it->current = start + count;
1766    it->end = start;
1767
1768    return &it->base;
1769 }
1770
1771 typedef struct _Eina_Iterator_Model_Base_Sorted Eina_Iterator_Model_Base_Sorted;
1772 struct _Eina_Iterator_Model_Base_Sorted
1773 {
1774    Eina_Iterator base;
1775    Eina_Model *model;
1776    unsigned int current;
1777    unsigned int count;
1778    Eina_Model *elements[];
1779 };
1780
1781 static Eina_Bool
1782 _eina_model_type_base_child_sorted_iterator_next(Eina_Iterator *base, void **data)
1783 {
1784    Eina_Iterator_Model_Base_Sorted *it;
1785
1786    it = (Eina_Iterator_Model_Base_Sorted *)base;
1787    if (it->current == it->count)
1788      return EINA_FALSE;
1789
1790    *data = eina_model_ref(it->elements[it->current]);
1791    it->current++;
1792    return EINA_TRUE;
1793 }
1794
1795 static void *
1796 _eina_model_type_base_child_sorted_iterator_get_container(Eina_Iterator *base)
1797 {
1798    Eina_Iterator_Model_Base_Sorted *it;
1799    it = (Eina_Iterator_Model_Base_Sorted *)base;
1800    return it->model;
1801 }
1802
1803 static void
1804 _eina_model_type_base_child_sorted_iterator_free(Eina_Iterator *base)
1805 {
1806    Eina_Iterator_Model_Base_Sorted *it;
1807    unsigned int i;
1808    it = (Eina_Iterator_Model_Base_Sorted *)base;
1809    eina_model_xunref(it->model, it);
1810
1811    for (i = 0; i < it->count; i++)
1812      _eina_model_unref(it->elements[i]);
1813
1814    free(it);
1815 }
1816
1817 static Eina_Iterator *
1818 _eina_model_type_base_child_sorted_iterator_get(Eina_Model *model, unsigned int start, unsigned int count, Eina_Compare_Cb compare)
1819 {
1820    Eina_Iterator_Model_Base_Sorted *it;
1821    int children_count;
1822    unsigned int i;
1823
1824    children_count = eina_model_child_count(model);
1825    if (children_count < 0)
1826      return NULL;
1827
1828    if (start + count > (unsigned int)children_count)
1829      {
1830         if (start >= (unsigned int)children_count)
1831           count = 0;
1832         else
1833           count = children_count - start;
1834      }
1835
1836    it = calloc(1, sizeof(*it) + count * sizeof(Eina_Model *));
1837    EINA_SAFETY_ON_NULL_RETURN_VAL(it, NULL);
1838    EINA_MAGIC_SET(&it->base, EINA_MAGIC_ITERATOR);
1839    it->base.version = EINA_ITERATOR_VERSION;
1840    it->base.next = _eina_model_type_base_child_sorted_iterator_next;
1841    it->base.get_container = _eina_model_type_base_child_sorted_iterator_get_container;
1842    it->base.free = _eina_model_type_base_child_sorted_iterator_free;
1843
1844    it->model = eina_model_xref(model, it, "eina_model_child_slice_sorted_iterator_get");
1845    it->current = 0;
1846    it->count = count;
1847
1848    for (i = 0; i < count; i++)
1849      {
1850         it->elements[i] = eina_model_child_get(model, i + start);
1851         if (!it->elements[i])
1852           {
1853              ERR("Failed to get child %u of model %p (%s)",
1854                  i + start, model, model->desc->cache.types[0]->name);
1855              free(it);
1856              return NULL;
1857           }
1858      }
1859
1860    if (count > 1)
1861      _eina_model_array_sort(it->elements, 0, count - 1, compare);
1862
1863    return &it->base;
1864 }
1865
1866 typedef struct _Eina_Iterator_Model_Base_Filtered Eina_Iterator_Model_Base_Filtered;
1867 struct _Eina_Iterator_Model_Base_Filtered
1868 {
1869    Eina_Iterator base;
1870    Eina_Model *model;
1871    Eina_Each_Cb match;
1872    const void *data;
1873    unsigned int current;
1874    unsigned int count;
1875 };
1876
1877 static Eina_Bool
1878 _eina_model_type_base_child_filtered_iterator_next(Eina_Iterator *base, void **data)
1879 {
1880    Eina_Iterator_Model_Base_Filtered *it;
1881    unsigned int *ret;
1882    int i;
1883
1884    it = (Eina_Iterator_Model_Base_Filtered *)base;
1885    if (it->count == 0) return EINA_FALSE;
1886
1887    i = eina_model_child_criteria_match(it->model, it->current, it->match, it->data);
1888    if (i < 0) return EINA_FALSE;
1889
1890    it->current = i + 1;
1891    it->count--;
1892    ret = (unsigned int *)data;
1893    *ret = i;
1894    return EINA_TRUE;
1895 }
1896
1897 static void *
1898 _eina_model_type_base_child_filtered_iterator_get_container(Eina_Iterator *base)
1899 {
1900    Eina_Iterator_Model_Base_Filtered *it;
1901    it = (Eina_Iterator_Model_Base_Filtered *)base;
1902    return it->model;
1903 }
1904
1905 static void
1906 _eina_model_type_base_child_filtered_iterator_free(Eina_Iterator *base)
1907 {
1908    Eina_Iterator_Model_Base_Filtered *it;
1909    it = (Eina_Iterator_Model_Base_Filtered *)base;
1910    eina_model_xunref(it->model, it);
1911    free(it);
1912 }
1913
1914 static Eina_Iterator *
1915 _eina_model_type_base_child_filtered_iterator_get(Eina_Model *model, unsigned int start, unsigned int count, Eina_Each_Cb match, const void *data)
1916 {
1917    Eina_Iterator_Model_Base_Filtered *it = calloc(1, sizeof(*it));
1918    EINA_SAFETY_ON_NULL_RETURN_VAL(it, NULL);
1919
1920    EINA_MAGIC_SET(&it->base, EINA_MAGIC_ITERATOR);
1921    it->base.version = EINA_ITERATOR_VERSION;
1922    it->base.next = _eina_model_type_base_child_filtered_iterator_next;
1923    it->base.get_container = _eina_model_type_base_child_filtered_iterator_get_container;
1924    it->base.free = _eina_model_type_base_child_filtered_iterator_free;
1925
1926    it->model = eina_model_xref(model, it, "eina_model_child_slice_filtered_iterator_get");
1927    it->match = match;
1928    it->data = data;
1929    it->current = start;
1930    it->count = count;
1931
1932    return &it->base;
1933 }
1934
1935 static char *
1936 _eina_model_type_base_to_string(const Eina_Model *model)
1937 {
1938    Eina_List *l, *props;
1939    const char *name;
1940    Eina_Strbuf *str;
1941    Eina_Bool first;
1942    int i, count;
1943    char *ret;
1944
1945    str = eina_strbuf_new();
1946    EINA_SAFETY_ON_NULL_RETURN_VAL(str, NULL);
1947
1948    eina_strbuf_append_printf(str, "%s({", model->desc->cache.types[0]->name);
1949
1950    props = eina_model_properties_names_list_get(model);
1951    props = eina_list_sort(props, 0, EINA_COMPARE_CB(strcmp));
1952
1953    first = EINA_TRUE;
1954    EINA_LIST_FOREACH(props, l, name)
1955      {
1956         Eina_Value val;
1957
1958         if (!first)
1959           eina_strbuf_append_printf(str, ", %s: ", name);
1960         else
1961           {
1962              eina_strbuf_append_printf(str, "%s: ", name);
1963              first = EINA_FALSE;
1964           }
1965
1966         if (!eina_model_property_get(model, name, &val))
1967           eina_strbuf_append_char(str, '?');
1968         else
1969           {
1970              char *tmp = eina_value_to_string(&val);
1971              eina_strbuf_append(str, tmp ? tmp : "?");
1972              free(tmp);
1973              eina_value_flush(&val);
1974           }
1975      }
1976    eina_list_free(props);
1977
1978    eina_strbuf_append(str, "}, [");
1979
1980    count = eina_model_child_count(model);
1981    first = EINA_TRUE;
1982    for (i = 0; i < count; i++)
1983      {
1984         Eina_Model *c = eina_model_child_get(model, i);
1985         if (!c)
1986           {
1987              if (!first)
1988                eina_strbuf_append(str, ", ?");
1989              else
1990                {
1991                   eina_strbuf_append_char(str, '?');
1992                   first = EINA_FALSE;
1993                }
1994           }
1995         else
1996           {
1997              char *tmp = eina_model_to_string(c);
1998              if (!first)
1999                eina_strbuf_append_printf(str, ", %s", tmp ? tmp : "?");
2000              else
2001                {
2002                   eina_strbuf_append(str, tmp ? tmp : "?");
2003                   first = EINA_FALSE;
2004                }
2005              free(tmp);
2006              _eina_model_unref(c);
2007           }
2008      }
2009
2010    eina_strbuf_append(str, "])");
2011
2012    ret = eina_strbuf_string_steal(str);
2013    eina_strbuf_free(str);
2014
2015    return ret;
2016 }
2017
2018 static const Eina_Model_Event_Description _eina_model_type_base_events[] = {
2019   EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_deleted, "", "model was deleted"),
2020   EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_freed, "", "model memory was released"),
2021   EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_property_set, "s", "model data was set, data name given as event information."),
2022   EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_property_del, "s", "model data was deleted, data name given as event information."),
2023   EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_children_changed, "", "model children changed (deleted, inserted)."),
2024   EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_child_inserted, "u", "model child was inserted, child position is given."),
2025   EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_child_set, "u", "model child was set, child position is given."),
2026   EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_child_del, "u", "model child was deleted, child position is given."),
2027   EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_loaded, "", "model was loaded"),
2028   EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_unloaded, "", "model was unloaded"),
2029   EINA_MODEL_EVENT_DESCRIPTION_SENTINEL
2030 };
2031
2032 static const Eina_Model_Type _EINA_MODEL_TYPE_BASE = {
2033   EINA_MODEL_TYPE_VERSION,
2034   0, /* there is no private data */
2035   sizeof(Eina_Model_Type),
2036   "Eina_Model_Type_Base",
2037   NULL, /* should be the only type with NULL here! */
2038   NULL, /* no interfaces implemented */
2039   _eina_model_type_base_events,
2040   _eina_model_type_base_setup,
2041   _eina_model_type_base_flush,
2042   _eina_model_type_base_constructor,
2043   _eina_model_type_base_destructor,
2044   _eina_model_type_base_copy,
2045   _eina_model_type_base_deep_copy,
2046   _eina_model_type_base_compare,
2047   NULL, /* no load */
2048   NULL, /* no unload */
2049   NULL, /* no property value get */
2050   NULL, /* no property value set */
2051   NULL, /* no property del */
2052   NULL, /* no properties names list */
2053   _eina_model_type_base_child_count,
2054   NULL, /* no child get */
2055   NULL, /* no child set */
2056   NULL, /* no child del */
2057   NULL, /* no child insert */
2058   _eina_model_type_base_child_find,
2059   _eina_model_type_base_child_criteria_match,
2060   NULL, /* no child sort */
2061   _eina_model_type_base_child_iterator_get,
2062   _eina_model_type_base_child_reversed_iterator_get,
2063   _eina_model_type_base_child_sorted_iterator_get,
2064   _eina_model_type_base_child_filtered_iterator_get,
2065   _eina_model_type_base_to_string,
2066   NULL, /* extension pointer */
2067   NULL, /* extension pointer */
2068   NULL, /* extension pointer */
2069   NULL  /* extension pointer */
2070 };
2071
2072 /*
2073  * EINA_MODEL_TYPE_MIXIN:
2074  *
2075  * Mix-in is a type that uses 2 interfaces, one for properties,
2076  * another for children. Users should inherit this model and implement
2077  * at least onf of the interfaces to get an usable model without
2078  * defining the methods.
2079  */
2080
2081 static const char _EINA_MODEL_INTERFACE_NAME_PROPERTIES[] = "Eina_Model_Interface_Properties";
2082 static const char _EINA_MODEL_INTERFACE_NAME_CHILDREN[] = "Eina_Model_Interface_Children";
2083
2084 typedef struct _Eina_Model_Type_Mixin_Data Eina_Model_Type_Mixin_Data;
2085 struct _Eina_Model_Type_Mixin_Data
2086 {
2087    /* just keep interfaces to avoid lookups */
2088    const Eina_Model_Interface *if_properties;
2089    const Eina_Model_Interface *if_children;
2090 };
2091
2092 static Eina_Bool
2093 _eina_model_type_mixin_setup(Eina_Model *model)
2094 {
2095    DBG("mix-in setup of %p", model);
2096    return EINA_TRUE;
2097 }
2098
2099 static Eina_Bool
2100 _eina_model_type_mixin_flush(Eina_Model *model)
2101 {
2102    DBG("mix-in flush of %p", model);
2103    return EINA_TRUE;
2104 }
2105
2106 static Eina_Bool
2107 _eina_model_type_mixin_constructor(Eina_Model *model)
2108 {
2109    Eina_Model_Type_Mixin_Data *priv = eina_model_type_private_data_get
2110      (model, EINA_MODEL_TYPE_MIXIN);
2111
2112    DBG("mix-in constructor of %p (priv=%p)", model, priv);
2113
2114    priv->if_properties = eina_model_interface_get
2115      (model, EINA_MODEL_INTERFACE_NAME_PROPERTIES);
2116    if (priv->if_properties)
2117      {
2118         if (!eina_model_interface_constructor(priv->if_properties, model))
2119           {
2120              ERR("Could not construct properties interface %p of %p (%s)",
2121                  model, priv->if_properties, model->desc->cache.types[0]->name);
2122              return EINA_FALSE;
2123           }
2124      }
2125
2126    priv->if_children = eina_model_interface_get
2127      (model, EINA_MODEL_INTERFACE_NAME_CHILDREN);
2128    if (priv->if_children)
2129      {
2130         if (!eina_model_interface_constructor(priv->if_children, model))
2131           {
2132              ERR("Could not construct children interface %p of %p (%s)",
2133                  model, priv->if_children, model->desc->cache.types[0]->name);
2134              return EINA_FALSE;
2135           }
2136      }
2137
2138    if ((!priv->if_properties) && (!priv->if_children))
2139      {
2140         ERR("Mix-in model %p (%s) does not implement properties or children "
2141             "interfaces!",
2142             model, model->desc->cache.types[0]->name);
2143         return EINA_FALSE;
2144      }
2145
2146    return EINA_TRUE;
2147 }
2148
2149 #define EINA_MODEL_TYPE_MIXIN_GET(model)                                \
2150   Eina_Model_Type_Mixin_Data *priv = eina_model_type_private_data_get   \
2151     (model, EINA_MODEL_TYPE_MIXIN)
2152
2153 static Eina_Bool
2154 _eina_model_type_mixin_destructor(Eina_Model *model)
2155 {
2156    EINA_MODEL_TYPE_MIXIN_GET(model);
2157
2158    DBG("mixin destructor of %p", model);
2159
2160    if (priv->if_properties)
2161      eina_model_interface_destructor(priv->if_properties, model);
2162
2163    if (priv->if_children)
2164      eina_model_interface_destructor(priv->if_children, model);
2165
2166    return EINA_TRUE;
2167 }
2168
2169 static Eina_Bool
2170 _eina_model_type_mixin_compare(const Eina_Model *a, const Eina_Model *b, int *cmp)
2171 {
2172    Eina_Bool ret = EINA_TRUE, did_prop = EINA_FALSE, did_child = EINA_FALSE;
2173
2174    *cmp = 0;
2175
2176    EINA_MODEL_TYPE_MIXIN_GET(a);
2177
2178    if (priv->if_properties)
2179      {
2180         Eina_Bool (*compare)(const Eina_Model*, const Eina_Model*, int *) =
2181           _eina_model_interface_find_offset
2182           (priv->if_properties,
2183            offsetof(Eina_Model_Interface_Properties, compare));
2184
2185         if (compare)
2186           {
2187              ret &= compare(a, b, cmp);
2188              did_prop = EINA_TRUE;
2189           }
2190      }
2191
2192    if ((ret) && (*cmp == 0))
2193      {
2194         if (priv->if_children)
2195           {
2196              Eina_Bool (*compare)(const Eina_Model*, const Eina_Model*, int *) =
2197                _eina_model_interface_find_offset
2198                (priv->if_children,
2199                 offsetof(Eina_Model_Interface_Children, compare));
2200
2201              if (compare)
2202                {
2203                   ret &= compare(a, b, cmp);
2204                   did_child = EINA_TRUE;
2205                }
2206           }
2207      }
2208
2209    if ((!did_prop) && (!did_child))
2210      return eina_model_type_compare(EINA_MODEL_TYPE_BASE, a, b, cmp);
2211
2212    return ret;
2213 }
2214
2215 static Eina_Bool
2216 _eina_model_type_mixin_load(Eina_Model *model)
2217 {
2218    Eina_Bool ret = EINA_TRUE;
2219
2220    EINA_MODEL_TYPE_MIXIN_GET(model);
2221
2222    if (priv->if_properties)
2223      ret &= eina_model_interface_properties_load(priv->if_properties, model);
2224
2225    if (priv->if_children)
2226      ret &= eina_model_interface_children_load(priv->if_children, model);
2227
2228    return ret;
2229 }
2230
2231 static Eina_Bool
2232 _eina_model_type_mixin_unload(Eina_Model *model)
2233 {
2234    Eina_Bool ret = EINA_TRUE;
2235
2236    EINA_MODEL_TYPE_MIXIN_GET(model);
2237
2238    if (priv->if_properties)
2239      ret &= eina_model_interface_properties_unload(priv->if_properties, model);
2240
2241    if (priv->if_children)
2242      ret &= eina_model_interface_children_unload(priv->if_children, model);
2243
2244    return ret;
2245 }
2246
2247 static Eina_Bool
2248 _eina_model_type_mixin_property_get(const Eina_Model *model, const char *name, Eina_Value *value)
2249 {
2250    Eina_Bool ret = EINA_FALSE;
2251
2252    EINA_MODEL_TYPE_MIXIN_GET(model);
2253
2254    if (priv->if_properties)
2255      ret = eina_model_interface_properties_get
2256        (priv->if_properties, model, name, value);
2257
2258    return ret;
2259 }
2260
2261 static Eina_Bool
2262 _eina_model_type_mixin_property_set(Eina_Model *model, const char *name, const Eina_Value *value)
2263 {
2264    Eina_Bool ret = EINA_FALSE;
2265
2266    EINA_MODEL_TYPE_MIXIN_GET(model);
2267
2268    if (priv->if_properties)
2269      ret = eina_model_interface_properties_set
2270        (priv->if_properties, model, name, value);
2271
2272    return ret;
2273 }
2274
2275 static Eina_Bool
2276 _eina_model_type_mixin_property_del(Eina_Model *model, const char *name)
2277 {
2278    Eina_Bool ret = EINA_FALSE;
2279
2280    EINA_MODEL_TYPE_MIXIN_GET(model);
2281
2282    if (priv->if_properties)
2283      ret = eina_model_interface_properties_del
2284        (priv->if_properties, model, name);
2285
2286    return ret;
2287 }
2288
2289 static Eina_List *
2290 _eina_model_type_mixin_properties_names_list_get(const Eina_Model *model)
2291 {
2292    Eina_List *ret = NULL;
2293
2294    EINA_MODEL_TYPE_MIXIN_GET(model);
2295
2296    if (priv->if_properties)
2297      ret = eina_model_interface_properties_names_list_get
2298        (priv->if_properties, model);
2299
2300    return ret;
2301 }
2302
2303 static int
2304 _eina_model_type_mixin_child_count(const Eina_Model *model)
2305 {
2306    EINA_MODEL_TYPE_MIXIN_GET(model);
2307
2308    if (!priv->if_children)
2309      return 0;
2310
2311    return eina_model_interface_children_count(priv->if_children, model);
2312 }
2313
2314 static Eina_Model *
2315 _eina_model_type_mixin_child_get(const Eina_Model *model, unsigned int position)
2316 {
2317    EINA_MODEL_TYPE_MIXIN_GET(model);
2318
2319    if (!priv->if_children)
2320      return 0;
2321
2322    return eina_model_interface_children_get(priv->if_children, model, position);
2323 }
2324
2325 static Eina_Bool
2326 _eina_model_type_mixin_child_set(Eina_Model *model, unsigned int position, Eina_Model *child)
2327 {
2328    EINA_MODEL_TYPE_MIXIN_GET(model);
2329
2330    if (!priv->if_children)
2331      return 0;
2332
2333    return eina_model_interface_children_set
2334      (priv->if_children, model, position, child);
2335 }
2336
2337 static Eina_Bool
2338 _eina_model_type_mixin_child_del(Eina_Model *model, unsigned int position)
2339 {
2340    EINA_MODEL_TYPE_MIXIN_GET(model);
2341
2342    if (!priv->if_children)
2343      return 0;
2344
2345    return eina_model_interface_children_del
2346      (priv->if_children, model, position);
2347 }
2348
2349 static Eina_Bool
2350 _eina_model_type_mixin_child_insert_at(Eina_Model *model, unsigned int position, Eina_Model *child)
2351 {
2352    EINA_MODEL_TYPE_MIXIN_GET(model);
2353
2354    if (!priv->if_children)
2355      return 0;
2356
2357    return eina_model_interface_children_insert_at
2358      (priv->if_children, model, position, child);
2359 }
2360
2361 static void
2362 _eina_model_type_mixin_child_sort(Eina_Model *model, Eina_Compare_Cb compare)
2363 {
2364    EINA_MODEL_TYPE_MIXIN_GET(model);
2365
2366    if (!priv->if_children)
2367      return;
2368    eina_model_interface_children_sort(priv->if_children, model, compare);
2369 }
2370
2371 static const Eina_Model_Type _EINA_MODEL_TYPE_MIXIN = {
2372   EINA_MODEL_TYPE_VERSION,
2373   sizeof(Eina_Model_Type_Mixin_Data),
2374   sizeof(Eina_Model_Type),
2375   "Eina_Model_Type_Mixin",
2376   &_EINA_MODEL_TYPE_BASE,
2377   NULL, /* no interfaces implemented */
2378   NULL, /* no extra events */
2379   _eina_model_type_mixin_setup,
2380   _eina_model_type_mixin_flush,
2381   _eina_model_type_mixin_constructor,
2382   _eina_model_type_mixin_destructor,
2383   NULL, /* no copy, as interface is called automatically */
2384   NULL, /* no deep copy, as interface is called automatically */
2385   _eina_model_type_mixin_compare,
2386   _eina_model_type_mixin_load,
2387   _eina_model_type_mixin_unload,
2388   _eina_model_type_mixin_property_get,
2389   _eina_model_type_mixin_property_set,
2390   _eina_model_type_mixin_property_del,
2391   _eina_model_type_mixin_properties_names_list_get,
2392   _eina_model_type_mixin_child_count,
2393   _eina_model_type_mixin_child_get,
2394   _eina_model_type_mixin_child_set,
2395   _eina_model_type_mixin_child_del,
2396   _eina_model_type_mixin_child_insert_at,
2397   NULL, /* use default find */
2398   NULL, /* use default criteria_match */
2399   _eina_model_type_mixin_child_sort,
2400   NULL, /* use default iterator get */
2401   NULL, /* use default reversed iterator get */
2402   NULL, /* use default sorted iterator get */
2403   NULL, /* use default filtered iterator get */
2404   NULL, /* use default to string */
2405   NULL, /* extension pointer */
2406   NULL, /* extension pointer */
2407   NULL, /* extension pointer */
2408   NULL  /* extension pointer */
2409 };
2410 #undef EINA_MODEL_TYPE_MIXIN_GET
2411
2412 /* Events for all Properties interface */
2413 static const Eina_Model_Event_Description _eina_model_interface_properties_events[] = {
2414   EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_properties_loaded, "", "model properties were loaded"),
2415   EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_properties_unloaded, "", "model properties were unloaded"),
2416   EINA_MODEL_EVENT_DESCRIPTION_SENTINEL
2417 };
2418
2419 /* EINA_MODEL_INTERFACE_PROPERTIES_HASH ******************************/
2420
2421 #define EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model)                 \
2422   Eina_Hash *priv = *(Eina_Hash **)eina_model_interface_private_data_get \
2423     (model, EINA_MODEL_INTERFACE_PROPERTIES_HASH)
2424
2425 static Eina_Bool
2426 _eina_model_interface_properties_hash_setup(Eina_Model *model)
2427 {
2428    Eina_Hash **p_priv = eina_model_interface_private_data_get
2429      (model, EINA_MODEL_INTERFACE_PROPERTIES_HASH);
2430
2431    DBG("setup interface properties (hash) at %p model %p (%s)",
2432        p_priv, model, model->desc->cache.types[0]->name);
2433
2434    *p_priv = eina_hash_string_small_new(NULL);
2435    return !!*p_priv;
2436 }
2437
2438 static Eina_Bool
2439 _eina_model_interface_properties_hash_flush(Eina_Model *model)
2440 {
2441    EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model);
2442
2443    DBG("flush interface properties (hash) at %p model %p (%s)",
2444        priv, model, model->desc->cache.types[0]->name);
2445
2446    if (priv)
2447      {
2448         ERR("interface properties flushed with values! priv=%p, model %p (%s)",
2449             priv, model, model->desc->cache.types[0]->name);
2450         eina_hash_free(priv);
2451      }
2452
2453    return EINA_TRUE;
2454 }
2455
2456 static Eina_Bool
2457 _eina_model_interface_properties_hash_constructor(Eina_Model *model)
2458 {
2459    EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model);
2460
2461    DBG("construct interface properties (hash) at %p model %p (%s)",
2462        priv, model, model->desc->cache.types[0]->name);
2463
2464    return EINA_TRUE;
2465 }
2466
2467 static Eina_Bool
2468 _eina_model_interface_properties_hash_destructor_foreach(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *data, void *fdata __UNUSED__)
2469 {
2470    eina_value_free(data);
2471    return EINA_TRUE;
2472 }
2473
2474 static Eina_Bool
2475 _eina_model_interface_properties_hash_destructor(Eina_Model *model)
2476 {
2477    Eina_Hash **p_priv = eina_model_interface_private_data_get
2478      (model, EINA_MODEL_INTERFACE_PROPERTIES_HASH);
2479    int count = eina_hash_population(*p_priv);
2480
2481    DBG("destroy interface properties (hash) at %p model %p (%s). %d values.",
2482        *p_priv, model, model->desc->cache.types[0]->name, count);
2483
2484    eina_hash_foreach
2485      (*p_priv, _eina_model_interface_properties_hash_destructor_foreach, NULL);
2486    eina_hash_free(*p_priv);
2487    *p_priv = NULL;
2488
2489    return EINA_TRUE;
2490 }
2491
2492 static Eina_Bool
2493 _eina_model_interface_properties_hash_get(const Eina_Model *model, const char *name, Eina_Value *value)
2494 {
2495    EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model);
2496    const Eina_Value *prop = eina_hash_find(priv, name);
2497    EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE);
2498    return eina_value_copy(prop, value);
2499 }
2500
2501 static Eina_Bool
2502 _eina_model_interface_properties_hash_set(Eina_Model *model, const char *name, const Eina_Value *value)
2503 {
2504    EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model);
2505    Eina_Value *prop, *old = eina_hash_find(priv, name);
2506
2507    prop = eina_value_new(eina_value_type_get(value));
2508    EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE);
2509
2510    eina_value_flush(prop);
2511    if (!eina_value_copy(value, prop))
2512      {
2513         ERR("Could not copy value '%s' from %p to %p", name, value, prop);
2514         eina_value_free(prop);
2515         return EINA_FALSE;
2516      }
2517
2518    if (!old)
2519      {
2520         if (!eina_hash_add(priv, name, prop))
2521           {
2522              ERR("Could not add value %p to hash as key '%s'", prop, name);
2523              eina_value_free(prop);
2524              return EINA_FALSE;
2525           }
2526      }
2527    else
2528      {
2529         eina_value_free(old);
2530         if (!eina_hash_modify(priv, name, prop))
2531           {
2532              ERR("Could not modify hash key '%s' value from %p to %p",
2533                  name, old, prop);
2534              eina_hash_del_by_key(priv, name);
2535              eina_value_free(prop);
2536              return EINA_FALSE;
2537           }
2538      }
2539
2540    return EINA_TRUE;
2541 }
2542
2543 static Eina_Bool
2544 _eina_model_interface_properties_hash_del(Eina_Model *model, const char *name)
2545 {
2546    EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model);
2547    Eina_Value *old = eina_hash_find(priv, name);
2548    EINA_SAFETY_ON_NULL_RETURN_VAL(old, EINA_FALSE);
2549    eina_value_free(old);
2550    return eina_hash_del_by_key(priv, name);
2551 }
2552
2553 static Eina_Bool
2554 _eina_model_interface_properties_hash_names_list_foreach(const Eina_Hash *hash __UNUSED__, const void *key, void *data __UNUSED__, void *fdata)
2555 {
2556    Eina_List **p_list = fdata;
2557    *p_list = eina_list_append(*p_list, eina_stringshare_add(key));
2558    return EINA_TRUE;
2559 }
2560
2561 static Eina_List *
2562 _eina_model_interface_properties_hash_names_list(const Eina_Model *model)
2563 {
2564    EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model);
2565    Eina_List *list = NULL;
2566    eina_hash_foreach
2567      (priv, _eina_model_interface_properties_hash_names_list_foreach, &list);
2568    return list;
2569 }
2570 #undef EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET
2571
2572 static const Eina_Model_Interface_Properties _EINA_MODEL_INTERFACE_PROPERTIES_HASH = {
2573   {
2574     EINA_MODEL_INTERFACE_VERSION,
2575     sizeof(Eina_Hash *),
2576     sizeof(Eina_Model_Interface_Properties),
2577     _EINA_MODEL_INTERFACE_NAME_PROPERTIES,
2578     NULL, /* no parent interfaces */
2579     _eina_model_interface_properties_events,
2580     _eina_model_interface_properties_hash_setup,
2581     _eina_model_interface_properties_hash_flush,
2582     _eina_model_interface_properties_hash_constructor,
2583     _eina_model_interface_properties_hash_destructor,
2584     NULL,
2585     NULL,
2586     NULL,
2587     NULL,
2588     NULL,
2589     NULL
2590   },
2591   EINA_MODEL_INTERFACE_PROPERTIES_VERSION,
2592   NULL, /* no compare */
2593   NULL, /* no load */
2594   NULL, /* no unload */
2595   _eina_model_interface_properties_hash_get,
2596   _eina_model_interface_properties_hash_set,
2597   _eina_model_interface_properties_hash_del,
2598   _eina_model_interface_properties_hash_names_list
2599 };
2600
2601 /* EINA_MODEL_INTERFACE_PROPERTIES_STRUCT ******************************/
2602
2603 static Eina_Value_Struct *
2604 _eina_model_interface_properties_struct_private_get(const Eina_Model *model)
2605 {
2606    Eina_Value *val = eina_model_interface_private_data_get
2607      (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT);
2608    return eina_value_memory_get(val);
2609 }
2610
2611 #define EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_GET(model)         \
2612   Eina_Value_Struct *priv =                                       \
2613     _eina_model_interface_properties_struct_private_get(model)
2614
2615 static Eina_Bool
2616 _eina_model_interface_properties_struct_setup(Eina_Model *model)
2617 {
2618    Eina_Value *val = eina_model_interface_private_data_get
2619      (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT);
2620
2621    DBG("setup interface properties (struct) at %p model %p (%s)",
2622        val, model, model->desc->cache.types[0]->name);
2623
2624    return eina_value_setup(val, EINA_VALUE_TYPE_STRUCT);
2625 }
2626
2627 static Eina_Bool
2628 _eina_model_interface_properties_struct_flush(Eina_Model *model)
2629 {
2630    Eina_Value *val = eina_model_interface_private_data_get
2631      (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT);
2632
2633    DBG("flush interface properties (struct) at %p model %p (%s)",
2634        val, model, model->desc->cache.types[0]->name);
2635
2636    if (val->type)
2637      {
2638         ERR("interface properties flushed with values! val=%p, model %p (%s)",
2639             val, model, model->desc->cache.types[0]->name);
2640         eina_value_flush(val);
2641      }
2642
2643    return EINA_TRUE;
2644 }
2645
2646 static Eina_Bool
2647 _eina_model_interface_properties_struct_constructor(Eina_Model *model)
2648 {
2649    EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_GET(model);
2650
2651    DBG("construct interface properties (struct) at %p model %p (%s)",
2652        priv, model, model->desc->cache.types[0]->name);
2653
2654    return EINA_TRUE;
2655 }
2656
2657 static Eina_Bool
2658 _eina_model_interface_properties_struct_destructor(Eina_Model *model)
2659 {
2660    Eina_Value *val = eina_model_interface_private_data_get
2661      (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT);
2662
2663    DBG("destroy interface properties (struct) at %p model %p (%s)",
2664        val, model, model->desc->cache.types[0]->name);
2665
2666    eina_value_flush(val);
2667    val->type = NULL;
2668
2669    return EINA_TRUE;
2670 }
2671
2672 static Eina_Bool
2673 _eina_model_interface_properties_struct_get(const Eina_Model *model, const char *name, Eina_Value *val)
2674 {
2675    const Eina_Value *v = eina_model_interface_private_data_get
2676      (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT);
2677    return eina_value_struct_value_get(v, name, val);
2678 }
2679
2680 static Eina_Bool
2681 _eina_model_interface_properties_struct_set(Eina_Model *model, const char *name, const Eina_Value *val)
2682 {
2683    Eina_Value *v = eina_model_interface_private_data_get
2684      (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT);
2685    return eina_value_struct_value_set(v, name, val);
2686 }
2687
2688 static Eina_Bool
2689 _eina_model_interface_properties_struct_del(Eina_Model *model __UNUSED__, const char *name __UNUSED__)
2690 {
2691    return EINA_FALSE; /* not allowed */
2692 }
2693
2694 static Eina_List *
2695 _eina_model_interface_properties_struct_names_list(const Eina_Model *model)
2696 {
2697    EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_GET(model);
2698    const Eina_Value_Struct_Member *itr;
2699    Eina_List *list = NULL;
2700
2701    EINA_SAFETY_ON_NULL_RETURN_VAL(priv, NULL);
2702    EINA_SAFETY_ON_NULL_RETURN_VAL(priv->desc, NULL);
2703    EINA_SAFETY_ON_NULL_RETURN_VAL(priv->desc->members, NULL);
2704
2705    itr = priv->desc->members;
2706    if (priv->desc->member_count)
2707      {
2708         const Eina_Value_Struct_Member *end = itr + priv->desc->member_count;
2709         for (; itr < end; itr++)
2710           list = eina_list_append(list, eina_stringshare_add(itr->name));
2711      }
2712    else
2713      {
2714         for (; itr->name != NULL; itr++)
2715           list = eina_list_append(list, eina_stringshare_add(itr->name));
2716      }
2717
2718    return list;
2719 }
2720 #undef EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_GET
2721
2722 static const Eina_Model_Interface_Properties _EINA_MODEL_INTERFACE_PROPERTIES_STRUCT = {
2723   {
2724     EINA_MODEL_INTERFACE_VERSION,
2725     sizeof(Eina_Value),
2726     sizeof(Eina_Model_Interface_Properties),
2727     _EINA_MODEL_INTERFACE_NAME_PROPERTIES,
2728     NULL, /* no parent interfaces */
2729     _eina_model_interface_properties_events,
2730     _eina_model_interface_properties_struct_setup,
2731     _eina_model_interface_properties_struct_flush,
2732     _eina_model_interface_properties_struct_constructor,
2733     _eina_model_interface_properties_struct_destructor,
2734     NULL,
2735     NULL,
2736     NULL,
2737     NULL,
2738     NULL,
2739     NULL
2740   },
2741   EINA_MODEL_INTERFACE_PROPERTIES_VERSION,
2742   NULL, /* no compare */
2743   NULL, /* no load */
2744   NULL, /* no unload */
2745   _eina_model_interface_properties_struct_get,
2746   _eina_model_interface_properties_struct_set,
2747   _eina_model_interface_properties_struct_del,
2748   _eina_model_interface_properties_struct_names_list
2749 };
2750
2751 /* Events for all Children interface */
2752 static const Eina_Model_Event_Description _eina_model_interface_children_events[] = {
2753   EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_children_loaded, "", "model children were loaded"),
2754   EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_children_unloaded, "", "model children were unloaded"),
2755   EINA_MODEL_EVENT_DESCRIPTION_SENTINEL
2756 };
2757
2758 /* EINA_MODEL_INTERFACE_CHILDREN_INARRAY ******************************/
2759
2760 #define EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model)        \
2761   Eina_Inarray *priv = eina_model_interface_private_data_get    \
2762     (model, EINA_MODEL_INTERFACE_CHILDREN_INARRAY)
2763
2764 static Eina_Bool
2765 _eina_model_interface_children_inarray_setup(Eina_Model *model)
2766 {
2767    EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model);
2768
2769    DBG("setup interface children (inarray) at %p model %p (%s)",
2770        priv, model, model->desc->cache.types[0]->name);
2771
2772    eina_inarray_step_set(priv, sizeof(Eina_Inarray), sizeof(Eina_Model *), 0);
2773    return EINA_TRUE;
2774 }
2775
2776 static Eina_Bool
2777 _eina_model_interface_children_inarray_flush(Eina_Model *model)
2778 {
2779    EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model);
2780    int count;
2781
2782    DBG("flush interface children (inarray) at %p model %p (%s)",
2783        priv, model, model->desc->cache.types[0]->name);
2784
2785    count = eina_inarray_count(priv);
2786    if (count > 0)
2787      ERR("interface children flushed with %d members! priv=%p, model %p (%s)",
2788          count, priv, model, model->desc->cache.types[0]->name);
2789
2790    eina_inarray_flush(priv);
2791    return EINA_TRUE;
2792 }
2793
2794 static Eina_Bool
2795 _eina_model_interface_children_inarray_constructor(Eina_Model *model)
2796 {
2797    EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model);
2798
2799    DBG("construct interface children (inarray) at %p model %p (%s)",
2800        priv, model, model->desc->cache.types[0]->name);
2801
2802    return EINA_TRUE;
2803 }
2804
2805 static Eina_Bool
2806 _eina_model_interface_children_inarray_destructor(Eina_Model *model)
2807 {
2808    Eina_Model **itr, **itr_end;
2809    int count;
2810
2811    EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model);
2812
2813    count = eina_inarray_count(priv);
2814
2815    DBG("destroy interface children (inarray) at %p model %p (%s). %d members.",
2816        priv, model, model->desc->cache.types[0]->name, count);
2817
2818    itr = priv->members;
2819    itr_end = itr + count;
2820    for (; itr < itr_end; itr++)
2821      eina_model_xunref(*itr, EINA_MODEL_INTERFACE_CHILDREN_INARRAY);
2822    eina_inarray_flush(priv);
2823
2824    return EINA_TRUE;
2825 }
2826
2827 static int
2828 _eina_model_interface_children_inarray_count(const Eina_Model *model)
2829 {
2830    EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model);
2831    return eina_inarray_count(priv);
2832 }
2833
2834 static Eina_Model *
2835 _eina_model_interface_children_inarray_get(const Eina_Model *model, unsigned int position)
2836 {
2837    EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model);
2838    Eina_Model **child = eina_inarray_nth(priv, position);
2839    if (!child)
2840      return NULL;
2841    return eina_model_ref(*child);
2842 }
2843
2844 static Eina_Bool
2845 _eina_model_interface_children_inarray_set(Eina_Model *model, unsigned int position, Eina_Model *child)
2846 {
2847    EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model);
2848    Eina_Model **p_old = eina_inarray_nth(priv, position);
2849    Eina_Model *old;
2850
2851    if (!p_old)
2852      return EINA_FALSE;
2853
2854    old = *p_old;
2855    if (!eina_inarray_replace_at(priv, position, &child))
2856      return EINA_FALSE;
2857
2858    eina_model_xref(child, EINA_MODEL_INTERFACE_CHILDREN_INARRAY,
2859                    "eina_model_child_set");
2860    eina_model_xunref(old, EINA_MODEL_INTERFACE_CHILDREN_INARRAY);
2861    return EINA_TRUE;
2862 }
2863
2864 static Eina_Bool
2865 _eina_model_interface_children_inarray_del(Eina_Model *model, unsigned int position)
2866 {
2867    EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model);
2868    Eina_Model **p_old = eina_inarray_nth(priv, position);
2869    Eina_Model *old;
2870
2871    if (!p_old)
2872      return EINA_FALSE;
2873
2874    old = *p_old;
2875    if (!eina_inarray_remove_at(priv, position))
2876      return EINA_FALSE;
2877
2878    eina_model_xunref(old, EINA_MODEL_INTERFACE_CHILDREN_INARRAY);
2879    return EINA_TRUE;
2880 }
2881
2882 static Eina_Bool
2883 _eina_model_interface_children_inarray_insert_at(Eina_Model *model, unsigned int position, Eina_Model *child)
2884 {
2885    EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model);
2886
2887    if (!eina_inarray_insert_at(priv, position, &child))
2888      return EINA_FALSE;
2889
2890    eina_model_xref(child, EINA_MODEL_INTERFACE_CHILDREN_INARRAY,
2891                    "eina_model_child_insert_at");
2892    return EINA_TRUE;
2893 }
2894
2895 static void
2896 _eina_model_interface_children_inarray_sort(Eina_Model *model, Eina_Compare_Cb compare)
2897 {
2898    EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model);
2899    int count = eina_inarray_count(priv);
2900    EINA_SAFETY_ON_FALSE_RETURN(count >= 0);
2901
2902    if (count > 1)
2903      _eina_model_array_sort(priv->members, 0, count - 1, compare);
2904 }
2905 #undef EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET
2906
2907 static const Eina_Model_Interface_Children _EINA_MODEL_INTERFACE_CHILDREN_INARRAY = {
2908   {
2909     EINA_MODEL_INTERFACE_VERSION,
2910     sizeof(Eina_Inarray),
2911     sizeof(Eina_Model_Interface_Children),
2912     _EINA_MODEL_INTERFACE_NAME_CHILDREN,
2913     NULL, /* no parent interfaces */
2914     _eina_model_interface_children_events,
2915     _eina_model_interface_children_inarray_setup,
2916     _eina_model_interface_children_inarray_flush,
2917     _eina_model_interface_children_inarray_constructor,
2918     _eina_model_interface_children_inarray_destructor,
2919     NULL,
2920     NULL,
2921     NULL,
2922     NULL,
2923     NULL,
2924     NULL
2925   },
2926   EINA_MODEL_INTERFACE_CHILDREN_VERSION,
2927   NULL, /* no compare */
2928   NULL, /* no load */
2929   NULL, /* no unload */
2930   _eina_model_interface_children_inarray_count,
2931   _eina_model_interface_children_inarray_get,
2932   _eina_model_interface_children_inarray_set,
2933   _eina_model_interface_children_inarray_del,
2934   _eina_model_interface_children_inarray_insert_at,
2935   _eina_model_interface_children_inarray_sort
2936 };
2937
2938 /* EINA_MODEL_TYPE_GENERIC ********************************************/
2939
2940 static const Eina_Model_Interface *_EINA_MODEL_TYPE_GENERIC_IFACES[] = {
2941   &_EINA_MODEL_INTERFACE_PROPERTIES_HASH.base,
2942   &_EINA_MODEL_INTERFACE_CHILDREN_INARRAY.base,
2943   NULL
2944 };
2945
2946 static const Eina_Model_Type _EINA_MODEL_TYPE_GENERIC =
2947   EINA_MODEL_TYPE_INIT_NOPRIVATE("Eina_Model_Type_Generic",
2948                                  Eina_Model_Type,
2949                                  &_EINA_MODEL_TYPE_MIXIN,
2950                                  _EINA_MODEL_TYPE_GENERIC_IFACES,
2951                                  NULL);
2952
2953 /* EINA_MODEL_TYPE_STRUCT ********************************************/
2954
2955 static const Eina_Model_Interface *_EINA_MODEL_TYPE_STRUCT_IFACES[] = {
2956   &_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base,
2957   &_EINA_MODEL_INTERFACE_CHILDREN_INARRAY.base,
2958   NULL
2959 };
2960
2961 static const Eina_Model_Type _EINA_MODEL_TYPE_STRUCT =
2962   EINA_MODEL_TYPE_INIT_NOPRIVATE("Eina_Model_Type_Struct",
2963                                  Eina_Model_Type,
2964                                  &_EINA_MODEL_TYPE_MIXIN,
2965                                  _EINA_MODEL_TYPE_STRUCT_IFACES,
2966                                  NULL);
2967
2968 /**
2969  */
2970
2971 /**
2972  * @internal
2973  * @brief Initialize the model module.
2974  *
2975  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
2976  *
2977  * This function sets up the model module of Eina. It is called
2978  * by eina_init().
2979  *
2980  * @see eina_init()
2981  */
2982 Eina_Bool
2983 eina_model_init(void)
2984 {
2985    const char *choice, *tmp;
2986
2987    _eina_model_log_dom = eina_log_domain_register("eina_model",
2988                                                   EINA_LOG_COLOR_DEFAULT);
2989    if (_eina_model_log_dom < 0)
2990      {
2991         EINA_LOG_ERR("Could not register log domain: eina_model");
2992         return EINA_FALSE;
2993      }
2994
2995    choice = getenv("EINA_MODEL_DEBUG");
2996    if (choice)
2997      {
2998         if (strcmp(choice, "1") == 0)
2999           _eina_model_debug = EINA_MODEL_DEBUG_CHECK;
3000         else if (strcmp(choice, "backtrace") == 0)
3001           _eina_model_debug = EINA_MODEL_DEBUG_BACKTRACE;
3002      }
3003
3004 #ifdef EINA_DEFAULT_MEMPOOL
3005    choice = "pass_through";
3006 #else
3007    choice = "chained_mempool";
3008 #endif
3009    tmp = getenv("EINA_MEMPOOL");
3010    if (tmp && tmp[0])
3011      choice = tmp;
3012
3013    if (choice)
3014      _eina_model_mp_choice = strdup(choice);
3015
3016    _eina_model_mp = eina_mempool_add
3017      (_eina_model_mp_choice, "model", NULL, sizeof(Eina_Model), 32);
3018    if (!_eina_model_mp)
3019      {
3020         ERR("Mempool for model cannot be allocated in model init.");
3021         goto on_init_fail_mp;
3022      }
3023
3024    if (!eina_lock_new(&_eina_model_inner_mps_lock))
3025      {
3026         ERR("Cannot create inner mempools lock in model init.");
3027         goto on_init_fail_lock_mp;
3028      }
3029    _eina_model_inner_mps = eina_hash_int32_new(NULL);
3030    if (!_eina_model_inner_mps)
3031      {
3032         ERR("Cannot create hash for inner mempools in model init.");
3033         goto on_init_fail_hash_mp;
3034      }
3035
3036    if (!eina_lock_new(&_eina_model_descriptions_lock))
3037      {
3038         ERR("Cannot create model descriptions lock in model init.");
3039         goto on_init_fail_lock_desc;
3040      }
3041    _eina_model_descriptions = eina_hash_pointer_new(NULL);
3042    if (!_eina_model_descriptions)
3043      {
3044         ERR("Cannot create model descriptions hash in model init.");
3045         goto on_init_fail_hash_desc;
3046      }
3047
3048    if (!eina_lock_new(&_eina_model_debug_list_lock))
3049      {
3050         ERR("Cannot create model debug list lock in model init.");
3051         goto on_init_fail_lock_debug;
3052      }
3053
3054    EINA_ERROR_MODEL_FAILED = eina_error_msg_static_register(
3055                                                             EINA_ERROR_MODEL_FAILED_STR);
3056    EINA_ERROR_MODEL_METHOD_MISSING = eina_error_msg_static_register(
3057                                                                     EINA_ERROR_MODEL_METHOD_MISSING_STR);
3058
3059    EINA_MODEL_TYPE_BASE = &_EINA_MODEL_TYPE_BASE;
3060    EINA_MODEL_TYPE_MIXIN = &_EINA_MODEL_TYPE_MIXIN;
3061    EINA_MODEL_TYPE_GENERIC = &_EINA_MODEL_TYPE_GENERIC;
3062    EINA_MODEL_TYPE_STRUCT = &_EINA_MODEL_TYPE_STRUCT;
3063
3064    EINA_MODEL_INTERFACE_PROPERTIES_HASH = &_EINA_MODEL_INTERFACE_PROPERTIES_HASH.base;
3065    EINA_MODEL_INTERFACE_PROPERTIES_STRUCT = &_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base;
3066
3067    EINA_MODEL_INTERFACE_CHILDREN_INARRAY = &_EINA_MODEL_INTERFACE_CHILDREN_INARRAY.base;
3068
3069    EINA_MODEL_INTERFACE_NAME_PROPERTIES = _EINA_MODEL_INTERFACE_NAME_PROPERTIES;
3070    EINA_MODEL_INTERFACE_NAME_CHILDREN = _EINA_MODEL_INTERFACE_NAME_CHILDREN;
3071
3072    eina_magic_string_static_set(EINA_MAGIC_MODEL, EINA_MAGIC_MODEL_STR);
3073
3074    return EINA_TRUE;
3075
3076  on_init_fail_lock_debug:
3077    eina_hash_free(_eina_model_descriptions);
3078  on_init_fail_hash_desc:
3079    eina_lock_free(&_eina_model_descriptions_lock);
3080  on_init_fail_lock_desc:
3081    eina_hash_free(_eina_model_inner_mps);
3082    _eina_model_inner_mps = NULL;
3083  on_init_fail_hash_mp:
3084    eina_lock_free(&_eina_model_inner_mps_lock);
3085  on_init_fail_lock_mp:
3086    eina_mempool_del(_eina_model_mp);
3087  on_init_fail_mp:
3088    free(_eina_model_mp_choice);
3089    _eina_model_mp_choice = NULL;
3090    eina_log_domain_unregister(_eina_model_log_dom);
3091    _eina_model_log_dom = -1;
3092    return EINA_FALSE;
3093 }
3094
3095 /**
3096  * @internal
3097  * @brief Shut down the model module.
3098  *
3099  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
3100  *
3101  * This function shuts down the model module set up by
3102  * eina_model_init(). It is called by eina_shutdown().
3103  *
3104  * @see eina_shutdown()
3105  */
3106 Eina_Bool
3107 eina_model_shutdown(void)
3108 {
3109    eina_lock_take(&_eina_model_debug_list_lock);
3110    if (eina_list_count(_eina_model_debug_list) > 0)
3111      ERR("%d models are still alive!", eina_list_count(_eina_model_debug_list));
3112    eina_lock_release(&_eina_model_debug_list_lock);
3113    eina_lock_free(&_eina_model_debug_list_lock);
3114
3115    eina_lock_take(&_eina_model_inner_mps_lock);
3116    if (eina_hash_population(_eina_model_inner_mps) != 0)
3117      ERR("Cannot free eina_model internal memory pools -- still in use!");
3118    else
3119      eina_hash_free(_eina_model_inner_mps);
3120    eina_lock_release(&_eina_model_inner_mps_lock);
3121    eina_lock_free(&_eina_model_inner_mps_lock);
3122
3123    eina_lock_take(&_eina_model_descriptions_lock);
3124    if (eina_hash_population(_eina_model_descriptions) != 0)
3125      ERR("Cannot free eina_model internal descriptions -- still in use!");
3126    else
3127      eina_hash_free(_eina_model_descriptions);
3128    eina_lock_release(&_eina_model_descriptions_lock);
3129    eina_lock_free(&_eina_model_descriptions_lock);
3130
3131    free(_eina_model_mp_choice);
3132    _eina_model_mp_choice = NULL;
3133    eina_mempool_del(_eina_model_mp);
3134    eina_log_domain_unregister(_eina_model_log_dom);
3135    _eina_model_log_dom = -1;
3136    return EINA_TRUE;
3137 }
3138
3139 /*============================================================================*
3140  *                                 Global                                     *
3141  *============================================================================*/
3142
3143 /*============================================================================*
3144  *                                   API                                      *
3145  *============================================================================*/
3146
3147
3148 EAPI Eina_Error EINA_ERROR_MODEL_FAILED = 0;
3149 EAPI Eina_Error EINA_ERROR_MODEL_METHOD_MISSING = 0;
3150
3151 EAPI const Eina_Model_Type *EINA_MODEL_TYPE_BASE = NULL;
3152 EAPI const Eina_Model_Type *EINA_MODEL_TYPE_MIXIN = NULL;
3153 EAPI const Eina_Model_Type *EINA_MODEL_TYPE_GENERIC = NULL;
3154 EAPI const Eina_Model_Type *EINA_MODEL_TYPE_STRUCT = NULL;
3155
3156 EAPI const Eina_Model_Interface *EINA_MODEL_INTERFACE_PROPERTIES_HASH = NULL;
3157 EAPI const Eina_Model_Interface *EINA_MODEL_INTERFACE_PROPERTIES_STRUCT = NULL;
3158 EAPI const Eina_Model_Interface *EINA_MODEL_INTERFACE_CHILDREN_INARRAY = NULL;
3159
3160 EAPI const char *EINA_MODEL_INTERFACE_NAME_PROPERTIES = "Eina_Model_Interface_Properties";
3161 EAPI const char *EINA_MODEL_INTERFACE_NAME_CHILDREN = "Eina_Model_Interface_Children";
3162
3163 EAPI Eina_Model *
3164 eina_model_new(const Eina_Model_Type *type)
3165 {
3166    const Eina_Model_Description *desc;
3167    Eina_Model *model;
3168    unsigned int i;
3169
3170    EINA_SAFETY_ON_NULL_RETURN_VAL(type, NULL);
3171    EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_model_type_check(type), NULL);
3172
3173    desc = _eina_model_description_get(type);
3174    EINA_SAFETY_ON_NULL_RETURN_VAL(desc, NULL);
3175
3176    model = eina_mempool_malloc(_eina_model_mp, sizeof(Eina_Model));
3177    EINA_SAFETY_ON_NULL_GOTO(model, failed_model);
3178
3179    model->desc = desc;
3180    model->listeners.entries = NULL;
3181    model->listeners.deleted = NULL;
3182    model->listeners.freeze = NULL;
3183    model->listeners.walking = 0;
3184
3185    if (desc->total.size == 0)
3186      model->privates = NULL;
3187    else
3188      {
3189         unsigned char *ptr;
3190
3191         model->privates = _eina_model_inner_alloc
3192           (desc->total.privates * sizeof(void *) +
3193            desc->total.size);
3194         EINA_SAFETY_ON_NULL_GOTO(model->privates, failed_privates);
3195
3196         ptr = (unsigned char *)(model->privates + desc->total.privates);
3197         for (i = 0; i < desc->total.privates; i++)
3198           {
3199              unsigned int size;
3200              if (i < desc->total.types)
3201                size = desc->cache.privates[i].type->private_size;
3202              else
3203                size = desc->cache.privates[i].iface->private_size;
3204
3205              if (size == 0)
3206                {
3207                   model->privates[i] = NULL;
3208                   continue;
3209                }
3210
3211              model->privates[i] = ptr;
3212              memset(ptr, 0, size);
3213
3214              if (size % sizeof(void *) != 0)
3215                size += sizeof(void *) - (size % sizeof(void *));
3216              ptr += size;
3217           }
3218      }
3219
3220    model->refcount = 1;
3221    model->xrefs = NULL;
3222    model->deleted = EINA_FALSE;
3223    EINA_MAGIC_SET(model, EINA_MAGIC_MODEL);
3224
3225    /* call setup of every type in the reverse order,
3226     * they should not call parent's setup.
3227     */
3228    for (i = desc->total.types; i > 0; i--)
3229      {
3230         if (desc->cache.types[i - 1]->setup)
3231           {
3232              if (!desc->cache.types[i - 1]->setup(model))
3233                {
3234                   ERR("Failed to setup model %p at type %p (%s)",
3235                       model, desc->cache.types[i - 1],
3236                       desc->cache.types[i - 1]->name);
3237                   goto failed_types;
3238                }
3239           }
3240      }
3241
3242    /* call setup of every interface in the reverse order,
3243     * they should not call parent's setup.
3244     */
3245    for (i = desc->total.ifaces; i > 0; i--)
3246      {
3247         if (desc->cache.ifaces[i - 1]->setup)
3248           {
3249              if (!desc->cache.ifaces[i - 1]->setup(model))
3250                {
3251                   ERR("Failed to setup model %p at interface %p (%s)",
3252                       model, desc->cache.ifaces[i - 1],
3253                       desc->cache.ifaces[i - 1]->name);
3254                   goto failed_ifaces;
3255                }
3256           }
3257      }
3258
3259    if (!desc->ops.type.constructor(model))
3260      {
3261         ERR("Failed to construct model %p, type %p (%s)",
3262             model, desc->cache.types[0], desc->cache.types[0]->name);
3263         goto failed_constructor;
3264      }
3265
3266    if (EINA_UNLIKELY(_eina_model_debug))
3267      {
3268         eina_lock_take(&_eina_model_debug_list_lock);
3269         _eina_model_debug_list = eina_list_append
3270           (_eina_model_debug_list, model);
3271         eina_lock_release(&_eina_model_debug_list_lock);
3272      }
3273
3274    return model;
3275
3276  failed_constructor:
3277    i = 0;
3278  failed_ifaces:
3279    /* flush every setup interface, natural order */
3280    for (; i < desc->total.ifaces; i++)
3281      desc->cache.ifaces[i]->flush(model);
3282    i = 0;
3283  failed_types:
3284    /* flush every setup type, natural order */
3285    for (; i < desc->total.types; i++)
3286      desc->cache.types[i]->flush(model);
3287
3288    if (model->privates)
3289      _eina_model_inner_free(desc->total.privates * sizeof(void *) +
3290                             desc->total.size,
3291                             model->privates);
3292
3293  failed_privates:
3294    EINA_MAGIC_SET(model, EINA_MAGIC_NONE);
3295    eina_mempool_free(_eina_model_mp, model);
3296  failed_model:
3297    _eina_model_description_dispose(desc);
3298    return NULL;
3299 }
3300
3301 static void
3302 _eina_model_free(Eina_Model *model)
3303 {
3304    const Eina_Model_Description *desc = model->desc;
3305    unsigned int i;
3306
3307    DBG("model %p (%s) refcount=%d deleted=%hhu",
3308        model, model->desc->cache.types[0]->name,
3309        model->refcount, model->deleted);
3310
3311    if (EINA_UNLIKELY(_eina_model_debug))
3312      {
3313         if (model->xrefs)
3314           {
3315              ERR("Model %p (%s) released with references pending:",
3316                  model, model->desc->cache.types[0]->name);
3317              while (model->xrefs)
3318                {
3319                   Eina_Model_XRef *ref = (Eina_Model_XRef *)model->xrefs;
3320                   model->xrefs = eina_inlist_remove(model->xrefs, model->xrefs);
3321
3322                   ERR("xref: %p '%s'", ref->id, ref->label);
3323                   free(ref);
3324                }
3325           }
3326
3327         eina_lock_take(&_eina_model_debug_list_lock);
3328         _eina_model_debug_list = eina_list_remove
3329           (_eina_model_debug_list, model);
3330         eina_lock_release(&_eina_model_debug_list_lock);
3331      }
3332
3333    /* flush every interface, natural order */
3334    for (i = 0; i < desc->total.ifaces; i++)
3335      if (desc->cache.ifaces[i]->flush)
3336        desc->cache.ifaces[i]->flush(model);
3337
3338    /* flush every type, natural order */
3339    for (i = 0; i < desc->total.types; i++)
3340      if (desc->cache.types[i]->flush)
3341        desc->cache.types[i]->flush(model);
3342
3343    model->refcount--;
3344    _eina_model_event_callback_call(model, _eina_model_str_freed, NULL);
3345
3346    if (model->privates)
3347      _eina_model_inner_free(desc->total.privates * sizeof(void *) +
3348                             desc->total.size,
3349                             model->privates);
3350
3351    if (model->listeners.deleted)
3352      _eina_model_event_callback_free_deleted(model);
3353
3354    if (model->listeners.entries)
3355      {
3356         for (i = 0; i < desc->total.events; i++)
3357           {
3358              Eina_Inlist *lst = model->listeners.entries[i];
3359              while (lst)
3360                {
3361                   void *tmp = lst;
3362                   lst = lst->next;
3363                   _eina_model_inner_free(sizeof(Eina_Model_Event_Listener),
3364                                          tmp);
3365                }
3366           }
3367
3368         _eina_model_inner_free(desc->total.events * sizeof(Eina_Inlist *),
3369                                model->listeners.entries);
3370      }
3371
3372    if (model->listeners.freeze)
3373      _eina_model_inner_free(model->desc->total.events * sizeof(int),
3374                             model->listeners.freeze);
3375
3376    EINA_MAGIC_SET(model, EINA_MAGIC_NONE);
3377    eina_mempool_free(_eina_model_mp, model);
3378
3379    _eina_model_description_dispose(desc);
3380 }
3381
3382 static void
3383 _eina_model_del(Eina_Model *model)
3384 {
3385    const Eina_Model_Description *desc = model->desc;
3386
3387    DBG("model %p (%s) refcount=%d deleted=%hhu",
3388        model, model->desc->cache.types[0]->name,
3389        model->refcount, model->deleted);
3390
3391    EINA_SAFETY_ON_TRUE_RETURN(model->deleted);
3392
3393    model->deleted = EINA_TRUE;
3394    _eina_model_event_callback_call(model, _eina_model_str_deleted, NULL);
3395
3396    if (!desc->ops.type.destructor(model))
3397      ERR("Failed to destroy model %p, type %p (%s)",
3398          model, desc->cache.types[0], desc->cache.types[0]->name);
3399 }
3400
3401 static void
3402 _eina_model_unref(Eina_Model *model)
3403 {
3404    DBG("model %p (%s) refcount=%d deleted=%hhu",
3405        model, model->desc->cache.types[0]->name,
3406        model->refcount, model->deleted);
3407
3408    if (model->refcount > 1)
3409      {
3410         model->refcount--;
3411         return;
3412      }
3413
3414    if (!model->deleted) _eina_model_del(model);
3415    _eina_model_free(model);
3416 }
3417
3418 #define EINA_MODEL_INSTANCE_CHECK_VAL(inst, retval)                     \
3419   do                                                                    \
3420     {                                                                   \
3421        if (!EINA_MAGIC_CHECK(inst, EINA_MAGIC_MODEL))                   \
3422          {                                                              \
3423             EINA_MAGIC_FAIL(inst, EINA_MAGIC_MODEL);                    \
3424             return retval;                                              \
3425          }                                                              \
3426        EINA_SAFETY_ON_NULL_RETURN_VAL(inst->desc, retval);              \
3427        EINA_SAFETY_ON_FALSE_RETURN_VAL(inst->refcount > 0, retval);     \
3428        EINA_SAFETY_ON_FALSE_RETURN_VAL(inst->desc->refcount > 0, retval); \
3429     }                                                                   \
3430   while (0)
3431
3432 #define EINA_MODEL_INSTANCE_CHECK(inst)                         \
3433   do                                                            \
3434     {                                                           \
3435        if (!EINA_MAGIC_CHECK(inst, EINA_MAGIC_MODEL))           \
3436          {                                                      \
3437             EINA_MAGIC_FAIL(inst, EINA_MAGIC_MODEL);            \
3438             return;                                             \
3439          }                                                      \
3440        EINA_SAFETY_ON_NULL_RETURN(inst->desc);                  \
3441        EINA_SAFETY_ON_FALSE_RETURN(inst->refcount > 0);         \
3442        EINA_SAFETY_ON_FALSE_RETURN(inst->desc->refcount > 0);   \
3443     }                                                           \
3444   while (0)
3445
3446 #define EINA_MODEL_TYPE_CALL_OPTIONAL_RETURN(model, method, def_retval, ...) \
3447   do                                                                    \
3448     {                                                                   \
3449        eina_error_set(0);                                               \
3450        if (model->desc->ops.type.method)                                \
3451          return model->desc->ops.type.method(model, ## __VA_ARGS__);    \
3452        DBG("Optional method" # method "() not implemented for model %p (%s)", \
3453            model, model->desc->cache.types[0]->name);                   \
3454        return def_retval;                                               \
3455     }                                                                   \
3456   while (0)
3457
3458 #define EINA_MODEL_TYPE_CALL_OPTIONAL(model, method, ...)               \
3459   do                                                                    \
3460     {                                                                   \
3461        eina_error_set(0);                                               \
3462        if (model->desc->ops.type.method)                                \
3463          model->desc->ops.type.method(model, ## __VA_ARGS__);           \
3464        else                                                             \
3465          DBG("Optional method" # method "() not implemented for model %p (%s)", \
3466              model, model->desc->cache.types[0]->name);                 \
3467     }                                                                   \
3468   while (0)
3469
3470 #define EINA_MODEL_TYPE_CALL_MANDATORY_RETURN(model, method, def_retval, ...) \
3471   do                                                                    \
3472     {                                                                   \
3473        eina_error_set(0);                                               \
3474        if (model->desc->ops.type.method)                                \
3475          return model->desc->ops.type.method(model, ## __VA_ARGS__);    \
3476        eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING);                 \
3477        CRITICAL("Mandatory method" # method "() not implemented for model %p (%s)", \
3478                 model, model->desc->cache.types[0]->name);              \
3479        return def_retval;                                               \
3480     }                                                                   \
3481   while (0)
3482
3483 #define EINA_MODEL_TYPE_CALL_MANDATORY(model, method, ...)              \
3484   do                                                                    \
3485     {                                                                   \
3486        eina_error_set(0);                                               \
3487        if (model->desc->ops.type.method)                                \
3488          model->desc->ops.type.method(model, ## __VA_ARGS__);           \
3489        else                                                             \
3490          {                                                              \
3491             eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING);            \
3492             CRITICAL("Mandatory method" # method "() not implemented for model %p (%s)", \
3493                      model, model->desc->cache.types[0]->name);         \
3494          }                                                              \
3495     }                                                                   \
3496   while (0)
3497
3498
3499 #define EINA_MODEL_TYPE_CALL_RETURN(model, method, def_retval, ...)     \
3500   do                                                                    \
3501     {                                                                   \
3502        eina_error_set(0);                                               \
3503        if (model->desc->ops.type.method)                                \
3504          return model->desc->ops.type.method(model, ## __VA_ARGS__);    \
3505        eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING);                 \
3506        ERR("Method" # method "() not implemented for model %p (%s)",    \
3507            model, model->desc->cache.types[0]->name);                   \
3508        return def_retval;                                               \
3509     }                                                                   \
3510   while (0)
3511
3512 #define EINA_MODEL_TYPE_CALL(model, method, ...)                        \
3513   do                                                                    \
3514     {                                                                   \
3515        eina_error_set(0);                                               \
3516        if (model->desc->ops.type.method)                                \
3517          model->desc->ops.type.method(model, ## __VA_ARGS__);           \
3518        else                                                             \
3519          {                                                              \
3520             eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING);            \
3521             ERR("Method" # method "() not implemented for model %p (%s)", \
3522                 model, model->desc->cache.types[0]->name);              \
3523          }                                                              \
3524     }                                                                   \
3525   while (0)
3526
3527 EAPI void
3528 eina_model_del(Eina_Model *model)
3529 {
3530    if (!model)
3531      return;
3532
3533    EINA_MODEL_INSTANCE_CHECK(model);
3534    _eina_model_del(model);
3535    _eina_model_unref(model);
3536 }
3537
3538 EAPI const Eina_Model_Type *
3539 eina_model_type_get(const Eina_Model *model)
3540 {
3541    EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
3542    return model->desc->cache.types[0];
3543 }
3544
3545 EAPI const Eina_Model_Interface *
3546 eina_model_interface_get(const Eina_Model *model, const char *name)
3547 {
3548    const Eina_Model_Description *desc;
3549    const Eina_Model_Interface **itr, **itr_end;
3550
3551    EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
3552    EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
3553
3554    desc = model->desc;
3555    itr = desc->cache.ifaces;
3556    itr_end = itr + desc->total.ifaces;
3557
3558    /* fallback to strcmp if user is lazy about speed */
3559    for (; itr < itr_end; itr++)
3560      if (strcmp((*itr)->name, name) == 0)
3561        return *itr;
3562
3563    return NULL;
3564 }
3565
3566 static Eina_Bool
3567 _eina_model_instance_check(const Eina_Model *model, const Eina_Model_Type *type)
3568 {
3569    const Eina_Model_Type **itr, **itr_end;
3570
3571    itr = model->desc->cache.types;
3572    itr_end = itr + model->desc->total.types;
3573
3574    for (; itr < itr_end; itr++)
3575      if (*itr == type)
3576        return EINA_TRUE;
3577
3578    return EINA_FALSE;
3579 }
3580
3581 EAPI Eina_Bool
3582 eina_model_instance_check(const Eina_Model *model, const Eina_Model_Type *type)
3583 {
3584    EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
3585    EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE);
3586    EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), EINA_FALSE);
3587    return _eina_model_instance_check(model, type);
3588 }
3589
3590 EAPI Eina_Model *
3591 eina_model_ref(Eina_Model *model)
3592 {
3593    EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
3594    DBG("model %p (%s) refcount=%d deleted=%hhu",
3595        model, model->desc->cache.types[0]->name,
3596        model->refcount, model->deleted);
3597    model->refcount++;
3598    return model;
3599 }
3600
3601 static Eina_Model *
3602 _eina_model_xref_add(Eina_Model *model, const void *id, const char *label)
3603 {
3604    Eina_Model_XRef *ref;
3605    void *bt[256];
3606    int btlen, labellen;
3607
3608    labellen = label ? strlen(label): 0;
3609    btlen = 0;
3610
3611 #ifdef HAVE_BACKTRACE
3612    if (_eina_model_debug == EINA_MODEL_DEBUG_BACKTRACE)
3613      btlen = backtrace(bt, EINA_C_ARRAY_LENGTH(bt));
3614 #endif
3615
3616    ref = calloc(1, sizeof(*ref) + (btlen * sizeof(void *)) + (labellen + 1));
3617    EINA_SAFETY_ON_NULL_RETURN_VAL(ref, NULL);
3618
3619    ref->id = id;
3620    memcpy(ref->label, label, labellen);
3621    ref->label[labellen] = '\0';
3622    ref->backtrace.count = btlen;
3623    if (btlen == 0) ref->backtrace.symbols = NULL;
3624    else
3625      {
3626         void *ptr = (unsigned char *)ref + sizeof(*ref) + (labellen + 1);
3627         ref->backtrace.symbols = ptr;
3628         memcpy(ptr, bt, btlen * sizeof(void *));
3629      }
3630
3631    model->xrefs = eina_inlist_append(model->xrefs, EINA_INLIST_GET(ref));
3632    return model;
3633 }
3634
3635 EAPI Eina_Model *
3636 eina_model_xref(Eina_Model *model, const void *id, const char *label)
3637 {
3638    EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
3639    DBG("model %p (%s) refcount=%d deleted=%hhu id=%p label=%s",
3640        model, model->desc->cache.types[0]->name,
3641        model->refcount, model->deleted, id, label ? label : "");
3642
3643    model->refcount++;
3644
3645    if (EINA_LIKELY(!_eina_model_debug))
3646      return model;
3647
3648    return _eina_model_xref_add(model, id, label);
3649 }
3650
3651 EAPI void
3652 eina_model_unref(Eina_Model *model)
3653 {
3654    EINA_MODEL_INSTANCE_CHECK(model);
3655    _eina_model_unref(model);
3656 }
3657
3658 EAPI void
3659 eina_model_xunref(Eina_Model *model, const void *id)
3660 {
3661    Eina_Model_XRef *ref;
3662    EINA_MODEL_INSTANCE_CHECK(model);
3663
3664    if (EINA_LIKELY(!_eina_model_debug))
3665      {
3666         _eina_model_unref(model);
3667         return;
3668      }
3669
3670    EINA_INLIST_FOREACH(model->xrefs, ref)
3671      {
3672         if (ref->id != id) continue;
3673
3674         model->xrefs = eina_inlist_remove(model->xrefs, EINA_INLIST_GET(ref));
3675         free(ref);
3676         _eina_model_unref(model);
3677         return;
3678      }
3679
3680    ERR("Could not find existing reference %p to model %p", id, model);
3681 }
3682
3683 EAPI int
3684 eina_model_refcount(const Eina_Model *model)
3685 {
3686    EINA_MODEL_INSTANCE_CHECK_VAL(model, -1);
3687    return model->refcount;
3688 }
3689
3690 EAPI const Eina_Inlist *
3691 eina_model_xrefs_get(const Eina_Model *model)
3692 {
3693    EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
3694    return model->xrefs;
3695 }
3696
3697 EAPI Eina_Bool
3698 eina_model_event_callback_add(Eina_Model *model, const char *event_name, Eina_Model_Event_Cb cb, const void *data)
3699 {
3700    const Eina_Model_Description *desc;
3701    Eina_Model_Event_Listener *el;
3702    int event_id;
3703
3704    EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
3705    EINA_SAFETY_ON_NULL_RETURN_VAL(event_name, EINA_FALSE);
3706    EINA_SAFETY_ON_NULL_RETURN_VAL(cb, EINA_FALSE);
3707
3708    desc = model->desc;
3709    event_id = _eina_model_description_event_id_find(desc, event_name);
3710    if (event_id < 0)
3711      {
3712         ERR("No event named %s for model %p (%s)",
3713             event_name, model, model->desc->cache.types[0]->name);
3714         return EINA_FALSE;
3715      }
3716
3717    if (!model->listeners.entries)
3718      {
3719         model->listeners.entries = _eina_model_inner_alloc
3720           (desc->total.events * sizeof(Eina_Inlist *));
3721         EINA_SAFETY_ON_NULL_RETURN_VAL(model->listeners.entries, EINA_FALSE);
3722         memset(model->listeners.entries, 0,
3723                desc->total.events * sizeof(Eina_Inlist *));
3724      }
3725
3726    el = _eina_model_inner_alloc(sizeof(Eina_Model_Event_Listener));
3727    EINA_SAFETY_ON_NULL_RETURN_VAL(el, EINA_FALSE);
3728
3729    el->cb = cb;
3730    el->data = data;
3731    el->deleted = EINA_FALSE;
3732    model->listeners.entries[event_id] = eina_inlist_append
3733      (model->listeners.entries[event_id], EINA_INLIST_GET(el));
3734
3735    return EINA_TRUE;
3736 }
3737
3738 EAPI Eina_Bool
3739 eina_model_event_callback_del(Eina_Model *model, const char *event_name, Eina_Model_Event_Cb cb, const void *data)
3740 {
3741    int event_id;
3742    Eina_Inlist *lst;
3743    Eina_Model_Event_Listener *el;
3744
3745    EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
3746    EINA_SAFETY_ON_NULL_RETURN_VAL(event_name, EINA_FALSE);
3747    EINA_SAFETY_ON_NULL_RETURN_VAL(cb, EINA_FALSE);
3748
3749    if (!model->listeners.entries)
3750      {
3751         ERR("No event callbacks for model %p (%s)",
3752             model, model->desc->cache.types[0]->name);
3753         return EINA_FALSE;
3754      }
3755
3756    event_id = _eina_model_description_event_id_find(model->desc, event_name);
3757    if (event_id < 0)
3758      {
3759         ERR("No event named %s for model %p (%s)",
3760             event_name, model, model->desc->cache.types[0]->name);
3761         return EINA_FALSE;
3762      }
3763
3764    lst = model->listeners.entries[event_id];
3765    EINA_INLIST_FOREACH(lst, el)
3766      {
3767         if (el->cb != cb) continue;
3768         if ((data) && (el->data != data)) continue;
3769
3770         if (model->listeners.walking == 0)
3771           {
3772              model->listeners.entries[event_id] = eina_inlist_remove
3773                (model->listeners.entries[event_id], EINA_INLIST_GET(el));
3774              _eina_model_inner_free(sizeof(Eina_Model_Event_Listener), el);
3775           }
3776         else
3777           {
3778              el->deleted = EINA_TRUE;
3779              if (!model->listeners.deleted)
3780                {
3781                   model->listeners.deleted = _eina_model_inner_alloc
3782                     (model->desc->total.events * sizeof(Eina_List *));
3783                   EINA_SAFETY_ON_NULL_RETURN_VAL(model->listeners.deleted,
3784                                                  EINA_FALSE);
3785
3786                   memset(model->listeners.deleted, 0,
3787                          model->desc->total.events * sizeof(Eina_List *));
3788
3789                }
3790              model->listeners.deleted[event_id] = eina_list_append
3791                (model->listeners.deleted[event_id], el);
3792           }
3793         return EINA_TRUE;
3794      }
3795
3796    ERR("No callback %p data %p found for event named %s for model %p (%s)",
3797        cb, data, event_name, model, model->desc->cache.types[0]->name);
3798    return EINA_FALSE;
3799 }
3800
3801 EAPI const Eina_Model_Event_Description *
3802 eina_model_event_description_get(const Eina_Model *model, const char *event_name)
3803 {
3804    const Eina_Model_Description *desc;
3805    int event_id;
3806
3807    EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
3808    EINA_SAFETY_ON_NULL_RETURN_VAL(event_name, NULL);
3809
3810    desc = model->desc;
3811    event_id = _eina_model_description_event_id_find(desc, event_name);
3812    if (event_id < 0)
3813      return NULL;
3814
3815    return desc->cache.events[event_id].desc;
3816 }
3817
3818 EAPI Eina_List *
3819 eina_model_event_names_list_get(const Eina_Model *model)
3820 {
3821    const Eina_Model_Event_Description_Cache *itr, *itr_end;
3822    Eina_List *lst = NULL;
3823
3824    EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
3825
3826    itr = model->desc->cache.events;
3827    itr_end = itr + model->desc->total.events;
3828
3829    for (; itr < itr_end; itr++)
3830      lst = eina_list_append(lst, eina_stringshare_add(itr->name));
3831
3832    return lst;
3833 }
3834
3835 EAPI void
3836 eina_model_event_names_list_free(Eina_List *list)
3837 {
3838    const char *str;
3839    EINA_LIST_FREE(list, str)
3840      eina_stringshare_del(str);
3841 }
3842
3843 EAPI Eina_Bool
3844 eina_model_event_callback_call(Eina_Model *model, const char *name, const void *event_info)
3845 {
3846    EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
3847    EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
3848    return _eina_model_event_callback_call(model, name, event_info);
3849 }
3850
3851 EAPI int
3852 eina_model_event_callback_freeze(Eina_Model *model, const char *name)
3853 {
3854    int event_id;
3855
3856    EINA_MODEL_INSTANCE_CHECK_VAL(model, -1);
3857    EINA_SAFETY_ON_NULL_RETURN_VAL(name, -1);
3858
3859    event_id = _eina_model_description_event_id_find(model->desc, name);
3860    if (event_id < 0) return -1;
3861
3862    if (!model->listeners.freeze)
3863      {
3864         model->listeners.freeze = _eina_model_inner_alloc
3865           (model->desc->total.events * sizeof(int));
3866         EINA_SAFETY_ON_NULL_RETURN_VAL(model->listeners.freeze, -1);
3867
3868         memset(model->listeners.freeze, 0,
3869                model->desc->total.events * sizeof(int));
3870      }
3871
3872    if (model->listeners.freeze[event_id] == 0)
3873      DBG("model %p (%s) event %s frozen",
3874          model, model->desc->cache.types[0]->name, name);
3875
3876    model->listeners.freeze[event_id]++;
3877    return model->listeners.freeze[event_id];
3878 }
3879
3880 EAPI int
3881 eina_model_event_callback_thaw(Eina_Model *model, const char *name)
3882 {
3883    int event_id;
3884
3885    EINA_MODEL_INSTANCE_CHECK_VAL(model, -1);
3886    EINA_SAFETY_ON_NULL_RETURN_VAL(name, -1);
3887    EINA_SAFETY_ON_NULL_RETURN_VAL(model->listeners.freeze, -1);
3888
3889    event_id = _eina_model_description_event_id_find(model->desc, name);
3890    if (event_id < 0) return -1;
3891
3892    model->listeners.freeze[event_id]--;
3893    if (model->listeners.freeze[event_id] == 0)
3894      DBG("model %p (%s) event %s unfrozen",
3895          model, model->desc->cache.types[0]->name, name);
3896    return model->listeners.freeze[event_id];
3897 }
3898
3899 EAPI Eina_Model *
3900 eina_model_copy(const Eina_Model *model)
3901 {
3902    const Eina_Model_Description *desc;
3903    Eina_Model *copy;
3904    unsigned int i;
3905
3906    EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
3907    desc = model->desc;
3908    copy = eina_model_new(desc->cache.types[0]);
3909    EINA_SAFETY_ON_NULL_RETURN_VAL(copy, NULL);
3910
3911    /* call copy of every type in the reverse order,
3912     * they should not call parent's copy.
3913     */
3914    for (i = desc->total.types; i > 0; i--)
3915      {
3916         if (desc->cache.types[i - 1]->copy)
3917           {
3918              if (!desc->cache.types[i - 1]->copy(model, copy))
3919                goto failed;
3920           }
3921      }
3922
3923    /* call copy of every interface in the reverse order,
3924     * they should not call parent's copy.
3925     */
3926    for (i = desc->total.ifaces; i > 0; i--)
3927      {
3928         if (desc->cache.ifaces[i - 1]->copy)
3929           {
3930              if (!desc->cache.ifaces[i - 1]->copy(model, copy))
3931                goto failed;
3932           }
3933      }
3934
3935    return copy;
3936
3937  failed:
3938    ERR("Failed to copy model %p %s", model, desc->cache.types[0]->name);
3939    eina_model_del(copy);
3940    return NULL;
3941 }
3942
3943 EAPI Eina_Model *
3944 eina_model_deep_copy(const Eina_Model *model)
3945 {
3946    const Eina_Model_Description *desc;
3947    Eina_Model *deep_copy;
3948    unsigned int i;
3949
3950    EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
3951    desc = model->desc;
3952    deep_copy = eina_model_new(desc->cache.types[0]);
3953    EINA_SAFETY_ON_NULL_RETURN_VAL(deep_copy, NULL);
3954
3955    /* call deep_copy of every type in the reverse order,
3956     * they should not call parent's deep_copy.
3957     */
3958    for (i = desc->total.types; i > 0; i--)
3959      {
3960         if (desc->cache.types[i - 1]->deep_copy)
3961           {
3962              if (!desc->cache.types[i - 1]->deep_copy(model, deep_copy))
3963                goto failed;
3964           }
3965      }
3966
3967    /* call deep_copy of every interface in the reverse order,
3968     * they should not call parent's deep_copy.
3969     */
3970    for (i = desc->total.ifaces; i > 0; i--)
3971      {
3972         if (desc->cache.ifaces[i - 1]->deep_copy)
3973           {
3974              if (!desc->cache.ifaces[i - 1]->deep_copy(model, deep_copy))
3975                goto failed;
3976           }
3977      }
3978
3979    return deep_copy;
3980
3981  failed:
3982    ERR("Failed to deep copy model %p %s", model, desc->cache.types[0]->name);
3983    eina_model_del(deep_copy);
3984    return NULL;
3985 }
3986
3987 EAPI int
3988 eina_model_compare(const Eina_Model *a, const Eina_Model *b)
3989 {
3990    const Eina_Model_Description *desc_a, *desc_b;
3991    Eina_Bool ok;
3992    int cmp = -1;
3993
3994    EINA_MODEL_INSTANCE_CHECK_VAL(a, -1);
3995    EINA_MODEL_INSTANCE_CHECK_VAL(b, -1);
3996    desc_a = a->desc;
3997    desc_b = b->desc;
3998
3999    if ((!desc_a->ops.type.compare) && (!desc_b->ops.type.compare))
4000      {
4001         ERR("Models %p (%s) and %p (%s) can't compare",
4002             a, desc_a->cache.types[0]->name,
4003             b, desc_b->cache.types[0]->name);
4004         eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING);
4005         return -1;
4006      }
4007    else if ((desc_a->ops.type.compare) && (desc_b->ops.type.compare))
4008      {
4009         ok = desc_a->ops.type.compare(a, b, &cmp);
4010         if (!ok)
4011           {
4012              ok = desc_b->ops.type.compare(b, a, &cmp);
4013              if (ok)
4014                cmp = -cmp; /* swapped sides! */
4015           }
4016      }
4017    else if (desc_a->ops.type.compare)
4018      ok = desc_a->ops.type.compare(a, b, &cmp);
4019    else
4020      {
4021         ok = desc_b->ops.type.compare(b, a, &cmp);
4022         if (ok)
4023           cmp = -cmp; /* swapped sides! */
4024      }
4025
4026    if (!ok)
4027      {
4028         ERR("Could not compare models %p (%s) and %p (%s)",
4029             a, desc_a->cache.types[0]->name,
4030             b, desc_b->cache.types[0]->name);
4031         eina_error_set(EINA_ERROR_MODEL_FAILED);
4032         return -1;
4033      }
4034
4035    return cmp;
4036 }
4037
4038 EAPI Eina_Bool
4039 eina_model_load(Eina_Model *model)
4040 {
4041    Eina_Bool ret;
4042
4043    EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
4044
4045    eina_error_set(0);
4046    if (model->desc->ops.type.load)
4047      {
4048         ret = model->desc->ops.type.load(model);
4049         if (ret)
4050           _eina_model_event_callback_call(model, _eina_model_str_loaded, NULL);
4051      }
4052    else
4053      {
4054         eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING);
4055         ret = EINA_FALSE;
4056         ERR("Method load() not implemented for model %p (%s)",
4057             model, model->desc->cache.types[0]->name);
4058      }
4059
4060    return ret;
4061 }
4062
4063 EAPI Eina_Bool
4064 eina_model_unload(Eina_Model *model)
4065 {
4066    Eina_Bool ret;
4067
4068    EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
4069
4070    eina_error_set(0);
4071    if (model->desc->ops.type.unload)
4072      {
4073         ret = model->desc->ops.type.unload(model);
4074         if (ret)
4075           _eina_model_event_callback_call
4076             (model, _eina_model_str_unloaded, NULL);
4077      }
4078    else
4079      {
4080         eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING);
4081         ret = EINA_FALSE;
4082         ERR("Method unload() not implemented for model %p (%s)",
4083             model, model->desc->cache.types[0]->name);
4084      }
4085
4086    return ret;
4087 }
4088
4089 EAPI Eina_Bool
4090 eina_model_property_get(const Eina_Model *model, const char *name, Eina_Value *value)
4091 {
4092    EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
4093    EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
4094    EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
4095    EINA_MODEL_TYPE_CALL_MANDATORY_RETURN(model, property_get, EINA_FALSE,
4096                                          name, value);
4097 }
4098
4099 EAPI Eina_Bool
4100 eina_model_property_set(Eina_Model *model, const const char *name, const Eina_Value *value)
4101 {
4102    Eina_Bool ret;
4103
4104    EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
4105    EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
4106    EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
4107    EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_type_check(value->type), EINA_FALSE);
4108
4109    eina_error_set(0);
4110    if (model->desc->ops.type.property_set)
4111      {
4112         ret = model->desc->ops.type.property_set(model, name, value);
4113         if (ret)
4114           _eina_model_event_callback_call
4115             (model, _eina_model_str_property_set, name);
4116      }
4117    else
4118      {
4119         eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING);
4120         ret = EINA_FALSE;
4121         ERR("Method property_set() not implemented for model %p (%s)",
4122             model, model->desc->cache.types[0]->name);
4123      }
4124
4125    return ret;
4126 }
4127
4128 EAPI Eina_Bool
4129 eina_model_property_del(Eina_Model *model, const char *name)
4130 {
4131    Eina_Bool ret;
4132
4133    EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
4134    EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
4135
4136    eina_error_set(0);
4137    if (model->desc->ops.type.property_del)
4138      {
4139         ret = model->desc->ops.type.property_del(model, name);
4140         if (ret)
4141           _eina_model_event_callback_call
4142             (model, _eina_model_str_property_del, name);
4143      }
4144    else
4145      {
4146         eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING);
4147         ret = EINA_FALSE;
4148         ERR("Method property_del() not implemented for model %p (%s)",
4149             model, model->desc->cache.types[0]->name);
4150      }
4151
4152    return ret;
4153 }
4154
4155 EAPI Eina_List *
4156 eina_model_properties_names_list_get(const Eina_Model *model)
4157 {
4158    EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
4159    EINA_MODEL_TYPE_CALL_OPTIONAL_RETURN(model, properties_names_list_get, NULL);
4160 }
4161
4162 EAPI void
4163 eina_model_properties_names_list_free(Eina_List *list)
4164 {
4165    const char *str;
4166    EINA_LIST_FREE(list, str)
4167      eina_stringshare_del(str);
4168 }
4169
4170 EAPI int
4171 eina_model_child_count(const Eina_Model *model)
4172 {
4173    EINA_MODEL_INSTANCE_CHECK_VAL(model, -1);
4174    EINA_MODEL_TYPE_CALL_OPTIONAL_RETURN(model, child_count, 0);
4175 }
4176
4177 EAPI Eina_Model *
4178 eina_model_child_get(const Eina_Model *model, unsigned int position)
4179 {
4180    EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
4181    EINA_MODEL_TYPE_CALL_RETURN(model, child_get, NULL, position);
4182 }
4183
4184 EAPI Eina_Bool
4185 eina_model_child_set(Eina_Model *model, unsigned int position, Eina_Model *child)
4186 {
4187    Eina_Bool ret;
4188
4189    EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
4190    EINA_MODEL_INSTANCE_CHECK_VAL(child, EINA_FALSE);
4191
4192    eina_error_set(0);
4193    if (model->desc->ops.type.child_set)
4194      {
4195         ret = model->desc->ops.type.child_set(model, position, child);
4196         if (ret)
4197           _eina_model_event_callback_call
4198             (model, _eina_model_str_child_set, &position);
4199      }
4200    else
4201      {
4202         eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING);
4203         ret = EINA_FALSE;
4204         ERR("Method child_set() not implemented for model %p (%s)",
4205             model, model->desc->cache.types[0]->name);
4206      }
4207
4208    return ret;
4209 }
4210
4211 EAPI Eina_Bool
4212 eina_model_child_del(Eina_Model *model, unsigned int position)
4213 {
4214    Eina_Bool ret;
4215
4216    EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
4217
4218    eina_error_set(0);
4219    if (model->desc->ops.type.child_del)
4220      {
4221         ret = model->desc->ops.type.child_del(model, position);
4222         if (ret)
4223           {
4224              _eina_model_event_callback_call
4225                (model, _eina_model_str_child_del, &position);
4226              _eina_model_event_callback_call
4227                (model, _eina_model_str_children_changed, NULL);
4228           }
4229      }
4230    else
4231      {
4232         eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING);
4233         ret = EINA_FALSE;
4234         ERR("Method child_del() not implemented for model %p (%s)",
4235             model, model->desc->cache.types[0]->name);
4236      }
4237
4238    return ret;
4239 }
4240
4241 EAPI Eina_Bool
4242 eina_model_child_insert_at(Eina_Model *model, unsigned int position, Eina_Model *child)
4243 {
4244    Eina_Bool ret;
4245
4246    EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
4247    EINA_SAFETY_ON_NULL_RETURN_VAL(child, EINA_FALSE);
4248
4249    eina_error_set(0);
4250    if (model->desc->ops.type.child_insert_at)
4251      {
4252         ret = model->desc->ops.type.child_insert_at(model, position, child);
4253         if (ret)
4254           {
4255              _eina_model_event_callback_call
4256                (model, _eina_model_str_child_inserted, &position);
4257              _eina_model_event_callback_call
4258                (model, _eina_model_str_children_changed, NULL);
4259           }
4260      }
4261    else
4262      {
4263         eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING);
4264         ret = EINA_FALSE;
4265         ERR("Method child_insert_at() not implemented for model %p (%s)",
4266             model, model->desc->cache.types[0]->name);
4267      }
4268
4269    return ret;
4270 }
4271
4272 EAPI int
4273 eina_model_child_append(Eina_Model *model, Eina_Model *child)
4274 {
4275    Eina_Bool ret;
4276    int position;
4277
4278    EINA_MODEL_INSTANCE_CHECK_VAL(model, -1);
4279    EINA_SAFETY_ON_NULL_RETURN_VAL(child, -1);
4280
4281    position = eina_model_child_count(model);
4282    if (position < 0)
4283      return -1;
4284
4285    eina_error_set(0);
4286    if (model->desc->ops.type.child_insert_at)
4287      {
4288         ret = model->desc->ops.type.child_insert_at(model, position, child);
4289         if (ret)
4290           {
4291              _eina_model_event_callback_call
4292                (model, _eina_model_str_child_inserted, &position);
4293              _eina_model_event_callback_call
4294                (model, _eina_model_str_children_changed, NULL);
4295           }
4296      }
4297    else
4298      {
4299         eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING);
4300         ret = EINA_FALSE;
4301         ERR("Method child_insert_at() not implemented for model %p (%s)",
4302             model, model->desc->cache.types[0]->name);
4303      }
4304
4305    return ret ? position : -1;
4306 }
4307
4308 EAPI int
4309 eina_model_child_find(const Eina_Model *model, unsigned int start_position, const Eina_Model *other)
4310 {
4311    EINA_MODEL_INSTANCE_CHECK_VAL(model, -1);
4312    EINA_SAFETY_ON_NULL_RETURN_VAL(other, -1);
4313    EINA_MODEL_TYPE_CALL_RETURN(model, child_find, -1, start_position, other);
4314 }
4315
4316 EAPI int
4317 eina_model_child_criteria_match(const Eina_Model *model, unsigned int start_position, Eina_Each_Cb match, const void *data)
4318 {
4319    EINA_MODEL_INSTANCE_CHECK_VAL(model, -1);
4320    EINA_SAFETY_ON_NULL_RETURN_VAL(match, -1);
4321    EINA_MODEL_TYPE_CALL_RETURN(model, child_criteria_match, -1,
4322                                start_position, match, data);
4323 }
4324
4325 EAPI Eina_Bool
4326 eina_model_child_sort(Eina_Model *model, Eina_Compare_Cb compare)
4327 {
4328    EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
4329    EINA_SAFETY_ON_NULL_RETURN_VAL(compare, EINA_FALSE);
4330    EINA_MODEL_TYPE_CALL(model, child_sort, compare);
4331    _eina_model_event_callback_call
4332      (model, _eina_model_str_children_changed, NULL);
4333    return EINA_TRUE;
4334 }
4335
4336 EAPI Eina_Iterator *
4337 eina_model_child_iterator_get(Eina_Model *model)
4338 {
4339    int count;
4340    EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
4341    count = eina_model_child_count(model);
4342    if (count < 0)
4343      return NULL;
4344    EINA_MODEL_TYPE_CALL_RETURN(model, child_iterator_get, NULL, 0, count);
4345 }
4346
4347 EAPI Eina_Iterator *
4348 eina_model_child_slice_iterator_get(Eina_Model *model, unsigned int start, unsigned int count)
4349 {
4350    EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
4351    EINA_MODEL_TYPE_CALL_RETURN(model, child_iterator_get, NULL, start, count);
4352 }
4353
4354 EAPI Eina_Iterator *
4355 eina_model_child_reversed_iterator_get(Eina_Model *model)
4356 {
4357    int count;
4358    EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
4359    count = eina_model_child_count(model);
4360    if (count < 0)
4361      return NULL;
4362    EINA_MODEL_TYPE_CALL_RETURN(model, child_reversed_iterator_get, NULL,
4363                                0, count);
4364 }
4365
4366 EAPI Eina_Iterator *
4367 eina_model_child_slice_reversed_iterator_get(Eina_Model *model, unsigned int start, unsigned int count)
4368 {
4369    EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
4370    EINA_MODEL_TYPE_CALL_RETURN(model, child_reversed_iterator_get, NULL,
4371                                start, count);
4372 }
4373
4374 EAPI Eina_Iterator *
4375 eina_model_child_sorted_iterator_get(Eina_Model *model, Eina_Compare_Cb compare)
4376 {
4377    int count;
4378    EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
4379    EINA_SAFETY_ON_NULL_RETURN_VAL(compare, NULL);
4380    count = eina_model_child_count(model);
4381    if (count < 0)
4382      return NULL;
4383    EINA_MODEL_TYPE_CALL_RETURN(model, child_sorted_iterator_get, NULL,
4384                                0, count, compare);
4385 }
4386
4387 EAPI Eina_Iterator *
4388 eina_model_child_slice_sorted_iterator_get(Eina_Model *model, unsigned int start, unsigned int count, Eina_Compare_Cb compare)
4389 {
4390    EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
4391    EINA_SAFETY_ON_NULL_RETURN_VAL(compare, NULL);
4392    EINA_MODEL_TYPE_CALL_RETURN(model, child_sorted_iterator_get, NULL,
4393                                start, count, compare);
4394 }
4395
4396 EAPI Eina_Iterator *
4397 eina_model_child_filtered_iterator_get(Eina_Model *model, Eina_Each_Cb match, const void *data)
4398 {
4399    int count;
4400    EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
4401    EINA_SAFETY_ON_NULL_RETURN_VAL(match, NULL);
4402    count = eina_model_child_count(model);
4403    if (count < 0)
4404      return NULL;
4405    EINA_MODEL_TYPE_CALL_RETURN(model, child_filtered_iterator_get, NULL,
4406                                0, count, match, data);
4407 }
4408
4409 EAPI Eina_Iterator *
4410 eina_model_child_slice_filtered_iterator_get(Eina_Model *model, unsigned int start, unsigned int count, Eina_Each_Cb match, const void *data)
4411 {
4412    EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
4413    EINA_SAFETY_ON_NULL_RETURN_VAL(match, NULL);
4414    EINA_MODEL_TYPE_CALL_RETURN(model, child_filtered_iterator_get, NULL,
4415                                start, count, match, data);
4416 }
4417
4418 EAPI char *
4419 eina_model_to_string(const Eina_Model *model)
4420 {
4421    EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
4422    EINA_MODEL_TYPE_CALL_RETURN(model, to_string, NULL);
4423 }
4424
4425 /* type functions *****************************************************/
4426
4427 EAPI Eina_Bool
4428 eina_model_type_check(const Eina_Model_Type *type)
4429 {
4430    EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE);
4431    return _eina_model_type_check(type);
4432 }
4433
4434 EAPI const char *
4435 eina_model_type_name_get(const Eina_Model_Type *type)
4436 {
4437    EINA_SAFETY_ON_NULL_RETURN_VAL(type, NULL);
4438    EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), NULL);
4439    return type->name;
4440 }
4441
4442 EAPI const Eina_Model_Type *
4443 eina_model_type_parent_get(const Eina_Model_Type *type)
4444 {
4445    EINA_SAFETY_ON_NULL_RETURN_VAL(type, NULL);
4446    EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), NULL);
4447    return type->parent;
4448 }
4449
4450 #define EINA_MODEL_TYPE_INSTANCE_CHECK(type, model)                     \
4451   EINA_SAFETY_ON_NULL_RETURN(type);                                     \
4452   EINA_SAFETY_ON_FALSE_RETURN(_eina_model_type_check(type));            \
4453   EINA_MODEL_INSTANCE_CHECK(model);                                     \
4454   EINA_SAFETY_ON_FALSE_RETURN(_eina_model_instance_check(model, type));
4455
4456 #define EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, retval)         \
4457   EINA_SAFETY_ON_NULL_RETURN_VAL(type, retval);                         \
4458   EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), retval); \
4459   EINA_MODEL_INSTANCE_CHECK_VAL(model, retval);                         \
4460   EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_instance_check(model, type), retval);
4461
4462 EAPI Eina_Bool
4463 eina_model_type_constructor(const Eina_Model_Type *type, Eina_Model *model)
4464 {
4465    Eina_Bool (*constructor)(Eina_Model *);
4466
4467    EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE);
4468
4469    constructor = _eina_model_type_find_offset
4470      (type, offsetof(Eina_Model_Type, constructor));
4471    EINA_SAFETY_ON_NULL_RETURN_VAL(constructor, EINA_FALSE);
4472
4473    return constructor(model);
4474 }
4475
4476 EAPI Eina_Bool
4477 eina_model_type_destructor(const Eina_Model_Type *type, Eina_Model *model)
4478 {
4479    Eina_Bool (*destructor)(Eina_Model *);
4480
4481    EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE);
4482
4483    destructor = _eina_model_type_find_offset
4484      (type, offsetof(Eina_Model_Type, destructor));
4485    EINA_SAFETY_ON_NULL_RETURN_VAL(destructor, EINA_FALSE);
4486
4487    return destructor(model);
4488 }
4489
4490 EAPI Eina_Bool
4491 eina_model_type_copy(const Eina_Model_Type *type, const Eina_Model *src, Eina_Model *dst)
4492 {
4493    Eina_Bool (*copy)(const Eina_Model *, Eina_Model *);
4494
4495    EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, src, EINA_FALSE);
4496    EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, dst, EINA_FALSE);
4497
4498    copy = _eina_model_type_find_offset
4499      (type, offsetof(Eina_Model_Type, copy));
4500    EINA_SAFETY_ON_NULL_RETURN_VAL(copy, EINA_FALSE);
4501
4502    return copy(src, dst);
4503 }
4504
4505 EAPI Eina_Bool
4506 eina_model_type_deep_copy(const Eina_Model_Type *type, const Eina_Model *src, Eina_Model *dst)
4507 {
4508    Eina_Bool (*deep_copy)(const Eina_Model *, Eina_Model *);
4509
4510    EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, src, EINA_FALSE);
4511    EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, dst, EINA_FALSE);
4512
4513    deep_copy = _eina_model_type_find_offset
4514      (type, offsetof(Eina_Model_Type, deep_copy));
4515    EINA_SAFETY_ON_NULL_RETURN_VAL(deep_copy, EINA_FALSE);
4516
4517    return deep_copy(src, dst);
4518 }
4519
4520 EAPI Eina_Bool
4521 eina_model_type_compare(const Eina_Model_Type *type, const Eina_Model *a, const Eina_Model *b, int *cmp)
4522 {
4523    Eina_Bool (*compare)(const Eina_Model *, const Eina_Model *, int *);
4524
4525    EINA_SAFETY_ON_NULL_RETURN_VAL(cmp, EINA_FALSE);
4526    *cmp = 0;
4527
4528    EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, a, EINA_FALSE);
4529    EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, b, EINA_FALSE);
4530
4531    compare = _eina_model_type_find_offset
4532      (type, offsetof(Eina_Model_Type, compare));
4533    EINA_SAFETY_ON_NULL_RETURN_VAL(compare, EINA_FALSE);
4534
4535    return compare(a, b, cmp);
4536 }
4537
4538 EAPI Eina_Bool
4539 eina_model_type_load(const Eina_Model_Type *type, Eina_Model *model)
4540 {
4541    Eina_Bool (*load)(Eina_Model *);
4542
4543    EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE);
4544
4545    load = _eina_model_type_find_offset
4546      (type, offsetof(Eina_Model_Type, load));
4547    EINA_SAFETY_ON_NULL_RETURN_VAL(load, EINA_FALSE);
4548
4549    return load(model);
4550 }
4551
4552 EAPI Eina_Bool
4553 eina_model_type_unload(const Eina_Model_Type *type, Eina_Model *model)
4554 {
4555    Eina_Bool (*unload)(Eina_Model *);
4556
4557    EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE);
4558
4559    unload = _eina_model_type_find_offset
4560      (type, offsetof(Eina_Model_Type, unload));
4561    EINA_SAFETY_ON_NULL_RETURN_VAL(unload, EINA_FALSE);
4562
4563    return unload(model);
4564 }
4565
4566 EAPI Eina_Bool
4567 eina_model_type_property_get(const Eina_Model_Type *type, const Eina_Model *model, const char *name, Eina_Value *value)
4568 {
4569    Eina_Bool (*property_get)(const Eina_Model *, const char *, Eina_Value *);
4570
4571    EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
4572    EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
4573
4574    EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE);
4575
4576    property_get = _eina_model_type_find_offset
4577      (type, offsetof(Eina_Model_Type, property_get));
4578    EINA_SAFETY_ON_NULL_RETURN_VAL(property_get, EINA_FALSE);
4579
4580    return property_get(model, name, value);
4581 }
4582
4583 EAPI Eina_Bool
4584 eina_model_type_property_set(const Eina_Model_Type *type, Eina_Model *model, const char *name, const Eina_Value *value)
4585 {
4586    Eina_Bool (*property_set)(Eina_Model *, const char *, const Eina_Value *);
4587
4588    EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
4589    EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
4590    EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_type_check(value->type), EINA_FALSE);
4591
4592    EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE);
4593
4594    property_set = _eina_model_type_find_offset
4595      (type, offsetof(Eina_Model_Type, property_set));
4596    EINA_SAFETY_ON_NULL_RETURN_VAL(property_set, EINA_FALSE);
4597
4598    return property_set(model, name, value);
4599 }
4600
4601 EAPI Eina_Bool
4602 eina_model_type_property_del(const Eina_Model_Type *type, Eina_Model *model, const char *name)
4603 {
4604    Eina_Bool (*property_del)(const Eina_Model *, const char *);
4605
4606    EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
4607    EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE);
4608
4609    property_del = _eina_model_type_find_offset
4610      (type, offsetof(Eina_Model_Type, property_del));
4611    EINA_SAFETY_ON_NULL_RETURN_VAL(property_del, EINA_FALSE);
4612
4613    return property_del(model, name);
4614 }
4615
4616 EAPI Eina_List *
4617 eina_model_type_properties_names_list_get(const Eina_Model_Type *type, const Eina_Model *model)
4618 {
4619    Eina_List *(*properties_names_list_get)(const Eina_Model *);
4620
4621    EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL);
4622
4623    properties_names_list_get = _eina_model_type_find_offset
4624      (type, offsetof(Eina_Model_Type, properties_names_list_get));
4625    EINA_SAFETY_ON_NULL_RETURN_VAL(properties_names_list_get, NULL);
4626
4627    return properties_names_list_get(model);
4628 }
4629
4630 EAPI int
4631 eina_model_type_child_count(const Eina_Model_Type *type, const Eina_Model *model)
4632 {
4633    int (*child_count)(const Eina_Model *);
4634
4635    EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, -1);
4636
4637    child_count = _eina_model_type_find_offset
4638      (type, offsetof(Eina_Model_Type, child_count));
4639    EINA_SAFETY_ON_NULL_RETURN_VAL(child_count, -1);
4640
4641    return child_count(model);
4642 }
4643
4644 EAPI Eina_Model *
4645 eina_model_type_child_get(const Eina_Model_Type *type, const Eina_Model *model, unsigned int position)
4646 {
4647    Eina_Model *(*child_get)(const Eina_Model *, unsigned int);
4648
4649    EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL);
4650
4651    child_get = _eina_model_type_find_offset
4652      (type, offsetof(Eina_Model_Type, child_get));
4653    EINA_SAFETY_ON_NULL_RETURN_VAL(child_get, NULL);
4654
4655    return child_get(model, position);
4656 }
4657
4658 EAPI Eina_Bool
4659 eina_model_type_child_set(const Eina_Model_Type *type, Eina_Model *model, unsigned int position, Eina_Model *child)
4660 {
4661    Eina_Bool (*child_set)(Eina_Model *, unsigned int, Eina_Model *);
4662
4663    EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE);
4664    EINA_MODEL_INSTANCE_CHECK_VAL(child, EINA_FALSE);
4665
4666    child_set = _eina_model_type_find_offset
4667      (type, offsetof(Eina_Model_Type, child_set));
4668    EINA_SAFETY_ON_NULL_RETURN_VAL(child_set, EINA_FALSE);
4669
4670    return child_set(model, position, child);
4671 }
4672
4673 EAPI Eina_Bool
4674 eina_model_type_child_del(const Eina_Model_Type *type, Eina_Model *model, unsigned int position)
4675 {
4676    Eina_Bool (*child_del)(Eina_Model *, unsigned int);
4677
4678    EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE);
4679
4680    child_del = _eina_model_type_find_offset
4681      (type, offsetof(Eina_Model_Type, child_del));
4682    EINA_SAFETY_ON_NULL_RETURN_VAL(child_del, EINA_FALSE);
4683
4684    return child_del(model, position);
4685 }
4686
4687 EAPI Eina_Bool
4688 eina_model_type_child_insert_at(const Eina_Model_Type *type, Eina_Model *model, unsigned int position, Eina_Model *child)
4689 {
4690    Eina_Bool (*child_insert_at)(Eina_Model *, unsigned int, Eina_Model *);
4691
4692    EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE);
4693    EINA_MODEL_INSTANCE_CHECK_VAL(child, EINA_FALSE);
4694
4695    child_insert_at = _eina_model_type_find_offset
4696      (type, offsetof(Eina_Model_Type, child_insert_at));
4697    EINA_SAFETY_ON_NULL_RETURN_VAL(child_insert_at, EINA_FALSE);
4698
4699    return child_insert_at(model, position, child);
4700 }
4701
4702 EAPI int
4703 eina_model_type_child_find(const Eina_Model_Type *type, const Eina_Model *model, unsigned int start_position, const Eina_Model *other)
4704 {
4705    int (*child_find)(const Eina_Model *, unsigned int, const Eina_Model *);
4706
4707    EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, -1);
4708    EINA_MODEL_INSTANCE_CHECK_VAL(other, -1);
4709
4710    child_find = _eina_model_type_find_offset
4711      (type, offsetof(Eina_Model_Type, child_find));
4712    EINA_SAFETY_ON_NULL_RETURN_VAL(child_find, -1);
4713
4714    return child_find(model, start_position, other);
4715 }
4716
4717 EAPI int
4718 eina_model_type_child_criteria_match(const Eina_Model_Type *type, const Eina_Model *model, unsigned int start_position, Eina_Each_Cb match, const void *data)
4719 {
4720    int (*child_criteria_match)(const Eina_Model *, unsigned int, Eina_Each_Cb, const void *);
4721
4722    EINA_SAFETY_ON_NULL_RETURN_VAL(match, -1);
4723    EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, -1);
4724
4725    child_criteria_match = _eina_model_type_find_offset
4726      (type, offsetof(Eina_Model_Type, child_criteria_match));
4727    EINA_SAFETY_ON_NULL_RETURN_VAL(child_criteria_match, -1);
4728
4729    return child_criteria_match(model, start_position, match, data);
4730 }
4731
4732 EAPI void
4733 eina_model_type_child_sort(const Eina_Model_Type *type, Eina_Model *model, Eina_Compare_Cb compare)
4734 {
4735    void (*child_sort)(Eina_Model *, Eina_Compare_Cb);
4736
4737    EINA_SAFETY_ON_NULL_RETURN(compare);
4738    EINA_MODEL_TYPE_INSTANCE_CHECK(type, model);
4739
4740    child_sort = _eina_model_type_find_offset
4741      (type, offsetof(Eina_Model_Type, child_sort));
4742    EINA_SAFETY_ON_NULL_RETURN(child_sort);
4743
4744    return child_sort(model, compare);
4745 }
4746
4747 EAPI Eina_Iterator *
4748 eina_model_type_child_iterator_get(const Eina_Model_Type *type, Eina_Model *model, unsigned int start, unsigned int count)
4749 {
4750    Eina_Iterator *(*child_iterator_get)(const Eina_Model *, unsigned int, unsigned int);
4751
4752    EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL);
4753
4754    child_iterator_get = _eina_model_type_find_offset
4755      (type, offsetof(Eina_Model_Type, child_iterator_get));
4756    EINA_SAFETY_ON_NULL_RETURN_VAL(child_iterator_get, NULL);
4757
4758    return child_iterator_get(model, start, count);
4759 }
4760
4761 EAPI Eina_Iterator *
4762 eina_model_type_child_reversed_iterator_get(const Eina_Model_Type *type, Eina_Model *model, unsigned int start, unsigned int count)
4763 {
4764    Eina_Iterator *(*child_reversed_iterator_get)(const Eina_Model *, unsigned int, unsigned int);
4765
4766    EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL);
4767
4768    child_reversed_iterator_get = _eina_model_type_find_offset
4769      (type, offsetof(Eina_Model_Type, child_reversed_iterator_get));
4770    EINA_SAFETY_ON_NULL_RETURN_VAL(child_reversed_iterator_get, NULL);
4771
4772    return child_reversed_iterator_get(model, start, count);
4773 }
4774
4775 EAPI Eina_Iterator *
4776 eina_model_type_child_sorted_iterator_get(const Eina_Model_Type *type, Eina_Model *model, unsigned int start, unsigned int count, Eina_Compare_Cb compare)
4777 {
4778    Eina_Iterator *(*child_sorted_iterator_get)(const Eina_Model *, unsigned int, unsigned int, Eina_Compare_Cb);
4779
4780    EINA_SAFETY_ON_NULL_RETURN_VAL(compare, NULL);
4781    EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL);
4782
4783    child_sorted_iterator_get = _eina_model_type_find_offset
4784      (type, offsetof(Eina_Model_Type, child_sorted_iterator_get));
4785    EINA_SAFETY_ON_NULL_RETURN_VAL(child_sorted_iterator_get, NULL);
4786
4787    return child_sorted_iterator_get(model, start, count, compare);
4788 }
4789
4790 EAPI Eina_Iterator *
4791 eina_model_type_child_filtered_iterator_get(const Eina_Model_Type *type, Eina_Model *model, unsigned int start, unsigned int count, Eina_Each_Cb match, const void *data)
4792 {
4793    Eina_Iterator *(*child_filtered_iterator_get)(const Eina_Model *, unsigned int, unsigned int, Eina_Each_Cb, const void *);
4794
4795    EINA_SAFETY_ON_NULL_RETURN_VAL(match, NULL);
4796    EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL);
4797
4798    child_filtered_iterator_get = _eina_model_type_find_offset
4799      (type, offsetof(Eina_Model_Type, child_filtered_iterator_get));
4800    EINA_SAFETY_ON_NULL_RETURN_VAL(child_filtered_iterator_get, NULL);
4801
4802    return child_filtered_iterator_get(model, start, count, match, data);
4803 }
4804
4805 EAPI char *
4806 eina_model_type_to_string(const Eina_Model_Type *type, const Eina_Model *model)
4807 {
4808    char *(*to_string)(const Eina_Model *);
4809
4810    EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL);
4811
4812    to_string = _eina_model_type_find_offset
4813      (type, offsetof(Eina_Model_Type, to_string));
4814    EINA_SAFETY_ON_NULL_RETURN_VAL(to_string, NULL);
4815
4816    return to_string(model);
4817 }
4818
4819 EAPI Eina_Bool
4820 eina_model_type_subclass_setup(Eina_Model_Type *type, const Eina_Model_Type *parent)
4821 {
4822    EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE);
4823    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, EINA_FALSE);
4824    EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(parent), EINA_FALSE);
4825    EINA_SAFETY_ON_FALSE_RETURN_VAL(type->version == EINA_MODEL_TYPE_VERSION,
4826                                    EINA_FALSE);
4827
4828    type->parent = parent;
4829    type->type_size = parent->type_size;
4830    type->interfaces = NULL;
4831    type->events = NULL;
4832
4833    type->setup = NULL;
4834    type->flush = NULL;
4835    type->constructor = NULL;
4836    type->destructor = NULL;
4837    type->copy = NULL;
4838    type->deep_copy = NULL;
4839    type->compare = NULL;
4840    type->load = NULL;
4841    type->unload = NULL;
4842    type->property_get = NULL;
4843    type->property_set = NULL;
4844    type->property_del = NULL;
4845    type->properties_names_list_get = NULL;
4846    type->child_count = NULL;
4847    type->child_get = NULL;
4848    type->child_set = NULL;
4849    type->child_del = NULL;
4850    type->child_insert_at = NULL;
4851    type->child_find = NULL;
4852    type->child_criteria_match = NULL;
4853    type->child_sort = NULL;
4854    type->child_iterator_get = NULL;
4855    type->child_reversed_iterator_get = NULL;
4856    type->child_sorted_iterator_get = NULL;
4857    type->child_filtered_iterator_get = NULL;
4858    type->to_string = NULL;
4859    type->__extension_ptr0 = NULL;
4860    type->__extension_ptr1 = NULL;
4861    type->__extension_ptr2 = NULL;
4862    type->__extension_ptr3 = NULL;
4863
4864    if (type->type_size > sizeof(Eina_Model_Type))
4865      {
4866         unsigned char *p = (unsigned char *)type;
4867         p += sizeof(Eina_Model_Type);
4868         memset(p, 0, type->type_size - sizeof(Eina_Model_Type));
4869      }
4870
4871    return EINA_TRUE;
4872 }
4873
4874 EAPI Eina_Bool
4875 eina_model_type_subclass_check(const Eina_Model_Type *type, const Eina_Model_Type *self_or_parent)
4876 {
4877    EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE);
4878    EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), EINA_FALSE);
4879    EINA_SAFETY_ON_NULL_RETURN_VAL(self_or_parent, EINA_FALSE);
4880
4881    for (; type != NULL; type = type->parent)
4882      {
4883         if (type == self_or_parent)
4884           return EINA_TRUE;
4885      }
4886
4887    return EINA_FALSE;
4888 }
4889
4890 static inline const Eina_Model_Interface *
4891 _eina_model_type_interface_get(const Eina_Model_Type *type, const char *name, Eina_Bool ptr_cmp __UNUSED__)
4892 {
4893    const Eina_Model_Interface **itr;
4894
4895    if (!type)
4896      return NULL;
4897
4898    if (!type->interfaces)
4899      return _eina_model_type_interface_get(type->parent, name, ptr_cmp);
4900
4901      {
4902         for (itr = type->interfaces ; itr != NULL ; itr++)
4903           if (strcmp((*itr)->name, name) == 0)
4904             return *itr;
4905      }
4906
4907    return NULL;
4908 }
4909
4910 static inline Eina_Bool
4911 _eina_model_interface_check(const Eina_Model_Interface *iface)
4912 {
4913    EINA_SAFETY_ON_FALSE_RETURN_VAL
4914      (iface->version == EINA_MODEL_INTERFACE_VERSION, EINA_FALSE);
4915    return EINA_TRUE;
4916 }
4917
4918 EAPI const Eina_Model_Interface *
4919 eina_model_type_interface_get(const Eina_Model_Type *type, const char *name)
4920 {
4921    const Eina_Model_Interface *iface;
4922
4923    EINA_SAFETY_ON_NULL_RETURN_VAL(type, NULL);
4924    EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), NULL);
4925
4926    /* search for pointer, make speed-aware users fast */
4927    iface = _eina_model_type_interface_get(type, name, EINA_TRUE);
4928
4929    if (!iface)
4930      {
4931         /* search using strcmp(), slow users don't care */
4932         iface = _eina_model_type_interface_get(type, name, EINA_FALSE);
4933      }
4934    else if (!_eina_model_interface_check(iface))
4935      iface = NULL;
4936
4937    return iface;
4938 }
4939
4940 EAPI void *
4941 eina_model_type_private_data_get(const Eina_Model *model, const Eina_Model_Type *type)
4942 {
4943    const Eina_Model_Description *desc;
4944    unsigned int i;
4945
4946    EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
4947    EINA_SAFETY_ON_NULL_RETURN_VAL(type, NULL);
4948    EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), NULL);
4949
4950    desc = model->desc;
4951
4952    for (i = 0; i < desc->total.types; i++)
4953      if (desc->cache.types[i] == type)
4954        return model->privates[i];
4955
4956    CRITICAL("Model %p (%s) is not an instance of type %p (%s)",
4957             model, desc->cache.types[0]->name,
4958             type, type->name);
4959    return NULL;
4960 }
4961
4962 EAPI const void *
4963 eina_model_method_offset_resolve(const Eina_Model *model, unsigned int offset)
4964 {
4965    const Eina_Model_Description *desc;
4966
4967    EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
4968    EINA_SAFETY_ON_FALSE_RETURN_VAL(offset >= sizeof(Eina_Model_Type), NULL);
4969    EINA_SAFETY_ON_FALSE_RETURN_VAL(offset % sizeof(void *) == 0, NULL);
4970
4971    desc = model->desc;
4972    EINA_SAFETY_ON_FALSE_RETURN_VAL
4973      (offset + sizeof(void *) <= desc->cache.types[0]->type_size, NULL);
4974
4975    offset -= sizeof(Eina_Model_Type);
4976    offset /= sizeof(void *);
4977    return desc->ops.type.extension[offset];
4978 }
4979
4980 EAPI const void *
4981 eina_model_type_method_offset_resolve(const Eina_Model_Type *type, const Eina_Model *model, unsigned int offset)
4982 {
4983    const Eina_Model_Description *desc;
4984
4985    EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL);
4986    EINA_SAFETY_ON_FALSE_RETURN_VAL(offset >= sizeof(Eina_Model_Type), NULL);
4987    EINA_SAFETY_ON_FALSE_RETURN_VAL(offset % sizeof(void *) == 0, NULL);
4988
4989    desc = model->desc;
4990    EINA_SAFETY_ON_FALSE_RETURN_VAL
4991      (offset + sizeof(void *) <= desc->cache.types[0]->type_size, NULL);
4992
4993    return _eina_model_type_find_offset(type, offset);
4994 }
4995
4996 /* interface functions ************************************************/
4997
4998 EAPI Eina_Bool
4999 eina_model_interface_check(const Eina_Model_Interface *iface)
5000 {
5001    EINA_SAFETY_ON_NULL_RETURN_VAL(iface, EINA_FALSE);
5002    return _eina_model_interface_check(iface);
5003 }
5004
5005 EAPI void *
5006 eina_model_interface_private_data_get(const Eina_Model *model, const Eina_Model_Interface *iface)
5007 {
5008    const Eina_Model_Description *desc;
5009    unsigned int i;
5010
5011    EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
5012    EINA_SAFETY_ON_NULL_RETURN_VAL(iface, NULL);
5013    EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_interface_check(iface), NULL);
5014
5015    desc = model->desc;
5016
5017    for (i = 0; i < desc->total.ifaces; i++)
5018      if (desc->cache.ifaces[i] == iface)
5019        return model->privates[desc->total.types + i];
5020
5021    CRITICAL("Model %p (%s) does not implement interface %p (%s)",
5022             model, desc->cache.types[0]->name,
5023             iface, iface->name);
5024    return NULL;
5025 }
5026
5027 static Eina_Bool
5028 _eina_model_interface_implemented(const Eina_Model *model, const Eina_Model_Interface *iface)
5029 {
5030    const Eina_Model_Interface **itr, **itr_end;
5031
5032    itr = model->desc->cache.ifaces;
5033    itr_end = itr + model->desc->total.ifaces;
5034
5035    for (; itr < itr_end; itr++)
5036      if (*itr == iface)
5037        return EINA_TRUE;
5038
5039    return EINA_FALSE;
5040 }
5041
5042 EAPI Eina_Bool
5043 eina_model_interface_implemented(const Eina_Model *model, const Eina_Model_Interface *iface)
5044 {
5045    EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
5046    EINA_SAFETY_ON_NULL_RETURN_VAL(iface, EINA_FALSE);
5047    EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_interface_check(iface),
5048                                    EINA_FALSE);
5049    return _eina_model_interface_implemented(model, iface);
5050 }
5051
5052 #define EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK(iface, model)            \
5053   EINA_SAFETY_ON_NULL_RETURN(iface);                                    \
5054   EINA_SAFETY_ON_FALSE_RETURN(_eina_model_interface_check(iface));      \
5055   EINA_MODEL_INSTANCE_CHECK(model);                                     \
5056   EINA_SAFETY_ON_FALSE_RETURN(_eina_model_interface_implemented(model, iface));
5057
5058 #define EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, retval) \
5059   EINA_SAFETY_ON_NULL_RETURN_VAL(iface, retval);                        \
5060   EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_interface_check(iface), retval); \
5061   EINA_MODEL_INSTANCE_CHECK_VAL(model, retval);                         \
5062   EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_interface_implemented(model, iface), retval);
5063
5064
5065 EAPI Eina_Bool
5066 eina_model_interface_constructor(const Eina_Model_Interface *iface, Eina_Model *model)
5067 {
5068    Eina_Bool (*constructor)(Eina_Model *);
5069
5070    EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
5071
5072    constructor = _eina_model_interface_find_offset
5073      (iface, offsetof(Eina_Model_Interface, constructor));
5074    EINA_SAFETY_ON_NULL_RETURN_VAL(constructor, EINA_FALSE);
5075    return constructor(model);
5076 }
5077
5078 EAPI Eina_Bool
5079 eina_model_interface_destructor(const Eina_Model_Interface *iface, Eina_Model *model)
5080 {
5081    Eina_Bool (*destructor)(Eina_Model *);
5082
5083    EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
5084
5085    destructor = _eina_model_interface_find_offset
5086      (iface, offsetof(Eina_Model_Interface, destructor));
5087    EINA_SAFETY_ON_NULL_RETURN_VAL(destructor, EINA_FALSE);
5088    return destructor(model);
5089 }
5090
5091 EAPI Eina_Bool
5092 eina_model_interface_copy(const Eina_Model_Interface *iface, const Eina_Model *src, Eina_Model *dst)
5093 {
5094    Eina_Bool (*copy)(const Eina_Model *, Eina_Model *);
5095
5096    EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, src, EINA_FALSE);
5097    EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, dst, EINA_FALSE);
5098
5099    copy = _eina_model_interface_find_offset
5100      (iface, offsetof(Eina_Model_Interface, copy));
5101    EINA_SAFETY_ON_NULL_RETURN_VAL(copy, EINA_FALSE);
5102    return copy(src, dst);
5103 }
5104
5105 EAPI Eina_Bool
5106 eina_model_interface_deep_copy(const Eina_Model_Interface *iface, const Eina_Model *src, Eina_Model *dst)
5107 {
5108    Eina_Bool (*deep_copy)(const Eina_Model *, Eina_Model *);
5109
5110    EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, src, EINA_FALSE);
5111    EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, dst, EINA_FALSE);
5112
5113    deep_copy = _eina_model_interface_find_offset
5114      (iface, offsetof(Eina_Model_Interface, deep_copy));
5115    EINA_SAFETY_ON_NULL_RETURN_VAL(deep_copy, EINA_FALSE);
5116    return deep_copy(src, dst);
5117 }
5118
5119 EAPI const void
5120 *eina_model_interface_method_offset_resolve(const Eina_Model_Interface *iface, const Eina_Model *model, unsigned int offset)
5121 {
5122    EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, NULL);
5123    EINA_SAFETY_ON_FALSE_RETURN_VAL(offset >= sizeof(Eina_Model_Interface), NULL);
5124    EINA_SAFETY_ON_FALSE_RETURN_VAL(offset % sizeof(void *) == 0, NULL);
5125    return _eina_model_interface_find_offset(iface, offset);
5126 }
5127
5128
5129 /* Eina_Model_Interface_Properties ************************************/
5130
5131 EAPI Eina_Bool
5132 eina_model_interface_properties_compare(const Eina_Model_Interface *iface, const Eina_Model *a, const Eina_Model *b, int *cmp)
5133 {
5134    Eina_Bool (*compare)(const Eina_Model *, const Eina_Model *, int *cmp);
5135
5136    EINA_SAFETY_ON_NULL_RETURN_VAL(cmp, EINA_FALSE);
5137
5138    *cmp = 0;
5139    EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, a, EINA_FALSE);
5140    EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, b, EINA_FALSE);
5141
5142    compare = _eina_model_interface_find_offset
5143      (iface, offsetof(Eina_Model_Interface_Properties, compare));
5144    EINA_SAFETY_ON_NULL_RETURN_VAL(compare, EINA_FALSE);
5145    return compare(a, b, cmp);
5146 }
5147
5148 EAPI Eina_Bool
5149 eina_model_interface_properties_load(const Eina_Model_Interface *iface, Eina_Model *model)
5150 {
5151    Eina_Bool (*load)(Eina_Model *);
5152    Eina_Bool ret;
5153
5154    EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
5155
5156    load = _eina_model_interface_find_offset
5157      (iface, offsetof(Eina_Model_Interface_Properties, load));
5158    EINA_SAFETY_ON_NULL_RETURN_VAL(load, EINA_FALSE);
5159    ret = load(model);
5160
5161    if (ret)
5162      _eina_model_event_callback_call
5163        (model, _eina_model_str_properties_loaded, NULL);
5164
5165    return ret;
5166 }
5167
5168 EAPI Eina_Bool
5169 eina_model_interface_properties_unload(const Eina_Model_Interface *iface, Eina_Model *model)
5170 {
5171    Eina_Bool (*unload)(Eina_Model *);
5172    Eina_Bool ret;
5173
5174    EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
5175
5176    unload = _eina_model_interface_find_offset
5177      (iface, offsetof(Eina_Model_Interface_Properties, unload));
5178    EINA_SAFETY_ON_NULL_RETURN_VAL(unload, EINA_FALSE);
5179    ret = unload(model);
5180
5181    if (ret)
5182      _eina_model_event_callback_call
5183        (model, _eina_model_str_properties_unloaded, NULL);
5184
5185    return ret;
5186 }
5187
5188 EAPI Eina_Bool
5189 eina_model_interface_properties_get(const Eina_Model_Interface *iface, const Eina_Model *model, const char *name, Eina_Value *value)
5190 {
5191    Eina_Bool (*get)(const Eina_Model *, const char *, Eina_Value *);
5192
5193    EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
5194    EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
5195    EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
5196
5197    get = _eina_model_interface_find_offset
5198      (iface, offsetof(Eina_Model_Interface_Properties, get));
5199    EINA_SAFETY_ON_NULL_RETURN_VAL(get, EINA_FALSE);
5200    return get(model, name, value);
5201 }
5202
5203 EAPI Eina_Bool
5204 eina_model_interface_properties_set(const Eina_Model_Interface *iface, Eina_Model *model, const char *name, const Eina_Value *value)
5205 {
5206    Eina_Bool (*set)(Eina_Model *, const char *, const Eina_Value *);
5207
5208    EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
5209    EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
5210    EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_type_check(value->type), EINA_FALSE);
5211    EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
5212
5213    set = _eina_model_interface_find_offset
5214      (iface, offsetof(Eina_Model_Interface_Properties, set));
5215    EINA_SAFETY_ON_NULL_RETURN_VAL(set, EINA_FALSE);
5216    return set(model, name, value);
5217 }
5218
5219 EAPI Eina_Bool
5220 eina_model_interface_properties_del(const Eina_Model_Interface *iface, Eina_Model *model, const char *name)
5221 {
5222    Eina_Bool (*del)(Eina_Model *, const char *);
5223
5224    EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
5225    EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
5226
5227    del = _eina_model_interface_find_offset
5228      (iface, offsetof(Eina_Model_Interface_Properties, del));
5229    EINA_SAFETY_ON_NULL_RETURN_VAL(del, EINA_FALSE);
5230    return del(model, name);
5231 }
5232
5233 EAPI Eina_List *
5234 eina_model_interface_properties_names_list_get(const Eina_Model_Interface *iface, const Eina_Model *model)
5235 {
5236    Eina_List *(*names_list_get)(const Eina_Model *);
5237
5238    EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, NULL);
5239
5240    names_list_get = _eina_model_interface_find_offset
5241      (iface, offsetof(Eina_Model_Interface_Properties, names_list_get));
5242    EINA_SAFETY_ON_NULL_RETURN_VAL(names_list_get, NULL);
5243    return names_list_get(model);
5244 }
5245
5246 /* Eina_Model_Interface_Children **************************************/
5247
5248 EAPI Eina_Bool
5249 eina_model_interface_children_compare(const Eina_Model_Interface *iface, const Eina_Model *a, const Eina_Model *b, int *cmp)
5250 {
5251    Eina_Bool (*compare)(const Eina_Model *, const Eina_Model *, int *);
5252
5253    EINA_SAFETY_ON_NULL_RETURN_VAL(cmp, EINA_FALSE);
5254
5255    *cmp = 0;
5256
5257    EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, a, EINA_FALSE);
5258    EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, b, EINA_FALSE);
5259
5260    compare = _eina_model_interface_find_offset
5261      (iface, offsetof(Eina_Model_Interface_Children, compare));
5262    EINA_SAFETY_ON_NULL_RETURN_VAL(compare, EINA_FALSE);
5263    return compare(a, b, cmp);
5264 }
5265
5266 EAPI Eina_Bool
5267 eina_model_interface_children_load(const Eina_Model_Interface *iface, Eina_Model *model)
5268 {
5269    Eina_Bool (*load)(Eina_Model *);
5270    Eina_Bool ret;
5271
5272    EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
5273
5274    load = _eina_model_interface_find_offset
5275      (iface, offsetof(Eina_Model_Interface_Children, load));
5276    EINA_SAFETY_ON_NULL_RETURN_VAL(load, EINA_FALSE);
5277    ret = load(model);
5278
5279    if (ret)
5280      _eina_model_event_callback_call
5281        (model, _eina_model_str_children_loaded, NULL);
5282
5283    return ret;
5284 }
5285
5286 EAPI Eina_Bool
5287 eina_model_interface_children_unload(const Eina_Model_Interface *iface, Eina_Model *model)
5288 {
5289    Eina_Bool (*unload)(Eina_Model *);
5290    Eina_Bool ret;
5291
5292    EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
5293
5294    unload = _eina_model_interface_find_offset
5295      (iface, offsetof(Eina_Model_Interface_Children, unload));
5296    EINA_SAFETY_ON_NULL_RETURN_VAL(unload, EINA_FALSE);
5297    ret = unload(model);
5298
5299    if (ret)
5300      _eina_model_event_callback_call
5301        (model, _eina_model_str_children_unloaded, NULL);
5302
5303    return ret;
5304 }
5305
5306 EAPI int
5307 eina_model_interface_children_count(const Eina_Model_Interface *iface, const Eina_Model *model)
5308 {
5309    int (*count)(const Eina_Model *);
5310
5311    EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, -1);
5312
5313    count = _eina_model_interface_find_offset
5314      (iface, offsetof(Eina_Model_Interface_Children, count));
5315    EINA_SAFETY_ON_NULL_RETURN_VAL(count, -1);
5316    return count(model);
5317 }
5318
5319 EAPI Eina_Model *
5320 eina_model_interface_children_get(const Eina_Model_Interface *iface, const Eina_Model *model, unsigned int position)
5321 {
5322    Eina_Model *(*get)(const Eina_Model *, unsigned int);
5323
5324    EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, NULL);
5325
5326    get = _eina_model_interface_find_offset
5327      (iface, offsetof(Eina_Model_Interface_Children, get));
5328    EINA_SAFETY_ON_NULL_RETURN_VAL(get, NULL);
5329    return get(model, position);
5330 }
5331
5332 EAPI Eina_Bool eina_model_interface_children_set(const Eina_Model_Interface *iface, Eina_Model *model, unsigned int position, Eina_Model *child)
5333 {
5334    Eina_Bool (*set)(const Eina_Model *, unsigned int, Eina_Model *);
5335
5336    EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
5337    EINA_MODEL_INSTANCE_CHECK_VAL(child, EINA_FALSE);
5338
5339    set = _eina_model_interface_find_offset
5340      (iface, offsetof(Eina_Model_Interface_Children, set));
5341    EINA_SAFETY_ON_NULL_RETURN_VAL(set, EINA_FALSE);
5342    return set(model, position, child);
5343 }
5344
5345 EAPI Eina_Bool
5346 eina_model_interface_children_del(const Eina_Model_Interface *iface, Eina_Model *model, unsigned int position)
5347 {
5348    Eina_Bool (*del)(Eina_Model *, unsigned int);
5349
5350    EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
5351
5352    del = _eina_model_interface_find_offset
5353      (iface, offsetof(Eina_Model_Interface_Children, del));
5354    EINA_SAFETY_ON_NULL_RETURN_VAL(del, EINA_FALSE);
5355    return del(model, position);
5356 }
5357
5358
5359 EAPI Eina_Bool
5360 eina_model_interface_children_insert_at(const Eina_Model_Interface *iface, Eina_Model *model, unsigned int position, Eina_Model *child)
5361 {
5362    Eina_Bool (*insert_at)(const Eina_Model *, unsigned int, Eina_Model *);
5363
5364    EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
5365    EINA_MODEL_INSTANCE_CHECK_VAL(child, EINA_FALSE);
5366
5367    insert_at = _eina_model_interface_find_offset
5368      (iface, offsetof(Eina_Model_Interface_Children, insert_at));
5369    EINA_SAFETY_ON_NULL_RETURN_VAL(insert_at, EINA_FALSE);
5370    return insert_at(model, position, child);
5371 }
5372
5373 EAPI void
5374 eina_model_interface_children_sort(const Eina_Model_Interface *iface, Eina_Model *model, Eina_Compare_Cb compare)
5375 {
5376    void (*sort)(const Eina_Model *, Eina_Compare_Cb);
5377
5378    EINA_SAFETY_ON_NULL_RETURN(compare);
5379    EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK(iface, model);
5380
5381    sort = _eina_model_interface_find_offset
5382      (iface, offsetof(Eina_Model_Interface_Children, sort));
5383    EINA_SAFETY_ON_NULL_RETURN(sort);
5384    return sort(model, compare);
5385 }
5386
5387 static Eina_Bool
5388 _eina_model_struct_set(Eina_Model *m, const Eina_Value_Struct_Desc *desc, void *memory)
5389 {
5390    Eina_Value_Struct st = {desc, memory};
5391    Eina_Value *val = eina_model_interface_private_data_get
5392      (m, &_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base);
5393    return eina_value_pset(val, &st);
5394 }
5395
5396 EAPI Eina_Model *
5397 eina_model_struct_new(const Eina_Value_Struct_Desc *desc)
5398 {
5399    Eina_Model *m;
5400
5401    EINA_SAFETY_ON_NULL_RETURN_VAL(desc, NULL);
5402    EINA_SAFETY_ON_FALSE_RETURN_VAL
5403      (desc->version == EINA_VALUE_STRUCT_DESC_VERSION, NULL);
5404
5405    m = eina_model_new(EINA_MODEL_TYPE_STRUCT);
5406    EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
5407
5408    EINA_SAFETY_ON_FALSE_GOTO(_eina_model_struct_set(m, desc, NULL), error);
5409    return m;
5410
5411  error:
5412    eina_model_del(m);
5413    return NULL;
5414 }
5415
5416 EAPI Eina_Model *
5417 eina_model_type_struct_new(const Eina_Model_Type *type, const Eina_Value_Struct_Desc *desc)
5418 {
5419    Eina_Model *m;
5420
5421    EINA_SAFETY_ON_FALSE_RETURN_VAL
5422      (eina_model_type_subclass_check(type, EINA_MODEL_TYPE_STRUCT), NULL);
5423    EINA_SAFETY_ON_NULL_RETURN_VAL(desc, NULL);
5424    EINA_SAFETY_ON_FALSE_RETURN_VAL
5425      (desc->version == EINA_VALUE_STRUCT_DESC_VERSION, NULL);
5426
5427    m = eina_model_new(type);
5428    EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
5429
5430    EINA_SAFETY_ON_FALSE_GOTO(_eina_model_struct_set(m, desc, NULL), error);
5431    return m;
5432
5433  error:
5434    eina_model_del(m);
5435    return NULL;
5436 }
5437
5438 EAPI Eina_Bool
5439 eina_model_struct_set(Eina_Model *model, const Eina_Value_Struct_Desc *desc, void *memory)
5440 {
5441    EINA_SAFETY_ON_NULL_RETURN_VAL(desc, EINA_FALSE);
5442    EINA_SAFETY_ON_FALSE_RETURN_VAL
5443      (desc->version == EINA_VALUE_STRUCT_DESC_VERSION, EINA_FALSE);
5444    EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL
5445      (&_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base, model, EINA_FALSE);
5446
5447    return _eina_model_struct_set(model, desc, memory);
5448 }
5449
5450 EAPI Eina_Bool
5451 eina_model_struct_get(const Eina_Model *model, const Eina_Value_Struct_Desc **p_desc, void **p_memory)
5452 {
5453    const Eina_Value *val;
5454    Eina_Value_Struct st;
5455
5456    EINA_SAFETY_ON_NULL_RETURN_VAL(p_desc, EINA_FALSE);
5457
5458    *p_desc = NULL;
5459    if (p_memory) *p_memory = NULL;
5460
5461    EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL
5462      (&_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base, model, EINA_FALSE);
5463
5464    val = eina_model_interface_private_data_get
5465      (model, &_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base);
5466
5467    EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_pget(val, &st), EINA_FALSE);
5468
5469    *p_desc = st.desc;
5470    if (p_memory) *p_memory = st.memory;
5471    return EINA_FALSE;
5472 }
5473
5474 EAPI void
5475 eina_models_usage_dump(void)
5476 {
5477    const Eina_List *l;
5478    const Eina_Model *m;
5479
5480    eina_lock_take(&_eina_model_debug_list_lock);
5481
5482    puts("DDD: model          refs           info (type, holders, backtrace)");
5483    puts("DDD: -------------- -------------- ---------------------------------");
5484
5485    EINA_LIST_FOREACH(_eina_model_debug_list, l, m)
5486      {
5487         Eina_Model_XRef *ref;
5488
5489         printf("DDD: %14p %14d %s\n",
5490                m, m->refcount, m->desc->cache.types[0]->name);
5491
5492         EINA_INLIST_FOREACH(m->xrefs, ref)
5493           {
5494              printf("DDD:                               id: %p '%s'\n",
5495                     ref->id, ref->label);
5496              if (ref->backtrace.count)
5497                {
5498                   char **symbols;
5499                   unsigned int i;
5500
5501 #ifdef HAVE_BACKTRACE_SYMBOLS
5502                   symbols = backtrace_symbols((void * const *)ref->backtrace.symbols,
5503                                               ref->backtrace.count);
5504 #else
5505                   symbols = NULL;
5506 #endif
5507
5508                   printf("DDD:            Backtrace: Address        Symbol\n");
5509                   for (i = 0; i < ref->backtrace.count; i++)
5510                     printf("DDD:                       %14p %s\n",
5511                            ref->backtrace.symbols[i],
5512                            symbols ? symbols[i] : "???");
5513
5514                   free(symbols);
5515                   puts("DDD:");
5516                }
5517           }
5518      }
5519
5520    eina_lock_release(&_eina_model_debug_list_lock);
5521 }
5522
5523 EAPI Eina_List *
5524 eina_models_list_get(void)
5525 {
5526    const Eina_List *l;
5527    Eina_Model *m;
5528    Eina_List *ret = NULL;
5529
5530    eina_lock_take(&_eina_model_debug_list_lock);
5531
5532    EINA_LIST_FOREACH(_eina_model_debug_list, l, m)
5533      {
5534         ret = eina_list_append
5535           (ret, eina_model_xref
5536            (m, eina_models_list_get, "eina_models_list_get"));
5537      }
5538
5539    eina_lock_release(&_eina_model_debug_list_lock);
5540
5541    return ret;
5542 }
5543
5544 EAPI void
5545 eina_models_list_free(Eina_List *list)
5546 {
5547    Eina_Model *m;
5548
5549    EINA_LIST_FREE(list, m)
5550      eina_model_xunref(m, eina_models_list_get);
5551 }