aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/eina/src/lib/eina_model.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/eina/src/lib/eina_model.c')
-rw-r--r--libraries/eina/src/lib/eina_model.c5548
1 files changed, 5548 insertions, 0 deletions
diff --git a/libraries/eina/src/lib/eina_model.c b/libraries/eina/src/lib/eina_model.c
new file mode 100644
index 0000000..ae06c1b
--- /dev/null
+++ b/libraries/eina/src/lib/eina_model.c
@@ -0,0 +1,5548 @@
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
35extern "C"
36# endif
37void *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
66static Eina_Mempool *_eina_model_mp = NULL;
67static Eina_Hash *_eina_model_inner_mps = NULL;
68static Eina_Lock _eina_model_inner_mps_lock;
69static char *_eina_model_mp_choice = NULL;
70static Eina_Hash *_eina_model_descriptions = NULL;
71static Eina_Lock _eina_model_descriptions_lock;
72static int _eina_model_log_dom = -1;
73static 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;
78static Eina_Lock _eina_model_debug_list_lock;
79static Eina_List *_eina_model_debug_list = NULL;
80
81static const char _eina_model_str_deleted[] = "deleted";
82static const char _eina_model_str_freed[] = "freed";
83static const char _eina_model_str_property_set[] = "property,set";
84static const char _eina_model_str_property_del[] = "property,deleted";
85static const char _eina_model_str_children_changed[] = "children,changed";
86static const char _eina_model_str_child_inserted[] = "child,inserted";
87static const char _eina_model_str_child_set[] = "child,set";
88static const char _eina_model_str_child_del[] = "child,deleted";
89static const char _eina_model_str_loaded[] = "loaded";
90static const char _eina_model_str_unloaded[] = "unloaded";
91static const char _eina_model_str_properties_loaded[] = "properties,loaded";
92static const char _eina_model_str_properties_unloaded[] = "properties,unloaded";
93static const char _eina_model_str_children_loaded[] = "children,loaded";
94static 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 */
125static 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
155static 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 */
184typedef struct _Eina_Model_Inner_Mp Eina_Model_Inner_Mp;
185struct _Eina_Model_Inner_Mp
186{
187 Eina_Mempool *mempool;
188 int refcount;
189};
190
191static 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
201static 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, 128);
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
231static 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
247static 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
260static 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
274static 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
289typedef union _Eina_Model_Provider Eina_Model_Provider;
290union _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 */
297typedef struct _Eina_Model_Event_Description_Cache Eina_Model_Event_Description_Cache;
298struct _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 */
321typedef struct _Eina_Model_Description Eina_Model_Description;
322struct _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
372static 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
506static 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 */
546static 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
665static 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
693static 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
707static 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
753static 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
794static 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
801static 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 */
816static 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
934static 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
972static 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
996static 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
1008static 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
1016static 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 */
1039typedef struct _Eina_Model_Event_Listener Eina_Model_Event_Listener;
1040struct _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
1048struct _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
1064static 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 */
1076static 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 */
1143static 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
1165static 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
1186static 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
1223static const char EINA_ERROR_MODEL_FAILED_STR[] = "Model check failed.";
1224static const char EINA_ERROR_MODEL_METHOD_MISSING_STR[] = "Model method is missing.";
1225static const char EINA_MAGIC_MODEL_STR[] = "Eina Model";
1226
1227static void _eina_model_unref(Eina_Model *model);
1228
1229/**
1230 * @endcond
1231 */
1232
1233/* EINA_MODEL_TYPE_BASE: base of all other types **********************/
1234
1235static 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
1242static 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
1249static 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
1256static 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
1263static 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
1292static 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
1330static 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
1339static 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
1388static 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
1397static 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
1478static 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
1558static 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
1573static 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
1580static 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
1606static 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
1633typedef struct _Eina_Iterator_Model_Base Eina_Iterator_Model_Base;
1634struct _Eina_Iterator_Model_Base
1635{
1636 Eina_Iterator base;
1637 Eina_Model *model;
1638 unsigned int current;
1639 unsigned int end;
1640};
1641
1642static 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
1659static 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
1667static 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
1676static 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
1695typedef struct _Eina_Iterator_Model_Base_Reversed Eina_Iterator_Model_Base_Reversed;
1696struct _Eina_Iterator_Model_Base_Reversed
1697{
1698 Eina_Iterator base;
1699 Eina_Model *model;
1700 unsigned int current;
1701 unsigned int end;
1702};
1703
1704static 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
1721static 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
1729static 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
1738static 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
1771typedef struct _Eina_Iterator_Model_Base_Sorted Eina_Iterator_Model_Base_Sorted;
1772struct _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
1781static 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
1795static 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
1803static 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
1817static 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
1866typedef struct _Eina_Iterator_Model_Base_Filtered Eina_Iterator_Model_Base_Filtered;
1867struct _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
1877static 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
1897static 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
1905static 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
1914static 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
1935static 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
2018static 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
2032static 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
2081static const char _EINA_MODEL_INTERFACE_NAME_PROPERTIES[] = "Eina_Model_Interface_Properties";
2082static const char _EINA_MODEL_INTERFACE_NAME_CHILDREN[] = "Eina_Model_Interface_Children";
2083
2084typedef struct _Eina_Model_Type_Mixin_Data Eina_Model_Type_Mixin_Data;
2085struct _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
2092static 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
2099static 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
2106static 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
2153static 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
2169static 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
2215static 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
2231static 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
2247static 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
2261static 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
2275static 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
2289static 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
2303static 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
2314static 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
2325static 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
2337static 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
2349static 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
2361static 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
2371static 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 */
2413static 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
2425static 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
2438static 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
2456static 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
2467static 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
2474static 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
2492static 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
2501static 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
2543static 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
2553static 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
2561static 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
2572static 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
2603static 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
2615static 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
2627static 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
2646static 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
2657static 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
2672static 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
2680static 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
2688static 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
2694static 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
2722static 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 */
2752static 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
2764static 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_setup(priv, sizeof(Eina_Model *), 0);
2773 return EINA_TRUE;
2774}
2775
2776static 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
2794static 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
2805static 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
2827static 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
2834static 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
2844static 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
2864static 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
2882static 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
2895static 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
2907static 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
2940static 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
2946static 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
2955static 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
2961static 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 */
2982Eina_Bool
2983eina_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), 320);
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 */
3106Eina_Bool
3107eina_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
3148EAPI Eina_Error EINA_ERROR_MODEL_FAILED = 0;
3149EAPI Eina_Error EINA_ERROR_MODEL_METHOD_MISSING = 0;
3150
3151EAPI const Eina_Model_Type *EINA_MODEL_TYPE_BASE = NULL;
3152EAPI const Eina_Model_Type *EINA_MODEL_TYPE_MIXIN = NULL;
3153EAPI const Eina_Model_Type *EINA_MODEL_TYPE_GENERIC = NULL;
3154EAPI const Eina_Model_Type *EINA_MODEL_TYPE_STRUCT = NULL;
3155
3156EAPI const Eina_Model_Interface *EINA_MODEL_INTERFACE_PROPERTIES_HASH = NULL;
3157EAPI const Eina_Model_Interface *EINA_MODEL_INTERFACE_PROPERTIES_STRUCT = NULL;
3158EAPI const Eina_Model_Interface *EINA_MODEL_INTERFACE_CHILDREN_INARRAY = NULL;
3159
3160EAPI const char *EINA_MODEL_INTERFACE_NAME_PROPERTIES = "Eina_Model_Interface_Properties";
3161EAPI const char *EINA_MODEL_INTERFACE_NAME_CHILDREN = "Eina_Model_Interface_Children";
3162
3163EAPI Eina_Model *
3164eina_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
3301static 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
3382static 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
3401static 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
3527EAPI void
3528eina_model_del(Eina_Model *model)
3529{
3530 EINA_MODEL_INSTANCE_CHECK(model);
3531 _eina_model_del(model);
3532 _eina_model_unref(model);
3533}
3534
3535EAPI const Eina_Model_Type *
3536eina_model_type_get(const Eina_Model *model)
3537{
3538 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
3539 return model->desc->cache.types[0];
3540}
3541
3542EAPI const Eina_Model_Interface *
3543eina_model_interface_get(const Eina_Model *model, const char *name)
3544{
3545 const Eina_Model_Description *desc;
3546 const Eina_Model_Interface **itr, **itr_end;
3547
3548 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
3549 EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
3550
3551 desc = model->desc;
3552 itr = desc->cache.ifaces;
3553 itr_end = itr + desc->total.ifaces;
3554
3555 /* fallback to strcmp if user is lazy about speed */
3556 for (; itr < itr_end; itr++)
3557 if (strcmp((*itr)->name, name) == 0)
3558 return *itr;
3559
3560 return NULL;
3561}
3562
3563static Eina_Bool
3564_eina_model_instance_check(const Eina_Model *model, const Eina_Model_Type *type)
3565{
3566 const Eina_Model_Type **itr, **itr_end;
3567
3568 itr = model->desc->cache.types;
3569 itr_end = itr + model->desc->total.types;
3570
3571 for (; itr < itr_end; itr++)
3572 if (*itr == type)
3573 return EINA_TRUE;
3574
3575 return EINA_FALSE;
3576}
3577
3578EAPI Eina_Bool
3579eina_model_instance_check(const Eina_Model *model, const Eina_Model_Type *type)
3580{
3581 EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
3582 EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE);
3583 EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), EINA_FALSE);
3584 return _eina_model_instance_check(model, type);
3585}
3586
3587EAPI Eina_Model *
3588eina_model_ref(Eina_Model *model)
3589{
3590 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
3591 DBG("model %p (%s) refcount=%d deleted=%hhu",
3592 model, model->desc->cache.types[0]->name,
3593 model->refcount, model->deleted);
3594 model->refcount++;
3595 return model;
3596}
3597
3598static Eina_Model *
3599_eina_model_xref_add(Eina_Model *model, const void *id, const char *label)
3600{
3601 Eina_Model_XRef *ref;
3602 void *bt[256];
3603 int btlen, labellen;
3604
3605 labellen = label ? strlen(label): 0;
3606 btlen = 0;
3607
3608#ifdef HAVE_BACKTRACE
3609 if (_eina_model_debug == EINA_MODEL_DEBUG_BACKTRACE)
3610 btlen = backtrace(bt, EINA_C_ARRAY_LENGTH(bt));
3611#endif
3612
3613 ref = calloc(1, sizeof(*ref) + (btlen * sizeof(void *)) + (labellen + 1));
3614 EINA_SAFETY_ON_NULL_RETURN_VAL(ref, NULL);
3615
3616 ref->id = id;
3617 memcpy(ref->label, label, labellen);
3618 ref->label[labellen] = '\0';
3619 ref->backtrace.count = btlen;
3620 if (btlen == 0) ref->backtrace.symbols = NULL;
3621 else
3622 {
3623 void *ptr = (unsigned char *)ref + sizeof(*ref) + (labellen + 1);
3624 ref->backtrace.symbols = ptr;
3625 memcpy(ptr, bt, btlen * sizeof(void *));
3626 }
3627
3628 model->xrefs = eina_inlist_append(model->xrefs, EINA_INLIST_GET(ref));
3629 return model;
3630}
3631
3632EAPI Eina_Model *
3633eina_model_xref(Eina_Model *model, const void *id, const char *label)
3634{
3635 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
3636 DBG("model %p (%s) refcount=%d deleted=%hhu id=%p label=%s",
3637 model, model->desc->cache.types[0]->name,
3638 model->refcount, model->deleted, id, label ? label : "");
3639
3640 model->refcount++;
3641
3642 if (EINA_LIKELY(!_eina_model_debug))
3643 return model;
3644
3645 return _eina_model_xref_add(model, id, label);
3646}
3647
3648EAPI void
3649eina_model_unref(Eina_Model *model)
3650{
3651 EINA_MODEL_INSTANCE_CHECK(model);
3652 _eina_model_unref(model);
3653}
3654
3655EAPI void
3656eina_model_xunref(Eina_Model *model, const void *id)
3657{
3658 Eina_Model_XRef *ref;
3659 EINA_MODEL_INSTANCE_CHECK(model);
3660
3661 if (EINA_LIKELY(!_eina_model_debug))
3662 {
3663 _eina_model_unref(model);
3664 return;
3665 }
3666
3667 EINA_INLIST_FOREACH(model->xrefs, ref)
3668 {
3669 if (ref->id != id) continue;
3670
3671 model->xrefs = eina_inlist_remove(model->xrefs, EINA_INLIST_GET(ref));
3672 free(ref);
3673 _eina_model_unref(model);
3674 return;
3675 }
3676
3677 ERR("Could not find existing reference %p to model %p", id, model);
3678}
3679
3680EAPI int
3681eina_model_refcount(const Eina_Model *model)
3682{
3683 EINA_MODEL_INSTANCE_CHECK_VAL(model, -1);
3684 return model->refcount;
3685}
3686
3687EAPI const Eina_Inlist *
3688eina_model_xrefs_get(const Eina_Model *model)
3689{
3690 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
3691 return model->xrefs;
3692}
3693
3694EAPI Eina_Bool
3695eina_model_event_callback_add(Eina_Model *model, const char *event_name, Eina_Model_Event_Cb cb, const void *data)
3696{
3697 const Eina_Model_Description *desc;
3698 Eina_Model_Event_Listener *el;
3699 int event_id;
3700
3701 EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
3702 EINA_SAFETY_ON_NULL_RETURN_VAL(event_name, EINA_FALSE);
3703 EINA_SAFETY_ON_NULL_RETURN_VAL(cb, EINA_FALSE);
3704
3705 desc = model->desc;
3706 event_id = _eina_model_description_event_id_find(desc, event_name);
3707 if (event_id < 0)
3708 {
3709 ERR("No event named %s for model %p (%s)",
3710 event_name, model, model->desc->cache.types[0]->name);
3711 return EINA_FALSE;
3712 }
3713
3714 if (!model->listeners.entries)
3715 {
3716 model->listeners.entries = _eina_model_inner_alloc
3717 (desc->total.events * sizeof(Eina_Inlist *));
3718 EINA_SAFETY_ON_NULL_RETURN_VAL(model->listeners.entries, EINA_FALSE);
3719 memset(model->listeners.entries, 0,
3720 desc->total.events * sizeof(Eina_Inlist *));
3721 }
3722
3723 el = _eina_model_inner_alloc(sizeof(Eina_Model_Event_Listener));
3724 EINA_SAFETY_ON_NULL_RETURN_VAL(el, EINA_FALSE);
3725
3726 el->cb = cb;
3727 el->data = data;
3728 el->deleted = EINA_FALSE;
3729 model->listeners.entries[event_id] = eina_inlist_append
3730 (model->listeners.entries[event_id], EINA_INLIST_GET(el));
3731
3732 return EINA_TRUE;
3733}
3734
3735EAPI Eina_Bool
3736eina_model_event_callback_del(Eina_Model *model, const char *event_name, Eina_Model_Event_Cb cb, const void *data)
3737{
3738 int event_id;
3739 Eina_Inlist *lst;
3740 Eina_Model_Event_Listener *el;
3741
3742 EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
3743 EINA_SAFETY_ON_NULL_RETURN_VAL(event_name, EINA_FALSE);
3744 EINA_SAFETY_ON_NULL_RETURN_VAL(cb, EINA_FALSE);
3745
3746 if (!model->listeners.entries)
3747 {
3748 ERR("No event callbacks for model %p (%s)",
3749 model, model->desc->cache.types[0]->name);
3750 return EINA_FALSE;
3751 }
3752
3753 event_id = _eina_model_description_event_id_find(model->desc, event_name);
3754 if (event_id < 0)
3755 {
3756 ERR("No event named %s for model %p (%s)",
3757 event_name, model, model->desc->cache.types[0]->name);
3758 return EINA_FALSE;
3759 }
3760
3761 lst = model->listeners.entries[event_id];
3762 EINA_INLIST_FOREACH(lst, el)
3763 {
3764 if (el->cb != cb) continue;
3765 if ((data) && (el->data != data)) continue;
3766
3767 if (model->listeners.walking == 0)
3768 {
3769 model->listeners.entries[event_id] = eina_inlist_remove
3770 (model->listeners.entries[event_id], EINA_INLIST_GET(el));
3771 _eina_model_inner_free(sizeof(Eina_Model_Event_Listener), el);
3772 }
3773 else
3774 {
3775 el->deleted = EINA_TRUE;
3776 if (!model->listeners.deleted)
3777 {
3778 model->listeners.deleted = _eina_model_inner_alloc
3779 (model->desc->total.events * sizeof(Eina_List *));
3780 EINA_SAFETY_ON_NULL_RETURN_VAL(model->listeners.deleted,
3781 EINA_FALSE);
3782
3783 memset(model->listeners.deleted, 0,
3784 model->desc->total.events * sizeof(Eina_List *));
3785
3786 }
3787 model->listeners.deleted[event_id] = eina_list_append
3788 (model->listeners.deleted[event_id], el);
3789 }
3790 return EINA_TRUE;
3791 }
3792
3793 ERR("No callback %p data %p found for event named %s for model %p (%s)",
3794 cb, data, event_name, model, model->desc->cache.types[0]->name);
3795 return EINA_FALSE;
3796}
3797
3798EAPI const Eina_Model_Event_Description *
3799eina_model_event_description_get(const Eina_Model *model, const char *event_name)
3800{
3801 const Eina_Model_Description *desc;
3802 int event_id;
3803
3804 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
3805 EINA_SAFETY_ON_NULL_RETURN_VAL(event_name, NULL);
3806
3807 desc = model->desc;
3808 event_id = _eina_model_description_event_id_find(desc, event_name);
3809 if (event_id < 0)
3810 return NULL;
3811
3812 return desc->cache.events[event_id].desc;
3813}
3814
3815EAPI Eina_List *
3816eina_model_event_names_list_get(const Eina_Model *model)
3817{
3818 const Eina_Model_Event_Description_Cache *itr, *itr_end;
3819 Eina_List *lst = NULL;
3820
3821 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
3822
3823 itr = model->desc->cache.events;
3824 itr_end = itr + model->desc->total.events;
3825
3826 for (; itr < itr_end; itr++)
3827 lst = eina_list_append(lst, eina_stringshare_add(itr->name));
3828
3829 return lst;
3830}
3831
3832EAPI void
3833eina_model_event_names_list_free(Eina_List *list)
3834{
3835 const char *str;
3836 EINA_LIST_FREE(list, str)
3837 eina_stringshare_del(str);
3838}
3839
3840EAPI Eina_Bool
3841eina_model_event_callback_call(Eina_Model *model, const char *name, const void *event_info)
3842{
3843 EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
3844 EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
3845 return _eina_model_event_callback_call(model, name, event_info);
3846}
3847
3848EAPI int
3849eina_model_event_callback_freeze(Eina_Model *model, const char *name)
3850{
3851 int event_id;
3852
3853 EINA_MODEL_INSTANCE_CHECK_VAL(model, -1);
3854 EINA_SAFETY_ON_NULL_RETURN_VAL(name, -1);
3855
3856 event_id = _eina_model_description_event_id_find(model->desc, name);
3857 if (event_id < 0) return -1;
3858
3859 if (!model->listeners.freeze)
3860 {
3861 model->listeners.freeze = _eina_model_inner_alloc
3862 (model->desc->total.events * sizeof(int));
3863 EINA_SAFETY_ON_NULL_RETURN_VAL(model->listeners.freeze, -1);
3864
3865 memset(model->listeners.freeze, 0,
3866 model->desc->total.events * sizeof(int));
3867 }
3868
3869 if (model->listeners.freeze[event_id] == 0)
3870 DBG("model %p (%s) event %s frozen",
3871 model, model->desc->cache.types[0]->name, name);
3872
3873 model->listeners.freeze[event_id]++;
3874 return model->listeners.freeze[event_id];
3875}
3876
3877EAPI int
3878eina_model_event_callback_thaw(Eina_Model *model, const char *name)
3879{
3880 int event_id;
3881
3882 EINA_MODEL_INSTANCE_CHECK_VAL(model, -1);
3883 EINA_SAFETY_ON_NULL_RETURN_VAL(name, -1);
3884 EINA_SAFETY_ON_NULL_RETURN_VAL(model->listeners.freeze, -1);
3885
3886 event_id = _eina_model_description_event_id_find(model->desc, name);
3887 if (event_id < 0) return -1;
3888
3889 model->listeners.freeze[event_id]--;
3890 if (model->listeners.freeze[event_id] == 0)
3891 DBG("model %p (%s) event %s unfrozen",
3892 model, model->desc->cache.types[0]->name, name);
3893 return model->listeners.freeze[event_id];
3894}
3895
3896EAPI Eina_Model *
3897eina_model_copy(const Eina_Model *model)
3898{
3899 const Eina_Model_Description *desc;
3900 Eina_Model *copy;
3901 unsigned int i;
3902
3903 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
3904 desc = model->desc;
3905 copy = eina_model_new(desc->cache.types[0]);
3906 EINA_SAFETY_ON_NULL_RETURN_VAL(copy, NULL);
3907
3908 /* call copy of every type in the reverse order,
3909 * they should not call parent's copy.
3910 */
3911 for (i = desc->total.types; i > 0; i--)
3912 {
3913 if (desc->cache.types[i - 1]->copy)
3914 {
3915 if (!desc->cache.types[i - 1]->copy(model, copy))
3916 goto failed;
3917 }
3918 }
3919
3920 /* call copy of every interface in the reverse order,
3921 * they should not call parent's copy.
3922 */
3923 for (i = desc->total.ifaces; i > 0; i--)
3924 {
3925 if (desc->cache.ifaces[i - 1]->copy)
3926 {
3927 if (!desc->cache.ifaces[i - 1]->copy(model, copy))
3928 goto failed;
3929 }
3930 }
3931
3932 return copy;
3933
3934 failed:
3935 ERR("Failed to copy model %p %s", model, desc->cache.types[0]->name);
3936 eina_model_del(copy);
3937 return NULL;
3938}
3939
3940EAPI Eina_Model *
3941eina_model_deep_copy(const Eina_Model *model)
3942{
3943 const Eina_Model_Description *desc;
3944 Eina_Model *deep_copy;
3945 unsigned int i;
3946
3947 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
3948 desc = model->desc;
3949 deep_copy = eina_model_new(desc->cache.types[0]);
3950 EINA_SAFETY_ON_NULL_RETURN_VAL(deep_copy, NULL);
3951
3952 /* call deep_copy of every type in the reverse order,
3953 * they should not call parent's deep_copy.
3954 */
3955 for (i = desc->total.types; i > 0; i--)
3956 {
3957 if (desc->cache.types[i - 1]->deep_copy)
3958 {
3959 if (!desc->cache.types[i - 1]->deep_copy(model, deep_copy))
3960 goto failed;
3961 }
3962 }
3963
3964 /* call deep_copy of every interface in the reverse order,
3965 * they should not call parent's deep_copy.
3966 */
3967 for (i = desc->total.ifaces; i > 0; i--)
3968 {
3969 if (desc->cache.ifaces[i - 1]->deep_copy)
3970 {
3971 if (!desc->cache.ifaces[i - 1]->deep_copy(model, deep_copy))
3972 goto failed;
3973 }
3974 }
3975
3976 return deep_copy;
3977
3978 failed:
3979 ERR("Failed to deep copy model %p %s", model, desc->cache.types[0]->name);
3980 eina_model_del(deep_copy);
3981 return NULL;
3982}
3983
3984EAPI int
3985eina_model_compare(const Eina_Model *a, const Eina_Model *b)
3986{
3987 const Eina_Model_Description *desc_a, *desc_b;
3988 Eina_Bool ok;
3989 int cmp = -1;
3990
3991 EINA_MODEL_INSTANCE_CHECK_VAL(a, -1);
3992 EINA_MODEL_INSTANCE_CHECK_VAL(b, -1);
3993 desc_a = a->desc;
3994 desc_b = b->desc;
3995
3996 if ((!desc_a->ops.type.compare) && (!desc_b->ops.type.compare))
3997 {
3998 ERR("Models %p (%s) and %p (%s) can't compare",
3999 a, desc_a->cache.types[0]->name,
4000 b, desc_b->cache.types[0]->name);
4001 eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING);
4002 return -1;
4003 }
4004 else if ((desc_a->ops.type.compare) && (desc_b->ops.type.compare))
4005 {
4006 ok = desc_a->ops.type.compare(a, b, &cmp);
4007 if (!ok)
4008 {
4009 ok = desc_b->ops.type.compare(b, a, &cmp);
4010 if (ok)
4011 cmp = -cmp; /* swapped sides! */
4012 }
4013 }
4014 else if (desc_a->ops.type.compare)
4015 ok = desc_a->ops.type.compare(a, b, &cmp);
4016 else
4017 {
4018 ok = desc_b->ops.type.compare(b, a, &cmp);
4019 if (ok)
4020 cmp = -cmp; /* swapped sides! */
4021 }
4022
4023 if (!ok)
4024 {
4025 ERR("Could not compare models %p (%s) and %p (%s)",
4026 a, desc_a->cache.types[0]->name,
4027 b, desc_b->cache.types[0]->name);
4028 eina_error_set(EINA_ERROR_MODEL_FAILED);
4029 return -1;
4030 }
4031
4032 return cmp;
4033}
4034
4035EAPI Eina_Bool
4036eina_model_load(Eina_Model *model)
4037{
4038 Eina_Bool ret;
4039
4040 EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
4041
4042 eina_error_set(0);
4043 if (model->desc->ops.type.load)
4044 {
4045 ret = model->desc->ops.type.load(model);
4046 if (ret)
4047 _eina_model_event_callback_call(model, _eina_model_str_loaded, NULL);
4048 }
4049 else
4050 {
4051 eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING);
4052 ret = EINA_FALSE;
4053 ERR("Method load() not implemented for model %p (%s)",
4054 model, model->desc->cache.types[0]->name);
4055 }
4056
4057 return ret;
4058}
4059
4060EAPI Eina_Bool
4061eina_model_unload(Eina_Model *model)
4062{
4063 Eina_Bool ret;
4064
4065 EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
4066
4067 eina_error_set(0);
4068 if (model->desc->ops.type.unload)
4069 {
4070 ret = model->desc->ops.type.unload(model);
4071 if (ret)
4072 _eina_model_event_callback_call
4073 (model, _eina_model_str_unloaded, NULL);
4074 }
4075 else
4076 {
4077 eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING);
4078 ret = EINA_FALSE;
4079 ERR("Method unload() not implemented for model %p (%s)",
4080 model, model->desc->cache.types[0]->name);
4081 }
4082
4083 return ret;
4084}
4085
4086EAPI Eina_Bool
4087eina_model_property_get(const Eina_Model *model, const char *name, Eina_Value *value)
4088{
4089 EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
4090 EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
4091 EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
4092 EINA_MODEL_TYPE_CALL_MANDATORY_RETURN(model, property_get, EINA_FALSE,
4093 name, value);
4094}
4095
4096EAPI Eina_Bool
4097eina_model_property_set(Eina_Model *model, const const char *name, const Eina_Value *value)
4098{
4099 Eina_Bool ret;
4100
4101 EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
4102 EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
4103 EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
4104 EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_type_check(value->type), EINA_FALSE);
4105
4106 eina_error_set(0);
4107 if (model->desc->ops.type.property_set)
4108 {
4109 ret = model->desc->ops.type.property_set(model, name, value);
4110 if (ret)
4111 _eina_model_event_callback_call
4112 (model, _eina_model_str_property_set, name);
4113 }
4114 else
4115 {
4116 eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING);
4117 ret = EINA_FALSE;
4118 ERR("Method property_set() not implemented for model %p (%s)",
4119 model, model->desc->cache.types[0]->name);
4120 }
4121
4122 return ret;
4123}
4124
4125EAPI Eina_Bool
4126eina_model_property_del(Eina_Model *model, const char *name)
4127{
4128 Eina_Bool ret;
4129
4130 EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
4131 EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
4132
4133 eina_error_set(0);
4134 if (model->desc->ops.type.property_del)
4135 {
4136 ret = model->desc->ops.type.property_del(model, name);
4137 if (ret)
4138 _eina_model_event_callback_call
4139 (model, _eina_model_str_property_del, name);
4140 }
4141 else
4142 {
4143 eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING);
4144 ret = EINA_FALSE;
4145 ERR("Method property_del() not implemented for model %p (%s)",
4146 model, model->desc->cache.types[0]->name);
4147 }
4148
4149 return ret;
4150}
4151
4152EAPI Eina_List *
4153eina_model_properties_names_list_get(const Eina_Model *model)
4154{
4155 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
4156 EINA_MODEL_TYPE_CALL_OPTIONAL_RETURN(model, properties_names_list_get, NULL);
4157}
4158
4159EAPI void
4160eina_model_properties_names_list_free(Eina_List *list)
4161{
4162 const char *str;
4163 EINA_LIST_FREE(list, str)
4164 eina_stringshare_del(str);
4165}
4166
4167EAPI int
4168eina_model_child_count(const Eina_Model *model)
4169{
4170 EINA_MODEL_INSTANCE_CHECK_VAL(model, -1);
4171 EINA_MODEL_TYPE_CALL_OPTIONAL_RETURN(model, child_count, 0);
4172}
4173
4174EAPI Eina_Model *
4175eina_model_child_get(const Eina_Model *model, unsigned int position)
4176{
4177 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
4178 EINA_MODEL_TYPE_CALL_RETURN(model, child_get, NULL, position);
4179}
4180
4181EAPI Eina_Bool
4182eina_model_child_set(Eina_Model *model, unsigned int position, Eina_Model *child)
4183{
4184 Eina_Bool ret;
4185
4186 EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
4187 EINA_MODEL_INSTANCE_CHECK_VAL(child, EINA_FALSE);
4188
4189 eina_error_set(0);
4190 if (model->desc->ops.type.child_set)
4191 {
4192 ret = model->desc->ops.type.child_set(model, position, child);
4193 if (ret)
4194 _eina_model_event_callback_call
4195 (model, _eina_model_str_child_set, &position);
4196 }
4197 else
4198 {
4199 eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING);
4200 ret = EINA_FALSE;
4201 ERR("Method child_set() not implemented for model %p (%s)",
4202 model, model->desc->cache.types[0]->name);
4203 }
4204
4205 return ret;
4206}
4207
4208EAPI Eina_Bool
4209eina_model_child_del(Eina_Model *model, unsigned int position)
4210{
4211 Eina_Bool ret;
4212
4213 EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
4214
4215 eina_error_set(0);
4216 if (model->desc->ops.type.child_del)
4217 {
4218 ret = model->desc->ops.type.child_del(model, position);
4219 if (ret)
4220 {
4221 _eina_model_event_callback_call
4222 (model, _eina_model_str_child_del, &position);
4223 _eina_model_event_callback_call
4224 (model, _eina_model_str_children_changed, NULL);
4225 }
4226 }
4227 else
4228 {
4229 eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING);
4230 ret = EINA_FALSE;
4231 ERR("Method child_del() not implemented for model %p (%s)",
4232 model, model->desc->cache.types[0]->name);
4233 }
4234
4235 return ret;
4236}
4237
4238EAPI Eina_Bool
4239eina_model_child_insert_at(Eina_Model *model, unsigned int position, Eina_Model *child)
4240{
4241 Eina_Bool ret;
4242
4243 EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
4244 EINA_SAFETY_ON_NULL_RETURN_VAL(child, EINA_FALSE);
4245
4246 eina_error_set(0);
4247 if (model->desc->ops.type.child_insert_at)
4248 {
4249 ret = model->desc->ops.type.child_insert_at(model, position, child);
4250 if (ret)
4251 {
4252 _eina_model_event_callback_call
4253 (model, _eina_model_str_child_inserted, &position);
4254 _eina_model_event_callback_call
4255 (model, _eina_model_str_children_changed, NULL);
4256 }
4257 }
4258 else
4259 {
4260 eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING);
4261 ret = EINA_FALSE;
4262 ERR("Method child_insert_at() not implemented for model %p (%s)",
4263 model, model->desc->cache.types[0]->name);
4264 }
4265
4266 return ret;
4267}
4268
4269EAPI int
4270eina_model_child_append(Eina_Model *model, Eina_Model *child)
4271{
4272 Eina_Bool ret;
4273 int position;
4274
4275 EINA_MODEL_INSTANCE_CHECK_VAL(model, -1);
4276 EINA_SAFETY_ON_NULL_RETURN_VAL(child, -1);
4277
4278 position = eina_model_child_count(model);
4279 if (position < 0)
4280 return -1;
4281
4282 eina_error_set(0);
4283 if (model->desc->ops.type.child_insert_at)
4284 {
4285 ret = model->desc->ops.type.child_insert_at(model, position, child);
4286 if (ret)
4287 {
4288 _eina_model_event_callback_call
4289 (model, _eina_model_str_child_inserted, &position);
4290 _eina_model_event_callback_call
4291 (model, _eina_model_str_children_changed, NULL);
4292 }
4293 }
4294 else
4295 {
4296 eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING);
4297 ret = EINA_FALSE;
4298 ERR("Method child_insert_at() not implemented for model %p (%s)",
4299 model, model->desc->cache.types[0]->name);
4300 }
4301
4302 return ret ? position : -1;
4303}
4304
4305EAPI int
4306eina_model_child_find(const Eina_Model *model, unsigned int start_position, const Eina_Model *other)
4307{
4308 EINA_MODEL_INSTANCE_CHECK_VAL(model, -1);
4309 EINA_SAFETY_ON_NULL_RETURN_VAL(other, -1);
4310 EINA_MODEL_TYPE_CALL_RETURN(model, child_find, -1, start_position, other);
4311}
4312
4313EAPI int
4314eina_model_child_criteria_match(const Eina_Model *model, unsigned int start_position, Eina_Each_Cb match, const void *data)
4315{
4316 EINA_MODEL_INSTANCE_CHECK_VAL(model, -1);
4317 EINA_SAFETY_ON_NULL_RETURN_VAL(match, -1);
4318 EINA_MODEL_TYPE_CALL_RETURN(model, child_criteria_match, -1,
4319 start_position, match, data);
4320}
4321
4322EAPI Eina_Bool
4323eina_model_child_sort(Eina_Model *model, Eina_Compare_Cb compare)
4324{
4325 EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
4326 EINA_SAFETY_ON_NULL_RETURN_VAL(compare, EINA_FALSE);
4327 EINA_MODEL_TYPE_CALL(model, child_sort, compare);
4328 _eina_model_event_callback_call
4329 (model, _eina_model_str_children_changed, NULL);
4330 return EINA_TRUE;
4331}
4332
4333EAPI Eina_Iterator *
4334eina_model_child_iterator_get(Eina_Model *model)
4335{
4336 int count;
4337 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
4338 count = eina_model_child_count(model);
4339 if (count < 0)
4340 return NULL;
4341 EINA_MODEL_TYPE_CALL_RETURN(model, child_iterator_get, NULL, 0, count);
4342}
4343
4344EAPI Eina_Iterator *
4345eina_model_child_slice_iterator_get(Eina_Model *model, unsigned int start, unsigned int count)
4346{
4347 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
4348 EINA_MODEL_TYPE_CALL_RETURN(model, child_iterator_get, NULL, start, count);
4349}
4350
4351EAPI Eina_Iterator *
4352eina_model_child_reversed_iterator_get(Eina_Model *model)
4353{
4354 int count;
4355 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
4356 count = eina_model_child_count(model);
4357 if (count < 0)
4358 return NULL;
4359 EINA_MODEL_TYPE_CALL_RETURN(model, child_reversed_iterator_get, NULL,
4360 0, count);
4361}
4362
4363EAPI Eina_Iterator *
4364eina_model_child_slice_reversed_iterator_get(Eina_Model *model, unsigned int start, unsigned int count)
4365{
4366 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
4367 EINA_MODEL_TYPE_CALL_RETURN(model, child_reversed_iterator_get, NULL,
4368 start, count);
4369}
4370
4371EAPI Eina_Iterator *
4372eina_model_child_sorted_iterator_get(Eina_Model *model, Eina_Compare_Cb compare)
4373{
4374 int count;
4375 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
4376 EINA_SAFETY_ON_NULL_RETURN_VAL(compare, NULL);
4377 count = eina_model_child_count(model);
4378 if (count < 0)
4379 return NULL;
4380 EINA_MODEL_TYPE_CALL_RETURN(model, child_sorted_iterator_get, NULL,
4381 0, count, compare);
4382}
4383
4384EAPI Eina_Iterator *
4385eina_model_child_slice_sorted_iterator_get(Eina_Model *model, unsigned int start, unsigned int count, Eina_Compare_Cb compare)
4386{
4387 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
4388 EINA_SAFETY_ON_NULL_RETURN_VAL(compare, NULL);
4389 EINA_MODEL_TYPE_CALL_RETURN(model, child_sorted_iterator_get, NULL,
4390 start, count, compare);
4391}
4392
4393EAPI Eina_Iterator *
4394eina_model_child_filtered_iterator_get(Eina_Model *model, Eina_Each_Cb match, const void *data)
4395{
4396 int count;
4397 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
4398 EINA_SAFETY_ON_NULL_RETURN_VAL(match, NULL);
4399 count = eina_model_child_count(model);
4400 if (count < 0)
4401 return NULL;
4402 EINA_MODEL_TYPE_CALL_RETURN(model, child_filtered_iterator_get, NULL,
4403 0, count, match, data);
4404}
4405
4406EAPI Eina_Iterator *
4407eina_model_child_slice_filtered_iterator_get(Eina_Model *model, unsigned int start, unsigned int count, Eina_Each_Cb match, const void *data)
4408{
4409 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
4410 EINA_SAFETY_ON_NULL_RETURN_VAL(match, NULL);
4411 EINA_MODEL_TYPE_CALL_RETURN(model, child_filtered_iterator_get, NULL,
4412 start, count, match, data);
4413}
4414
4415EAPI char *
4416eina_model_to_string(const Eina_Model *model)
4417{
4418 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
4419 EINA_MODEL_TYPE_CALL_RETURN(model, to_string, NULL);
4420}
4421
4422/* type functions *****************************************************/
4423
4424EAPI Eina_Bool
4425eina_model_type_check(const Eina_Model_Type *type)
4426{
4427 EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE);
4428 return _eina_model_type_check(type);
4429}
4430
4431EAPI const char *
4432eina_model_type_name_get(const Eina_Model_Type *type)
4433{
4434 EINA_SAFETY_ON_NULL_RETURN_VAL(type, NULL);
4435 EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), NULL);
4436 return type->name;
4437}
4438
4439EAPI const Eina_Model_Type *
4440eina_model_type_parent_get(const Eina_Model_Type *type)
4441{
4442 EINA_SAFETY_ON_NULL_RETURN_VAL(type, NULL);
4443 EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), NULL);
4444 return type->parent;
4445}
4446
4447#define EINA_MODEL_TYPE_INSTANCE_CHECK(type, model) \
4448 EINA_SAFETY_ON_NULL_RETURN(type); \
4449 EINA_SAFETY_ON_FALSE_RETURN(_eina_model_type_check(type)); \
4450 EINA_MODEL_INSTANCE_CHECK(model); \
4451 EINA_SAFETY_ON_FALSE_RETURN(_eina_model_instance_check(model, type));
4452
4453#define EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, retval) \
4454 EINA_SAFETY_ON_NULL_RETURN_VAL(type, retval); \
4455 EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), retval); \
4456 EINA_MODEL_INSTANCE_CHECK_VAL(model, retval); \
4457 EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_instance_check(model, type), retval);
4458
4459EAPI Eina_Bool
4460eina_model_type_constructor(const Eina_Model_Type *type, Eina_Model *model)
4461{
4462 Eina_Bool (*constructor)(Eina_Model *);
4463
4464 EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE);
4465
4466 constructor = _eina_model_type_find_offset
4467 (type, offsetof(Eina_Model_Type, constructor));
4468 EINA_SAFETY_ON_NULL_RETURN_VAL(constructor, EINA_FALSE);
4469
4470 return constructor(model);
4471}
4472
4473EAPI Eina_Bool
4474eina_model_type_destructor(const Eina_Model_Type *type, Eina_Model *model)
4475{
4476 Eina_Bool (*destructor)(Eina_Model *);
4477
4478 EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE);
4479
4480 destructor = _eina_model_type_find_offset
4481 (type, offsetof(Eina_Model_Type, destructor));
4482 EINA_SAFETY_ON_NULL_RETURN_VAL(destructor, EINA_FALSE);
4483
4484 return destructor(model);
4485}
4486
4487EAPI Eina_Bool
4488eina_model_type_copy(const Eina_Model_Type *type, const Eina_Model *src, Eina_Model *dst)
4489{
4490 Eina_Bool (*copy)(const Eina_Model *, Eina_Model *);
4491
4492 EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, src, EINA_FALSE);
4493 EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, dst, EINA_FALSE);
4494
4495 copy = _eina_model_type_find_offset
4496 (type, offsetof(Eina_Model_Type, copy));
4497 EINA_SAFETY_ON_NULL_RETURN_VAL(copy, EINA_FALSE);
4498
4499 return copy(src, dst);
4500}
4501
4502EAPI Eina_Bool
4503eina_model_type_deep_copy(const Eina_Model_Type *type, const Eina_Model *src, Eina_Model *dst)
4504{
4505 Eina_Bool (*deep_copy)(const Eina_Model *, Eina_Model *);
4506
4507 EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, src, EINA_FALSE);
4508 EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, dst, EINA_FALSE);
4509
4510 deep_copy = _eina_model_type_find_offset
4511 (type, offsetof(Eina_Model_Type, deep_copy));
4512 EINA_SAFETY_ON_NULL_RETURN_VAL(deep_copy, EINA_FALSE);
4513
4514 return deep_copy(src, dst);
4515}
4516
4517EAPI Eina_Bool
4518eina_model_type_compare(const Eina_Model_Type *type, const Eina_Model *a, const Eina_Model *b, int *cmp)
4519{
4520 Eina_Bool (*compare)(const Eina_Model *, const Eina_Model *, int *);
4521
4522 EINA_SAFETY_ON_NULL_RETURN_VAL(cmp, EINA_FALSE);
4523 *cmp = 0;
4524
4525 EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, a, EINA_FALSE);
4526 EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, b, EINA_FALSE);
4527
4528 compare = _eina_model_type_find_offset
4529 (type, offsetof(Eina_Model_Type, compare));
4530 EINA_SAFETY_ON_NULL_RETURN_VAL(compare, EINA_FALSE);
4531
4532 return compare(a, b, cmp);
4533}
4534
4535EAPI Eina_Bool
4536eina_model_type_load(const Eina_Model_Type *type, Eina_Model *model)
4537{
4538 Eina_Bool (*load)(Eina_Model *);
4539
4540 EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE);
4541
4542 load = _eina_model_type_find_offset
4543 (type, offsetof(Eina_Model_Type, load));
4544 EINA_SAFETY_ON_NULL_RETURN_VAL(load, EINA_FALSE);
4545
4546 return load(model);
4547}
4548
4549EAPI Eina_Bool
4550eina_model_type_unload(const Eina_Model_Type *type, Eina_Model *model)
4551{
4552 Eina_Bool (*unload)(Eina_Model *);
4553
4554 EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE);
4555
4556 unload = _eina_model_type_find_offset
4557 (type, offsetof(Eina_Model_Type, unload));
4558 EINA_SAFETY_ON_NULL_RETURN_VAL(unload, EINA_FALSE);
4559
4560 return unload(model);
4561}
4562
4563EAPI Eina_Bool
4564eina_model_type_property_get(const Eina_Model_Type *type, const Eina_Model *model, const char *name, Eina_Value *value)
4565{
4566 Eina_Bool (*property_get)(const Eina_Model *, const char *, Eina_Value *);
4567
4568 EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
4569 EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
4570
4571 EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE);
4572
4573 property_get = _eina_model_type_find_offset
4574 (type, offsetof(Eina_Model_Type, property_get));
4575 EINA_SAFETY_ON_NULL_RETURN_VAL(property_get, EINA_FALSE);
4576
4577 return property_get(model, name, value);
4578}
4579
4580EAPI Eina_Bool
4581eina_model_type_property_set(const Eina_Model_Type *type, Eina_Model *model, const char *name, const Eina_Value *value)
4582{
4583 Eina_Bool (*property_set)(Eina_Model *, const char *, const Eina_Value *);
4584
4585 EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
4586 EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
4587 EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_type_check(value->type), EINA_FALSE);
4588
4589 EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE);
4590
4591 property_set = _eina_model_type_find_offset
4592 (type, offsetof(Eina_Model_Type, property_set));
4593 EINA_SAFETY_ON_NULL_RETURN_VAL(property_set, EINA_FALSE);
4594
4595 return property_set(model, name, value);
4596}
4597
4598EAPI Eina_Bool
4599eina_model_type_property_del(const Eina_Model_Type *type, Eina_Model *model, const char *name)
4600{
4601 Eina_Bool (*property_del)(const Eina_Model *, const char *);
4602
4603 EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
4604 EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE);
4605
4606 property_del = _eina_model_type_find_offset
4607 (type, offsetof(Eina_Model_Type, property_del));
4608 EINA_SAFETY_ON_NULL_RETURN_VAL(property_del, EINA_FALSE);
4609
4610 return property_del(model, name);
4611}
4612
4613EAPI Eina_List *
4614eina_model_type_properties_names_list_get(const Eina_Model_Type *type, const Eina_Model *model)
4615{
4616 Eina_List *(*properties_names_list_get)(const Eina_Model *);
4617
4618 EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL);
4619
4620 properties_names_list_get = _eina_model_type_find_offset
4621 (type, offsetof(Eina_Model_Type, properties_names_list_get));
4622 EINA_SAFETY_ON_NULL_RETURN_VAL(properties_names_list_get, NULL);
4623
4624 return properties_names_list_get(model);
4625}
4626
4627EAPI int
4628eina_model_type_child_count(const Eina_Model_Type *type, const Eina_Model *model)
4629{
4630 int (*child_count)(const Eina_Model *);
4631
4632 EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, -1);
4633
4634 child_count = _eina_model_type_find_offset
4635 (type, offsetof(Eina_Model_Type, child_count));
4636 EINA_SAFETY_ON_NULL_RETURN_VAL(child_count, -1);
4637
4638 return child_count(model);
4639}
4640
4641EAPI Eina_Model *
4642eina_model_type_child_get(const Eina_Model_Type *type, const Eina_Model *model, unsigned int position)
4643{
4644 Eina_Model *(*child_get)(const Eina_Model *, unsigned int);
4645
4646 EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL);
4647
4648 child_get = _eina_model_type_find_offset
4649 (type, offsetof(Eina_Model_Type, child_get));
4650 EINA_SAFETY_ON_NULL_RETURN_VAL(child_get, NULL);
4651
4652 return child_get(model, position);
4653}
4654
4655EAPI Eina_Bool
4656eina_model_type_child_set(const Eina_Model_Type *type, Eina_Model *model, unsigned int position, Eina_Model *child)
4657{
4658 Eina_Bool (*child_set)(Eina_Model *, unsigned int, Eina_Model *);
4659
4660 EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE);
4661 EINA_MODEL_INSTANCE_CHECK_VAL(child, EINA_FALSE);
4662
4663 child_set = _eina_model_type_find_offset
4664 (type, offsetof(Eina_Model_Type, child_set));
4665 EINA_SAFETY_ON_NULL_RETURN_VAL(child_set, EINA_FALSE);
4666
4667 return child_set(model, position, child);
4668}
4669
4670EAPI Eina_Bool
4671eina_model_type_child_del(const Eina_Model_Type *type, Eina_Model *model, unsigned int position)
4672{
4673 Eina_Bool (*child_del)(Eina_Model *, unsigned int);
4674
4675 EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE);
4676
4677 child_del = _eina_model_type_find_offset
4678 (type, offsetof(Eina_Model_Type, child_del));
4679 EINA_SAFETY_ON_NULL_RETURN_VAL(child_del, EINA_FALSE);
4680
4681 return child_del(model, position);
4682}
4683
4684EAPI Eina_Bool
4685eina_model_type_child_insert_at(const Eina_Model_Type *type, Eina_Model *model, unsigned int position, Eina_Model *child)
4686{
4687 Eina_Bool (*child_insert_at)(Eina_Model *, unsigned int, Eina_Model *);
4688
4689 EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE);
4690 EINA_MODEL_INSTANCE_CHECK_VAL(child, EINA_FALSE);
4691
4692 child_insert_at = _eina_model_type_find_offset
4693 (type, offsetof(Eina_Model_Type, child_insert_at));
4694 EINA_SAFETY_ON_NULL_RETURN_VAL(child_insert_at, EINA_FALSE);
4695
4696 return child_insert_at(model, position, child);
4697}
4698
4699EAPI int
4700eina_model_type_child_find(const Eina_Model_Type *type, const Eina_Model *model, unsigned int start_position, const Eina_Model *other)
4701{
4702 int (*child_find)(const Eina_Model *, unsigned int, const Eina_Model *);
4703
4704 EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, -1);
4705 EINA_MODEL_INSTANCE_CHECK_VAL(other, -1);
4706
4707 child_find = _eina_model_type_find_offset
4708 (type, offsetof(Eina_Model_Type, child_find));
4709 EINA_SAFETY_ON_NULL_RETURN_VAL(child_find, -1);
4710
4711 return child_find(model, start_position, other);
4712}
4713
4714EAPI int
4715eina_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)
4716{
4717 int (*child_criteria_match)(const Eina_Model *, unsigned int, Eina_Each_Cb, const void *);
4718
4719 EINA_SAFETY_ON_NULL_RETURN_VAL(match, -1);
4720 EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, -1);
4721
4722 child_criteria_match = _eina_model_type_find_offset
4723 (type, offsetof(Eina_Model_Type, child_criteria_match));
4724 EINA_SAFETY_ON_NULL_RETURN_VAL(child_criteria_match, -1);
4725
4726 return child_criteria_match(model, start_position, match, data);
4727}
4728
4729EAPI void
4730eina_model_type_child_sort(const Eina_Model_Type *type, Eina_Model *model, Eina_Compare_Cb compare)
4731{
4732 void (*child_sort)(Eina_Model *, Eina_Compare_Cb);
4733
4734 EINA_SAFETY_ON_NULL_RETURN(compare);
4735 EINA_MODEL_TYPE_INSTANCE_CHECK(type, model);
4736
4737 child_sort = _eina_model_type_find_offset
4738 (type, offsetof(Eina_Model_Type, child_sort));
4739 EINA_SAFETY_ON_NULL_RETURN(child_sort);
4740
4741 return child_sort(model, compare);
4742}
4743
4744EAPI Eina_Iterator *
4745eina_model_type_child_iterator_get(const Eina_Model_Type *type, Eina_Model *model, unsigned int start, unsigned int count)
4746{
4747 Eina_Iterator *(*child_iterator_get)(const Eina_Model *, unsigned int, unsigned int);
4748
4749 EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL);
4750
4751 child_iterator_get = _eina_model_type_find_offset
4752 (type, offsetof(Eina_Model_Type, child_iterator_get));
4753 EINA_SAFETY_ON_NULL_RETURN_VAL(child_iterator_get, NULL);
4754
4755 return child_iterator_get(model, start, count);
4756}
4757
4758EAPI Eina_Iterator *
4759eina_model_type_child_reversed_iterator_get(const Eina_Model_Type *type, Eina_Model *model, unsigned int start, unsigned int count)
4760{
4761 Eina_Iterator *(*child_reversed_iterator_get)(const Eina_Model *, unsigned int, unsigned int);
4762
4763 EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL);
4764
4765 child_reversed_iterator_get = _eina_model_type_find_offset
4766 (type, offsetof(Eina_Model_Type, child_reversed_iterator_get));
4767 EINA_SAFETY_ON_NULL_RETURN_VAL(child_reversed_iterator_get, NULL);
4768
4769 return child_reversed_iterator_get(model, start, count);
4770}
4771
4772EAPI Eina_Iterator *
4773eina_model_type_child_sorted_iterator_get(const Eina_Model_Type *type, Eina_Model *model, unsigned int start, unsigned int count, Eina_Compare_Cb compare)
4774{
4775 Eina_Iterator *(*child_sorted_iterator_get)(const Eina_Model *, unsigned int, unsigned int, Eina_Compare_Cb);
4776
4777 EINA_SAFETY_ON_NULL_RETURN_VAL(compare, NULL);
4778 EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL);
4779
4780 child_sorted_iterator_get = _eina_model_type_find_offset
4781 (type, offsetof(Eina_Model_Type, child_sorted_iterator_get));
4782 EINA_SAFETY_ON_NULL_RETURN_VAL(child_sorted_iterator_get, NULL);
4783
4784 return child_sorted_iterator_get(model, start, count, compare);
4785}
4786
4787EAPI Eina_Iterator *
4788eina_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)
4789{
4790 Eina_Iterator *(*child_filtered_iterator_get)(const Eina_Model *, unsigned int, unsigned int, Eina_Each_Cb, const void *);
4791
4792 EINA_SAFETY_ON_NULL_RETURN_VAL(match, NULL);
4793 EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL);
4794
4795 child_filtered_iterator_get = _eina_model_type_find_offset
4796 (type, offsetof(Eina_Model_Type, child_filtered_iterator_get));
4797 EINA_SAFETY_ON_NULL_RETURN_VAL(child_filtered_iterator_get, NULL);
4798
4799 return child_filtered_iterator_get(model, start, count, match, data);
4800}
4801
4802EAPI char *
4803eina_model_type_to_string(const Eina_Model_Type *type, const Eina_Model *model)
4804{
4805 char *(*to_string)(const Eina_Model *);
4806
4807 EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL);
4808
4809 to_string = _eina_model_type_find_offset
4810 (type, offsetof(Eina_Model_Type, to_string));
4811 EINA_SAFETY_ON_NULL_RETURN_VAL(to_string, NULL);
4812
4813 return to_string(model);
4814}
4815
4816EAPI Eina_Bool
4817eina_model_type_subclass_setup(Eina_Model_Type *type, const Eina_Model_Type *parent)
4818{
4819 EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE);
4820 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, EINA_FALSE);
4821 EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(parent), EINA_FALSE);
4822 EINA_SAFETY_ON_FALSE_RETURN_VAL(type->version == EINA_MODEL_TYPE_VERSION,
4823 EINA_FALSE);
4824
4825 type->parent = parent;
4826 type->type_size = parent->type_size;
4827 type->interfaces = NULL;
4828 type->events = NULL;
4829
4830 type->setup = NULL;
4831 type->flush = NULL;
4832 type->constructor = NULL;
4833 type->destructor = NULL;
4834 type->copy = NULL;
4835 type->deep_copy = NULL;
4836 type->compare = NULL;
4837 type->load = NULL;
4838 type->unload = NULL;
4839 type->property_get = NULL;
4840 type->property_set = NULL;
4841 type->property_del = NULL;
4842 type->properties_names_list_get = NULL;
4843 type->child_count = NULL;
4844 type->child_get = NULL;
4845 type->child_set = NULL;
4846 type->child_del = NULL;
4847 type->child_insert_at = NULL;
4848 type->child_find = NULL;
4849 type->child_criteria_match = NULL;
4850 type->child_sort = NULL;
4851 type->child_iterator_get = NULL;
4852 type->child_reversed_iterator_get = NULL;
4853 type->child_sorted_iterator_get = NULL;
4854 type->child_filtered_iterator_get = NULL;
4855 type->to_string = NULL;
4856 type->__extension_ptr0 = NULL;
4857 type->__extension_ptr1 = NULL;
4858 type->__extension_ptr2 = NULL;
4859 type->__extension_ptr3 = NULL;
4860
4861 if (type->type_size > sizeof(Eina_Model_Type))
4862 {
4863 unsigned char *p = (unsigned char *)type;
4864 p += sizeof(Eina_Model_Type);
4865 memset(p, 0, type->type_size - sizeof(Eina_Model_Type));
4866 }
4867
4868 return EINA_TRUE;
4869}
4870
4871EAPI Eina_Bool
4872eina_model_type_subclass_check(const Eina_Model_Type *type, const Eina_Model_Type *self_or_parent)
4873{
4874 EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE);
4875 EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), EINA_FALSE);
4876 EINA_SAFETY_ON_NULL_RETURN_VAL(self_or_parent, EINA_FALSE);
4877
4878 for (; type != NULL; type = type->parent)
4879 {
4880 if (type == self_or_parent)
4881 return EINA_TRUE;
4882 }
4883
4884 return EINA_FALSE;
4885}
4886
4887static inline const Eina_Model_Interface *
4888_eina_model_type_interface_get(const Eina_Model_Type *type, const char *name, Eina_Bool ptr_cmp __UNUSED__)
4889{
4890 const Eina_Model_Interface **itr;
4891
4892 if (!type)
4893 return NULL;
4894
4895 if (!type->interfaces)
4896 return _eina_model_type_interface_get(type->parent, name, ptr_cmp);
4897
4898 {
4899 for (itr = type->interfaces ; itr != NULL ; itr++)
4900 if (strcmp((*itr)->name, name) == 0)
4901 return *itr;
4902 }
4903
4904 return NULL;
4905}
4906
4907static inline Eina_Bool
4908_eina_model_interface_check(const Eina_Model_Interface *iface)
4909{
4910 EINA_SAFETY_ON_FALSE_RETURN_VAL
4911 (iface->version == EINA_MODEL_INTERFACE_VERSION, EINA_FALSE);
4912 return EINA_TRUE;
4913}
4914
4915EAPI const Eina_Model_Interface *
4916eina_model_type_interface_get(const Eina_Model_Type *type, const char *name)
4917{
4918 const Eina_Model_Interface *iface;
4919
4920 EINA_SAFETY_ON_NULL_RETURN_VAL(type, NULL);
4921 EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), NULL);
4922
4923 /* search for pointer, make speed-aware users fast */
4924 iface = _eina_model_type_interface_get(type, name, EINA_TRUE);
4925
4926 if (!iface)
4927 {
4928 /* search using strcmp(), slow users don't care */
4929 iface = _eina_model_type_interface_get(type, name, EINA_FALSE);
4930 }
4931 else if (!_eina_model_interface_check(iface))
4932 iface = NULL;
4933
4934 return iface;
4935}
4936
4937EAPI void *
4938eina_model_type_private_data_get(const Eina_Model *model, const Eina_Model_Type *type)
4939{
4940 const Eina_Model_Description *desc;
4941 unsigned int i;
4942
4943 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
4944 EINA_SAFETY_ON_NULL_RETURN_VAL(type, NULL);
4945 EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), NULL);
4946
4947 desc = model->desc;
4948
4949 for (i = 0; i < desc->total.types; i++)
4950 if (desc->cache.types[i] == type)
4951 return model->privates[i];
4952
4953 CRITICAL("Model %p (%s) is not an instance of type %p (%s)",
4954 model, desc->cache.types[0]->name,
4955 type, type->name);
4956 return NULL;
4957}
4958
4959EAPI const void *
4960eina_model_method_offset_resolve(const Eina_Model *model, unsigned int offset)
4961{
4962 const Eina_Model_Description *desc;
4963
4964 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
4965 EINA_SAFETY_ON_FALSE_RETURN_VAL(offset >= sizeof(Eina_Model_Type), NULL);
4966 EINA_SAFETY_ON_FALSE_RETURN_VAL(offset % sizeof(void *) == 0, NULL);
4967
4968 desc = model->desc;
4969 EINA_SAFETY_ON_FALSE_RETURN_VAL
4970 (offset + sizeof(void *) <= desc->cache.types[0]->type_size, NULL);
4971
4972 offset -= sizeof(Eina_Model_Type);
4973 offset /= sizeof(void *);
4974 return desc->ops.type.extension[offset];
4975}
4976
4977EAPI const void *
4978eina_model_type_method_offset_resolve(const Eina_Model_Type *type, const Eina_Model *model, unsigned int offset)
4979{
4980 const Eina_Model_Description *desc;
4981
4982 EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL);
4983 EINA_SAFETY_ON_FALSE_RETURN_VAL(offset >= sizeof(Eina_Model_Type), NULL);
4984 EINA_SAFETY_ON_FALSE_RETURN_VAL(offset % sizeof(void *) == 0, NULL);
4985
4986 desc = model->desc;
4987 EINA_SAFETY_ON_FALSE_RETURN_VAL
4988 (offset + sizeof(void *) <= desc->cache.types[0]->type_size, NULL);
4989
4990 return _eina_model_type_find_offset(type, offset);
4991}
4992
4993/* interface functions ************************************************/
4994
4995EAPI Eina_Bool
4996eina_model_interface_check(const Eina_Model_Interface *iface)
4997{
4998 EINA_SAFETY_ON_NULL_RETURN_VAL(iface, EINA_FALSE);
4999 return _eina_model_interface_check(iface);
5000}
5001
5002EAPI void *
5003eina_model_interface_private_data_get(const Eina_Model *model, const Eina_Model_Interface *iface)
5004{
5005 const Eina_Model_Description *desc;
5006 unsigned int i;
5007
5008 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
5009 EINA_SAFETY_ON_NULL_RETURN_VAL(iface, NULL);
5010 EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_interface_check(iface), NULL);
5011
5012 desc = model->desc;
5013
5014 for (i = 0; i < desc->total.ifaces; i++)
5015 if (desc->cache.ifaces[i] == iface)
5016 return model->privates[desc->total.types + i];
5017
5018 CRITICAL("Model %p (%s) does not implement interface %p (%s)",
5019 model, desc->cache.types[0]->name,
5020 iface, iface->name);
5021 return NULL;
5022}
5023
5024static Eina_Bool
5025_eina_model_interface_implemented(const Eina_Model *model, const Eina_Model_Interface *iface)
5026{
5027 const Eina_Model_Interface **itr, **itr_end;
5028
5029 itr = model->desc->cache.ifaces;
5030 itr_end = itr + model->desc->total.ifaces;
5031
5032 for (; itr < itr_end; itr++)
5033 if (*itr == iface)
5034 return EINA_TRUE;
5035
5036 return EINA_FALSE;
5037}
5038
5039EAPI Eina_Bool
5040eina_model_interface_implemented(const Eina_Model *model, const Eina_Model_Interface *iface)
5041{
5042 EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
5043 EINA_SAFETY_ON_NULL_RETURN_VAL(iface, EINA_FALSE);
5044 EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_interface_check(iface),
5045 EINA_FALSE);
5046 return _eina_model_interface_implemented(model, iface);
5047}
5048
5049#define EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK(iface, model) \
5050 EINA_SAFETY_ON_NULL_RETURN(iface); \
5051 EINA_SAFETY_ON_FALSE_RETURN(_eina_model_interface_check(iface)); \
5052 EINA_MODEL_INSTANCE_CHECK(model); \
5053 EINA_SAFETY_ON_FALSE_RETURN(_eina_model_interface_implemented(model, iface));
5054
5055#define EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, retval) \
5056 EINA_SAFETY_ON_NULL_RETURN_VAL(iface, retval); \
5057 EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_interface_check(iface), retval); \
5058 EINA_MODEL_INSTANCE_CHECK_VAL(model, retval); \
5059 EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_interface_implemented(model, iface), retval);
5060
5061
5062EAPI Eina_Bool
5063eina_model_interface_constructor(const Eina_Model_Interface *iface, Eina_Model *model)
5064{
5065 Eina_Bool (*constructor)(Eina_Model *);
5066
5067 EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
5068
5069 constructor = _eina_model_interface_find_offset
5070 (iface, offsetof(Eina_Model_Interface, constructor));
5071 EINA_SAFETY_ON_NULL_RETURN_VAL(constructor, EINA_FALSE);
5072 return constructor(model);
5073}
5074
5075EAPI Eina_Bool
5076eina_model_interface_destructor(const Eina_Model_Interface *iface, Eina_Model *model)
5077{
5078 Eina_Bool (*destructor)(Eina_Model *);
5079
5080 EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
5081
5082 destructor = _eina_model_interface_find_offset
5083 (iface, offsetof(Eina_Model_Interface, destructor));
5084 EINA_SAFETY_ON_NULL_RETURN_VAL(destructor, EINA_FALSE);
5085 return destructor(model);
5086}
5087
5088EAPI Eina_Bool
5089eina_model_interface_copy(const Eina_Model_Interface *iface, const Eina_Model *src, Eina_Model *dst)
5090{
5091 Eina_Bool (*copy)(const Eina_Model *, Eina_Model *);
5092
5093 EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, src, EINA_FALSE);
5094 EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, dst, EINA_FALSE);
5095
5096 copy = _eina_model_interface_find_offset
5097 (iface, offsetof(Eina_Model_Interface, copy));
5098 EINA_SAFETY_ON_NULL_RETURN_VAL(copy, EINA_FALSE);
5099 return copy(src, dst);
5100}
5101
5102EAPI Eina_Bool
5103eina_model_interface_deep_copy(const Eina_Model_Interface *iface, const Eina_Model *src, Eina_Model *dst)
5104{
5105 Eina_Bool (*deep_copy)(const Eina_Model *, Eina_Model *);
5106
5107 EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, src, EINA_FALSE);
5108 EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, dst, EINA_FALSE);
5109
5110 deep_copy = _eina_model_interface_find_offset
5111 (iface, offsetof(Eina_Model_Interface, deep_copy));
5112 EINA_SAFETY_ON_NULL_RETURN_VAL(deep_copy, EINA_FALSE);
5113 return deep_copy(src, dst);
5114}
5115
5116EAPI const void
5117*eina_model_interface_method_offset_resolve(const Eina_Model_Interface *iface, const Eina_Model *model, unsigned int offset)
5118{
5119 EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, NULL);
5120 EINA_SAFETY_ON_FALSE_RETURN_VAL(offset >= sizeof(Eina_Model_Interface), NULL);
5121 EINA_SAFETY_ON_FALSE_RETURN_VAL(offset % sizeof(void *) == 0, NULL);
5122 return _eina_model_interface_find_offset(iface, offset);
5123}
5124
5125
5126/* Eina_Model_Interface_Properties ************************************/
5127
5128EAPI Eina_Bool
5129eina_model_interface_properties_compare(const Eina_Model_Interface *iface, const Eina_Model *a, const Eina_Model *b, int *cmp)
5130{
5131 Eina_Bool (*compare)(const Eina_Model *, const Eina_Model *, int *cmp);
5132
5133 EINA_SAFETY_ON_NULL_RETURN_VAL(cmp, EINA_FALSE);
5134
5135 *cmp = 0;
5136 EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, a, EINA_FALSE);
5137 EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, b, EINA_FALSE);
5138
5139 compare = _eina_model_interface_find_offset
5140 (iface, offsetof(Eina_Model_Interface_Properties, compare));
5141 EINA_SAFETY_ON_NULL_RETURN_VAL(compare, EINA_FALSE);
5142 return compare(a, b, cmp);
5143}
5144
5145EAPI Eina_Bool
5146eina_model_interface_properties_load(const Eina_Model_Interface *iface, Eina_Model *model)
5147{
5148 Eina_Bool (*load)(Eina_Model *);
5149 Eina_Bool ret;
5150
5151 EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
5152
5153 load = _eina_model_interface_find_offset
5154 (iface, offsetof(Eina_Model_Interface_Properties, load));
5155 EINA_SAFETY_ON_NULL_RETURN_VAL(load, EINA_FALSE);
5156 ret = load(model);
5157
5158 if (ret)
5159 _eina_model_event_callback_call
5160 (model, _eina_model_str_properties_loaded, NULL);
5161
5162 return ret;
5163}
5164
5165EAPI Eina_Bool
5166eina_model_interface_properties_unload(const Eina_Model_Interface *iface, Eina_Model *model)
5167{
5168 Eina_Bool (*unload)(Eina_Model *);
5169 Eina_Bool ret;
5170
5171 EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
5172
5173 unload = _eina_model_interface_find_offset
5174 (iface, offsetof(Eina_Model_Interface_Properties, unload));
5175 EINA_SAFETY_ON_NULL_RETURN_VAL(unload, EINA_FALSE);
5176 ret = unload(model);
5177
5178 if (ret)
5179 _eina_model_event_callback_call
5180 (model, _eina_model_str_properties_unloaded, NULL);
5181
5182 return ret;
5183}
5184
5185EAPI Eina_Bool
5186eina_model_interface_properties_get(const Eina_Model_Interface *iface, const Eina_Model *model, const char *name, Eina_Value *value)
5187{
5188 Eina_Bool (*get)(const Eina_Model *, const char *, Eina_Value *);
5189
5190 EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
5191 EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
5192 EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
5193
5194 get = _eina_model_interface_find_offset
5195 (iface, offsetof(Eina_Model_Interface_Properties, get));
5196 EINA_SAFETY_ON_NULL_RETURN_VAL(get, EINA_FALSE);
5197 return get(model, name, value);
5198}
5199
5200EAPI Eina_Bool
5201eina_model_interface_properties_set(const Eina_Model_Interface *iface, Eina_Model *model, const char *name, const Eina_Value *value)
5202{
5203 Eina_Bool (*set)(Eina_Model *, const char *, const Eina_Value *);
5204
5205 EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
5206 EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
5207 EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_type_check(value->type), EINA_FALSE);
5208 EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
5209
5210 set = _eina_model_interface_find_offset
5211 (iface, offsetof(Eina_Model_Interface_Properties, set));
5212 EINA_SAFETY_ON_NULL_RETURN_VAL(set, EINA_FALSE);
5213 return set(model, name, value);
5214}
5215
5216EAPI Eina_Bool
5217eina_model_interface_properties_del(const Eina_Model_Interface *iface, Eina_Model *model, const char *name)
5218{
5219 Eina_Bool (*del)(Eina_Model *, const char *);
5220
5221 EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
5222 EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
5223
5224 del = _eina_model_interface_find_offset
5225 (iface, offsetof(Eina_Model_Interface_Properties, del));
5226 EINA_SAFETY_ON_NULL_RETURN_VAL(del, EINA_FALSE);
5227 return del(model, name);
5228}
5229
5230EAPI Eina_List *
5231eina_model_interface_properties_names_list_get(const Eina_Model_Interface *iface, const Eina_Model *model)
5232{
5233 Eina_List *(*names_list_get)(const Eina_Model *);
5234
5235 EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, NULL);
5236
5237 names_list_get = _eina_model_interface_find_offset
5238 (iface, offsetof(Eina_Model_Interface_Properties, names_list_get));
5239 EINA_SAFETY_ON_NULL_RETURN_VAL(names_list_get, NULL);
5240 return names_list_get(model);
5241}
5242
5243/* Eina_Model_Interface_Children **************************************/
5244
5245EAPI Eina_Bool
5246eina_model_interface_children_compare(const Eina_Model_Interface *iface, const Eina_Model *a, const Eina_Model *b, int *cmp)
5247{
5248 Eina_Bool (*compare)(const Eina_Model *, const Eina_Model *, int *);
5249
5250 EINA_SAFETY_ON_NULL_RETURN_VAL(cmp, EINA_FALSE);
5251
5252 *cmp = 0;
5253
5254 EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, a, EINA_FALSE);
5255 EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, b, EINA_FALSE);
5256
5257 compare = _eina_model_interface_find_offset
5258 (iface, offsetof(Eina_Model_Interface_Children, compare));
5259 EINA_SAFETY_ON_NULL_RETURN_VAL(compare, EINA_FALSE);
5260 return compare(a, b, cmp);
5261}
5262
5263EAPI Eina_Bool
5264eina_model_interface_children_load(const Eina_Model_Interface *iface, Eina_Model *model)
5265{
5266 Eina_Bool (*load)(Eina_Model *);
5267 Eina_Bool ret;
5268
5269 EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
5270
5271 load = _eina_model_interface_find_offset
5272 (iface, offsetof(Eina_Model_Interface_Children, load));
5273 EINA_SAFETY_ON_NULL_RETURN_VAL(load, EINA_FALSE);
5274 ret = load(model);
5275
5276 if (ret)
5277 _eina_model_event_callback_call
5278 (model, _eina_model_str_children_loaded, NULL);
5279
5280 return ret;
5281}
5282
5283EAPI Eina_Bool
5284eina_model_interface_children_unload(const Eina_Model_Interface *iface, Eina_Model *model)
5285{
5286 Eina_Bool (*unload)(Eina_Model *);
5287 Eina_Bool ret;
5288
5289 EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
5290
5291 unload = _eina_model_interface_find_offset
5292 (iface, offsetof(Eina_Model_Interface_Children, unload));
5293 EINA_SAFETY_ON_NULL_RETURN_VAL(unload, EINA_FALSE);
5294 ret = unload(model);
5295
5296 if (ret)
5297 _eina_model_event_callback_call
5298 (model, _eina_model_str_children_unloaded, NULL);
5299
5300 return ret;
5301}
5302
5303EAPI int
5304eina_model_interface_children_count(const Eina_Model_Interface *iface, const Eina_Model *model)
5305{
5306 int (*count)(const Eina_Model *);
5307
5308 EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, -1);
5309
5310 count = _eina_model_interface_find_offset
5311 (iface, offsetof(Eina_Model_Interface_Children, count));
5312 EINA_SAFETY_ON_NULL_RETURN_VAL(count, -1);
5313 return count(model);
5314}
5315
5316EAPI Eina_Model *
5317eina_model_interface_children_get(const Eina_Model_Interface *iface, const Eina_Model *model, unsigned int position)
5318{
5319 Eina_Model *(*get)(const Eina_Model *, unsigned int);
5320
5321 EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, NULL);
5322
5323 get = _eina_model_interface_find_offset
5324 (iface, offsetof(Eina_Model_Interface_Children, get));
5325 EINA_SAFETY_ON_NULL_RETURN_VAL(get, NULL);
5326 return get(model, position);
5327}
5328
5329EAPI Eina_Bool eina_model_interface_children_set(const Eina_Model_Interface *iface, Eina_Model *model, unsigned int position, Eina_Model *child)
5330{
5331 Eina_Bool (*set)(const Eina_Model *, unsigned int, Eina_Model *);
5332
5333 EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
5334 EINA_MODEL_INSTANCE_CHECK_VAL(child, EINA_FALSE);
5335
5336 set = _eina_model_interface_find_offset
5337 (iface, offsetof(Eina_Model_Interface_Children, set));
5338 EINA_SAFETY_ON_NULL_RETURN_VAL(set, EINA_FALSE);
5339 return set(model, position, child);
5340}
5341
5342EAPI Eina_Bool
5343eina_model_interface_children_del(const Eina_Model_Interface *iface, Eina_Model *model, unsigned int position)
5344{
5345 Eina_Bool (*del)(Eina_Model *, unsigned int);
5346
5347 EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
5348
5349 del = _eina_model_interface_find_offset
5350 (iface, offsetof(Eina_Model_Interface_Children, del));
5351 EINA_SAFETY_ON_NULL_RETURN_VAL(del, EINA_FALSE);
5352 return del(model, position);
5353}
5354
5355
5356EAPI Eina_Bool
5357eina_model_interface_children_insert_at(const Eina_Model_Interface *iface, Eina_Model *model, unsigned int position, Eina_Model *child)
5358{
5359 Eina_Bool (*insert_at)(const Eina_Model *, unsigned int, Eina_Model *);
5360
5361 EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
5362 EINA_MODEL_INSTANCE_CHECK_VAL(child, EINA_FALSE);
5363
5364 insert_at = _eina_model_interface_find_offset
5365 (iface, offsetof(Eina_Model_Interface_Children, insert_at));
5366 EINA_SAFETY_ON_NULL_RETURN_VAL(insert_at, EINA_FALSE);
5367 return insert_at(model, position, child);
5368}
5369
5370EAPI void
5371eina_model_interface_children_sort(const Eina_Model_Interface *iface, Eina_Model *model, Eina_Compare_Cb compare)
5372{
5373 void (*sort)(const Eina_Model *, Eina_Compare_Cb);
5374
5375 EINA_SAFETY_ON_NULL_RETURN(compare);
5376 EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK(iface, model);
5377
5378 sort = _eina_model_interface_find_offset
5379 (iface, offsetof(Eina_Model_Interface_Children, sort));
5380 EINA_SAFETY_ON_NULL_RETURN(sort);
5381 return sort(model, compare);
5382}
5383
5384static Eina_Bool
5385_eina_model_struct_set(Eina_Model *m, const Eina_Value_Struct_Desc *desc, void *memory)
5386{
5387 Eina_Value_Struct st = {desc, memory};
5388 Eina_Value *val = eina_model_interface_private_data_get
5389 (m, &_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base);
5390 return eina_value_pset(val, &st);
5391}
5392
5393EAPI Eina_Model *
5394eina_model_struct_new(const Eina_Value_Struct_Desc *desc)
5395{
5396 Eina_Model *m;
5397
5398 EINA_SAFETY_ON_NULL_RETURN_VAL(desc, NULL);
5399 EINA_SAFETY_ON_FALSE_RETURN_VAL
5400 (desc->version == EINA_VALUE_STRUCT_DESC_VERSION, NULL);
5401
5402 m = eina_model_new(EINA_MODEL_TYPE_STRUCT);
5403 EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
5404
5405 EINA_SAFETY_ON_FALSE_GOTO(_eina_model_struct_set(m, desc, NULL), error);
5406 return m;
5407
5408 error:
5409 eina_model_del(m);
5410 return NULL;
5411}
5412
5413EAPI Eina_Model *
5414eina_model_type_struct_new(const Eina_Model_Type *type, const Eina_Value_Struct_Desc *desc)
5415{
5416 Eina_Model *m;
5417
5418 EINA_SAFETY_ON_FALSE_RETURN_VAL
5419 (eina_model_type_subclass_check(type, EINA_MODEL_TYPE_STRUCT), NULL);
5420 EINA_SAFETY_ON_NULL_RETURN_VAL(desc, NULL);
5421 EINA_SAFETY_ON_FALSE_RETURN_VAL
5422 (desc->version == EINA_VALUE_STRUCT_DESC_VERSION, NULL);
5423
5424 m = eina_model_new(type);
5425 EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
5426
5427 EINA_SAFETY_ON_FALSE_GOTO(_eina_model_struct_set(m, desc, NULL), error);
5428 return m;
5429
5430 error:
5431 eina_model_del(m);
5432 return NULL;
5433}
5434
5435EAPI Eina_Bool
5436eina_model_struct_set(Eina_Model *model, const Eina_Value_Struct_Desc *desc, void *memory)
5437{
5438 EINA_SAFETY_ON_NULL_RETURN_VAL(desc, EINA_FALSE);
5439 EINA_SAFETY_ON_FALSE_RETURN_VAL
5440 (desc->version == EINA_VALUE_STRUCT_DESC_VERSION, EINA_FALSE);
5441 EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL
5442 (&_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base, model, EINA_FALSE);
5443
5444 return _eina_model_struct_set(model, desc, memory);
5445}
5446
5447EAPI Eina_Bool
5448eina_model_struct_get(const Eina_Model *model, const Eina_Value_Struct_Desc **p_desc, void **p_memory)
5449{
5450 const Eina_Value *val;
5451 Eina_Value_Struct st;
5452
5453 EINA_SAFETY_ON_NULL_RETURN_VAL(p_desc, EINA_FALSE);
5454
5455 *p_desc = NULL;
5456 if (p_memory) *p_memory = NULL;
5457
5458 EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL
5459 (&_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base, model, EINA_FALSE);
5460
5461 val = eina_model_interface_private_data_get
5462 (model, &_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base);
5463
5464 EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_pget(val, &st), EINA_FALSE);
5465
5466 *p_desc = st.desc;
5467 if (p_memory) *p_memory = st.memory;
5468 return EINA_FALSE;
5469}
5470
5471EAPI void
5472eina_models_usage_dump(void)
5473{
5474 const Eina_List *l;
5475 const Eina_Model *m;
5476
5477 eina_lock_take(&_eina_model_debug_list_lock);
5478
5479 puts("DDD: model refs info (type, holders, backtrace)");
5480 puts("DDD: -------------- -------------- ---------------------------------");
5481
5482 EINA_LIST_FOREACH(_eina_model_debug_list, l, m)
5483 {
5484 Eina_Model_XRef *ref;
5485
5486 printf("DDD: %14p %14d %s\n",
5487 m, m->refcount, m->desc->cache.types[0]->name);
5488
5489 EINA_INLIST_FOREACH(m->xrefs, ref)
5490 {
5491 printf("DDD: id: %p '%s'\n",
5492 ref->id, ref->label);
5493 if (ref->backtrace.count)
5494 {
5495 char **symbols;
5496 unsigned int i;
5497
5498#ifdef HAVE_BACKTRACE_SYMBOLS
5499 symbols = backtrace_symbols((void * const *)ref->backtrace.symbols,
5500 ref->backtrace.count);
5501#else
5502 symbols = NULL;
5503#endif
5504
5505 printf("DDD: Backtrace: Address Symbol\n");
5506 for (i = 0; i < ref->backtrace.count; i++)
5507 printf("DDD: %14p %s\n",
5508 ref->backtrace.symbols[i],
5509 symbols ? symbols[i] : "???");
5510
5511 free(symbols);
5512 puts("DDD:");
5513 }
5514 }
5515 }
5516
5517 eina_lock_release(&_eina_model_debug_list_lock);
5518}
5519
5520EAPI Eina_List *
5521eina_models_list_get(void)
5522{
5523 const Eina_List *l;
5524 Eina_Model *m;
5525 Eina_List *ret = NULL;
5526
5527 eina_lock_take(&_eina_model_debug_list_lock);
5528
5529 EINA_LIST_FOREACH(_eina_model_debug_list, l, m)
5530 {
5531 ret = eina_list_append
5532 (ret, eina_model_xref
5533 (m, eina_models_list_get, "eina_models_list_get"));
5534 }
5535
5536 eina_lock_release(&_eina_model_debug_list_lock);
5537
5538 return ret;
5539}
5540
5541EAPI void
5542eina_models_list_free(Eina_List *list)
5543{
5544 Eina_Model *m;
5545
5546 EINA_LIST_FREE(list, m)
5547 eina_model_xunref(m, eina_models_list_get);
5548}