1 /*
2  * Copyright (C) 2010 Canonical, Ltd.
3  *
4  * This library is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License
6  * version 3.0 as published by the Free Software Foundation.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU Lesser General Public License version 3.0 for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public
14  * License along with this library. If not, see
15  * <http://www.gnu.org/licenses/>.
16  *
17  * Authored by:
18  *               Mikkel Kamstrup Erlandsen <mikkel.kamstrup@canonical.com>
19  */
20 
21 /**
22  * SECTION:dee-serializable-model
23  * @short_description: Abstract base class for easing implementations of
24  *                     #DeeModel<!-- -->s providing a unique version number
25  *                     for each row
26  * @include: dee.h
27  *
28  * #DeeSerializableModel is an abstract base class to ease implementation of
29  * #DeeModel<!-- -->s providing rows versioned by a
30  * <emphasis>sequence number</emphasis>.
31  *
32  */
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif
36 
37 #include <memory.h>
38 #include <time.h>
39 #include <unistd.h>
40 
41 #include "dee-model.h"
42 #include "dee-serializable-model.h"
43 #include "dee-serializable.h"
44 #include "dee-marshal.h"
45 #include "trace-log.h"
46 
47 static void     dee_serializable_model_model_iface_init (DeeModelIface *iface);
48 static void     dee_serializable_model_serializable_iface_init (DeeSerializableIface *iface);
49 static GObject* dee_serializable_model_parse_serialized (GVariant *data);
50 
51 #define MODEL_VARIANT_TYPE_1_0 G_VARIANT_TYPE ("(asaav(tt))")
52 #define MODEL_VARIANT_TYPE     G_VARIANT_TYPE ("(asaav(tt)a{sv})")
53 
54 /**
55  * DeeSerializableModelPrivate:
56  *
57  * Ignore this structure.
58  */
59 struct _DeeSerializableModelPrivate
60 {
61   /* Seqnum tracking */
62   guint64     seqnum;
63 
64   /* Column type info */
65   guint       n_columns;
66   gchar     **column_schemas; // NULL terminated
67   gchar     **column_names;   // NULL terminated
68   guint32    *column_name_hashes;
69   GHashTable *field_schemas;
70   gboolean    inside_changeset;
71 };
72 
73 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (DeeSerializableModel,
74                                   dee_serializable_model,
75                                   G_TYPE_OBJECT,
76                                   G_ADD_PRIVATE(DeeSerializableModel)
77                                   G_IMPLEMENT_INTERFACE (DEE_TYPE_MODEL,
78                                                          dee_serializable_model_model_iface_init)
79                                   G_IMPLEMENT_INTERFACE (DEE_TYPE_SERIALIZABLE,
80                                                          dee_serializable_model_serializable_iface_init));
81 
82 typedef struct _FieldSchemaInfo FieldSchemaInfo;
83 
84 struct _FieldSchemaInfo
85 {
86   gint   ref_count;     // thread unsafe refcount
87   gchar *schema;
88   guint  column;
89 };
90 
91 /*
92  * Public overridable DeeSerializableModel methods
93  */
94 static guint64   dee_serializable_model_get_seqnum_real  (DeeModel     *self);
95 
96 static void      dee_serializable_model_set_seqnum_real  (DeeModel     *self,
97                                                        guint64       seqnum);
98 
99 static guint64   dee_serializable_model_inc_seqnum_real  (DeeModel     *self);
100 
101 /*
102  * DeeModel forward declarations
103  */
104 static const gchar* const*   dee_serializable_model_get_schema (DeeModel *self,
105                                                              guint    *num_columns);
106 
107 static const gchar*   dee_serializable_model_get_column_schema (DeeModel *self,
108                                                                 guint     column);
109 
110 static const gchar*   dee_serializable_model_get_field_schema  (DeeModel    *self,
111                                                                 const gchar *field_name,
112                                                                 guint       *out_column);
113 
114 static gint           dee_serializable_model_get_column_index  (DeeModel    *self,
115                                                                 const gchar *column_name);
116 
117 static void           dee_serializable_model_set_schema_full  (DeeModel           *self,
118                                                             const gchar* const *column_schemas,
119                                                             guint               num_columns);
120 
121 static void           dee_serializable_model_set_column_names_full (DeeModel     *self,
122                                                                     const gchar **column_names,
123                                                                     guint         num_columns);
124 
125 static const gchar**  dee_serializable_model_get_column_names (DeeModel *self,
126                                                                guint    *num_columns);
127 
128 static void           dee_serializable_model_register_vardict_schema (DeeModel     *self,
129                                                                       guint         column,
130                                                                       GHashTable   *schema);
131 
132 static GHashTable*    dee_serializable_model_get_vardict_schema (DeeModel *self,
133                                                                  guint     column);
134 
135 static guint          dee_serializable_model_get_n_columns  (DeeModel *self);
136 
137 static guint          dee_serializable_model_get_n_rows     (DeeModel *self);
138 
139 static void           dee_serializable_model_clear          (DeeModel *self);
140 
141 static DeeModelIter*  dee_serializable_model_append_row  (DeeModel  *self,
142                                                        GVariant **row_members);
143 
144 static DeeModelIter*  dee_serializable_model_prepend_row  (DeeModel  *self,
145                                                         GVariant **row_members);
146 
147 static DeeModelIter*  dee_serializable_model_insert_row  (DeeModel  *self,
148                                                        guint      pos,
149                                                        GVariant **row_members);
150 
151 static DeeModelIter*  dee_serializable_model_insert_row_before (DeeModel      *self,
152                                                              DeeModelIter  *iter,
153                                                              GVariant     **row_members);
154 
155 static DeeModelIter*  dee_serializable_model_insert_row_sorted (DeeModel           *self,
156                                                                 GVariant          **row_members,
157                                                                 DeeCompareRowFunc   cmp_func,
158                                                                 gpointer            user_data);
159 
160 static DeeModelIter*  dee_serializable_model_find_row_sorted   (DeeModel           *self,
161                                                                 GVariant          **row_spec,
162                                                                 DeeCompareRowFunc   cmp_func,
163                                                                 gpointer            user_data,
164                                                                 gboolean           *out_was_found);
165 
166 static void           dee_serializable_model_remove         (DeeModel     *self,
167                                                           DeeModelIter *iter);
168 
169 static void           dee_serializable_model_set_value      (DeeModel       *self,
170                                                           DeeModelIter   *iter,
171                                                           guint           column,
172                                                           GVariant       *value);
173 
174 static void           dee_serializable_model_set_row            (DeeModel       *self,
175                                                               DeeModelIter   *iter,
176                                                               GVariant      **row_members);
177 
178 static GVariant*     dee_serializable_model_get_value      (DeeModel     *self,
179                                                           DeeModelIter *iter,
180                                                           guint         column);
181 
182 static GVariant*     dee_serializable_model_get_value_by_name (DeeModel     *self,
183                                                                DeeModelIter *iter,
184                                                                const gchar  *column_name);
185 
186 static GVariant**    dee_serializable_model_get_row         (DeeModel    *self,
187                                                              DeeModelIter *iter,
188                                                              GVariant    **out_row_members);
189 
190 static DeeModelIter* dee_serializable_model_get_first_iter  (DeeModel     *self);
191 
192 static DeeModelIter* dee_serializable_model_get_last_iter   (DeeModel     *self);
193 
194 static DeeModelIter* dee_serializable_model_get_iter_at_row (DeeModel     *self,
195                                                          guint          row);
196 
197 static gboolean       dee_serializable_model_get_bool       (DeeModel    *self,
198                                                          DeeModelIter *iter,
199                                                          guint         column);
200 
201 static guchar         dee_serializable_model_get_uchar      (DeeModel     *self,
202                                                          DeeModelIter *iter,
203                                                          guint          column);
204 
205 static gint32         dee_serializable_model_get_int32     (DeeModel     *self,
206                                                          DeeModelIter *iter,
207                                                          guint          column);
208 
209 static guint32        dee_serializable_model_get_uint32    (DeeModel     *self,
210                                                          DeeModelIter *iter,
211                                                          guint          column);
212 
213 static gint64         dee_serializable_model_get_int64      (DeeModel     *self,
214                                                          DeeModelIter *iter,
215                                                          guint          column);
216 
217 static guint64        dee_serializable_model_get_uint64     (DeeModel     *self,
218                                                          DeeModelIter *iter,
219                                                          guint          column);
220 
221 static gdouble        dee_serializable_model_get_double     (DeeModel     *self,
222                                                          DeeModelIter *iter,
223                                                          guint          column);
224 
225 static const gchar*   dee_serializable_model_get_string     (DeeModel     *self,
226                                                          DeeModelIter *iter,
227                                                          guint          column);
228 
229 static DeeModelIter* dee_serializable_model_next            (DeeModel     *self,
230                                                          DeeModelIter *iter);
231 
232 static DeeModelIter* dee_serializable_model_prev            (DeeModel     *self,
233                                                          DeeModelIter *iter);
234 
235 static gboolean       dee_serializable_model_is_first       (DeeModel     *self,
236                                                          DeeModelIter *iter);
237 
238 static gboolean       dee_serializable_model_is_last        (DeeModel     *self,
239                                                          DeeModelIter *iter);
240 
241 static void           dee_serializable_model_begin_changeset (DeeModel    *self);
242 
243 static void           dee_serializable_model_end_changeset   (DeeModel    *self);
244 
245 static guint sigid_changeset_started = 0;
246 static guint sigid_changeset_finished = 0;
247 
248 /* FieldSchemaInfo methods */
249 static FieldSchemaInfo*
field_schema_info_new(const gchar * schema,guint column)250 field_schema_info_new (const gchar *schema, guint column)
251 {
252   FieldSchemaInfo *info;
253 
254   info = g_slice_new (FieldSchemaInfo);
255   info->ref_count = 1;
256   info->schema = g_strdup (schema);
257   info->column = column;
258 
259   return info;
260 }
261 
262 static FieldSchemaInfo*
field_schema_info_ref(FieldSchemaInfo * info)263 field_schema_info_ref (FieldSchemaInfo *info)
264 {
265   g_return_val_if_fail (info, NULL);
266 
267   info->ref_count++;
268 
269   return info;
270 }
271 
272 static void
field_schema_info_unref(FieldSchemaInfo * info)273 field_schema_info_unref (FieldSchemaInfo *info)
274 {
275   g_return_if_fail (info);
276   g_return_if_fail (info->ref_count > 0);
277 
278   if (--info->ref_count <= 0)
279   {
280     g_free (info->schema);
281     g_slice_free (FieldSchemaInfo, info);
282   }
283 }
284 
285 /* GObject Init */
286 static void
dee_serializable_model_finalize(GObject * object)287 dee_serializable_model_finalize (GObject *object)
288 {
289   DeeSerializableModelPrivate *priv = DEE_SERIALIZABLE_MODEL (object)->priv;
290 
291   priv->n_columns = 0;
292   priv->seqnum = 0;
293 
294   if (priv->column_schemas != NULL)
295     {
296       g_strfreev (priv->column_schemas);
297       priv->column_schemas = NULL;
298     }
299 
300   if (priv->column_names != NULL)
301     {
302       g_strfreev (priv->column_names);
303       priv->column_names = NULL;
304     }
305 
306   if (priv->column_name_hashes != NULL)
307     {
308       g_free (priv->column_name_hashes);
309       priv->column_name_hashes = NULL;
310     }
311 
312   if (priv->field_schemas != NULL)
313     {
314       g_hash_table_unref (priv->field_schemas);
315       priv->field_schemas = NULL;
316     }
317 
318   G_OBJECT_CLASS (dee_serializable_model_parent_class)->finalize (object);
319 }
320 
321 static void
dee_serializable_model_set_property(GObject * object,guint id,const GValue * value,GParamSpec * pspec)322 dee_serializable_model_set_property (GObject      *object,
323                                  guint         id,
324                                  const GValue *value,
325                                  GParamSpec   *pspec)
326 {
327   switch (id)
328     {
329     default:
330       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, id, pspec);
331       break;
332     }
333 }
334 
335 static void
dee_serializable_model_get_property(GObject * object,guint id,GValue * value,GParamSpec * pspec)336 dee_serializable_model_get_property (GObject    *object,
337                                  guint       id,
338                                  GValue     *value,
339                                  GParamSpec *pspec)
340 {
341   switch (id)
342     {
343     default:
344       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, id, pspec);
345       break;
346     }
347 }
348 
349 static void
dee_serializable_model_class_init(DeeSerializableModelClass * klass)350 dee_serializable_model_class_init (DeeSerializableModelClass *klass)
351 {
352   GObjectClass  *obj_class = G_OBJECT_CLASS (klass);
353 
354   obj_class->finalize     = dee_serializable_model_finalize;
355   obj_class->set_property = dee_serializable_model_set_property;
356   obj_class->get_property = dee_serializable_model_get_property;
357 
358   klass->get_seqnum = dee_serializable_model_get_seqnum_real;
359   klass->set_seqnum = dee_serializable_model_set_seqnum_real;
360   klass->inc_seqnum = dee_serializable_model_inc_seqnum_real;
361 
362   sigid_changeset_started = g_signal_lookup ("changeset-started", DEE_TYPE_MODEL);
363   sigid_changeset_finished = g_signal_lookup ("changeset-finished", DEE_TYPE_MODEL);
364 }
365 
366 static void
dee_serializable_model_init(DeeSerializableModel * model)367 dee_serializable_model_init (DeeSerializableModel *model)
368 {
369   DeeSerializableModelPrivate *priv;
370 
371   priv = model->priv = dee_serializable_model_get_instance_private (model);
372 
373   priv->seqnum = 0;
374 
375   priv->n_columns = 0;
376   priv->column_schemas = NULL;
377 
378 
379 }
380 
381 static guint64
dee_serializable_model_get_seqnum_real(DeeModel * self)382 dee_serializable_model_get_seqnum_real (DeeModel *self)
383 {
384   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), 0);
385 
386   return DEE_SERIALIZABLE_MODEL (self)->priv->seqnum;
387 }
388 
389 
390 /**
391  * dee_serializable_model_get_seqnum:
392  *
393  * @self: (type DeeSerializableModel): A #DeeSerializableModel instance
394  *
395  * Return value: Sequence number of this #DeeSerializableModel.
396  */
397 guint64
dee_serializable_model_get_seqnum(DeeModel * self)398 dee_serializable_model_get_seqnum (DeeModel *self)
399 {
400   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), 0);
401 
402   return DEE_SERIALIZABLE_MODEL_GET_CLASS (self)->get_seqnum (self);
403 }
404 
405 static void
dee_serializable_model_set_seqnum_real(DeeModel * self,guint64 seqnum)406 dee_serializable_model_set_seqnum_real (DeeModel *self,
407                                           guint64   seqnum)
408 {
409   g_return_if_fail (DEE_IS_SERIALIZABLE_MODEL (self));
410 
411   DEE_SERIALIZABLE_MODEL (self)->priv->seqnum = seqnum;
412 }
413 
414 /**
415  * dee_serializable_model_set_seqnum:
416  *
417  * @self: (type DeeSerializableModel): A #DeeSerializableModel instance
418  * @seqnum: Sequence number
419  *
420  * Sets sequence number of this #DeeSerializableModel.
421  */
422 void
dee_serializable_model_set_seqnum(DeeModel * self,guint64 seqnum)423 dee_serializable_model_set_seqnum (DeeModel *self,
424                                      guint64   seqnum)
425 {
426   g_return_if_fail (DEE_IS_SERIALIZABLE_MODEL (self));
427 
428   DEE_SERIALIZABLE_MODEL_GET_CLASS (self)->set_seqnum (self, seqnum);
429 }
430 
431 static guint64
dee_serializable_model_inc_seqnum_real(DeeModel * self)432 dee_serializable_model_inc_seqnum_real (DeeModel *self)
433 {
434   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), 0);
435 
436   return ++DEE_SERIALIZABLE_MODEL (self)->priv->seqnum;
437 }
438 
439 /**
440  * dee_serializable_model_inc_seqnum:
441  *
442  * @self: (type DeeSerializableModel): A #DeeSerializableModel instance
443  *
444  * Increments sequence number of this #DeeSerializableModel.
445  */
446 guint64
dee_serializable_model_inc_seqnum(DeeModel * self)447 dee_serializable_model_inc_seqnum (DeeModel *self)
448 {
449   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), 0);
450 
451   return DEE_SERIALIZABLE_MODEL_GET_CLASS (self)->inc_seqnum (self);
452 }
453 
454 /*
455  * DeeModel API
456  */
457 
458 static void
dee_serializable_model_set_schema_full(DeeModel * self,const gchar * const * column_schemas,guint num_columns)459 dee_serializable_model_set_schema_full  (DeeModel           *self,
460                                       const gchar* const *column_schemas,
461                                       guint               num_columns)
462 {
463   DeeSerializableModelPrivate  *priv;
464   gchar                    **column_schemas_copy;
465   guint                      i;
466 
467   g_return_if_fail (DEE_IS_SERIALIZABLE_MODEL (self));
468   g_return_if_fail (column_schemas != NULL);
469 
470   priv = DEE_SERIALIZABLE_MODEL (self)->priv;
471 
472   if (priv->column_schemas != NULL)
473     {
474       g_critical ("The DeeModel %p already has a schema", self);
475       return;
476     }
477 
478   /* Allocate space to store the column schemas. We NULL terminate it
479    * in order to play well with g_strfreev() */
480   column_schemas_copy = g_new0 (gchar*, num_columns + 1);
481 
482   /* Validate the type strings and copy the schema for our selves */
483   for (i = 0; i < num_columns; i++)
484     {
485       if (!g_variant_type_string_is_valid (column_schemas[i]))
486         {
487           g_critical ("When setting schema for DeeModel %p: '%s' is not a "
488                       "valid type string", self, column_schemas[i]);
489           return;
490         }
491       column_schemas_copy[i] = g_strdup (column_schemas[i]);
492     }
493 
494   /* Register the validated types as our column types */
495   priv->column_schemas = column_schemas_copy; // steal
496   priv->n_columns = num_columns;
497 
498 #ifdef ENABLE_TRACE_LOG
499   gchar* schema = g_strjoinv (", ", priv->column_schemas);
500   trace_object (self, "Set schema: (%s)", schema);
501   g_free (schema);
502 #endif
503 }
504 
505 static void
dee_serializable_model_set_column_names_full(DeeModel * self,const gchar ** column_names,guint num_columns)506 dee_serializable_model_set_column_names_full (DeeModel     *self,
507                                               const gchar **column_names,
508                                               guint         num_columns)
509 {
510   DeeSerializableModelPrivate *priv;
511   guint i, j;
512   gboolean any_name_null;
513 
514   g_return_if_fail (DEE_IS_SERIALIZABLE_MODEL (self));
515 
516   priv = DEE_SERIALIZABLE_MODEL (self)->priv;
517 
518   any_name_null = FALSE;
519   for (i = 0; i < num_columns; i++)
520     any_name_null |= column_names[i] == NULL;
521 
522   if (num_columns < priv->n_columns || any_name_null)
523     {
524       g_critical ("All column names have to be set!");
525       return;
526     }
527 
528   if (priv->column_names) g_strfreev (priv->column_names);
529   if (priv->column_name_hashes) g_free (priv->column_name_hashes);
530 
531   priv->column_names = g_new0 (gchar*, priv->n_columns + 1);
532   priv->column_name_hashes = g_new0 (guint32, priv->n_columns);
533 
534   for (i = 0; i < num_columns; i++)
535     {
536       priv->column_names[i] = g_strdup (column_names[i]);
537 
538       // hash for fast compares
539       priv->column_name_hashes[i] = column_names[i] != NULL ?
540         g_str_hash (column_names[i]) : 0;
541     }
542 
543   // check for uniqueness
544   for (i = 0; i < num_columns; i++)
545     {
546       for (j = i+1; j < num_columns; j++)
547         {
548           if (g_strcmp0 (priv->column_names[i], priv->column_names[j]) == 0)
549             {
550               g_warning ("Column names for columns %u and %u are the same!",
551                          i, j);
552             }
553         }
554     }
555 }
556 
557 static const gchar**
dee_serializable_model_get_column_names(DeeModel * self,guint * n_columns)558 dee_serializable_model_get_column_names (DeeModel *self,
559                                          guint    *n_columns)
560 {
561   DeeSerializableModelPrivate *priv;
562 
563   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), NULL);
564 
565   priv = ((DeeSerializableModel*) self)->priv;
566 
567   if (n_columns != NULL)
568     *n_columns = priv->n_columns;
569 
570   return (const gchar**) priv->column_names;
571 }
572 
573 static void
dee_serializable_model_register_vardict_schema(DeeModel * self,guint column,GHashTable * schema)574 dee_serializable_model_register_vardict_schema (DeeModel     *self,
575                                                 guint         column,
576                                                 GHashTable   *schema)
577 {
578   DeeSerializableModelPrivate *priv;
579   GHashTableIter iter;
580   gpointer       key, value;
581 
582   g_return_if_fail (DEE_IS_SERIALIZABLE_MODEL (self));
583   g_return_if_fail (schema);
584 
585   priv = ((DeeSerializableModel*) self)->priv;
586   g_return_if_fail (priv->column_schemas);
587   g_return_if_fail (column < priv->n_columns);
588   g_return_if_fail (g_variant_type_is_subtype_of (G_VARIANT_TYPE (priv->column_schemas[column]),
589                                                   G_VARIANT_TYPE_VARDICT));
590 
591   if (priv->column_names == NULL || priv->column_names[column] == NULL)
592     {
593       g_critical ("Column name for column %u has to be set before calling "
594                   "dee_model_register_vardict_schema", column);
595       return;
596     }
597 
598   if (priv->field_schemas == NULL)
599     priv->field_schemas = g_hash_table_new_full (g_str_hash, g_str_equal,
600                                                  g_free,
601                                                  (GDestroyNotify) field_schema_info_unref);
602 
603   g_hash_table_iter_init (&iter, schema);
604   while (g_hash_table_iter_next (&iter, &key, &value))
605     {
606       FieldSchemaInfo *info;
607       const gchar     *field_schema;
608       gchar *full_name;
609       guint  registered_column;
610 
611       field_schema = dee_model_get_field_schema (self, key, &registered_column);
612       if (field_schema && registered_column != column)
613         {
614           g_warning ("Field '%s' is already registered for column %u! Please "
615                      "use fully qualified names to refer to it ('%s::%s' and "
616                      "'%s::%s')",
617                      (gchar*) key, registered_column,
618                      priv->column_names[registered_column], (gchar*) key,
619                      priv->column_names[column], (gchar*) key);
620         }
621       else if (field_schema && !g_str_equal (field_schema, value))
622         {
623           g_warning ("Field '%s' was already registered with schema '%s'! "
624                      "Overwriting with schema '%s'",
625                      (gchar*) key, field_schema, (gchar*) value);
626         }
627 
628       info = field_schema_info_new (value, column);
629       g_hash_table_insert (priv->field_schemas, g_strdup (key), info);
630       full_name = g_strdup_printf ("%s::%s", priv->column_names[column],
631                                    (gchar*) key);
632       /* transfering ownership of full_name to hashtable */
633       g_hash_table_insert (priv->field_schemas, full_name,
634                            field_schema_info_ref (info));
635     }
636 }
637 
638 static GHashTable*
dee_serializable_model_get_vardict_schema(DeeModel * self,guint column)639 dee_serializable_model_get_vardict_schema (DeeModel     *self,
640                                            guint         column)
641 {
642   DeeSerializableModelPrivate *priv;
643   GHashTable    *result;
644   GHashTableIter iter;
645   gpointer       key, value;
646 
647   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), NULL);
648 
649   priv = ((DeeSerializableModel*) self)->priv;
650   g_return_val_if_fail (priv->column_schemas, NULL);
651   g_return_val_if_fail (column < priv->n_columns, NULL);
652   g_return_val_if_fail (g_variant_type_is_subtype_of (G_VARIANT_TYPE (priv->column_schemas[column]),
653                                                   G_VARIANT_TYPE_VARDICT), NULL);
654 
655   if (priv->field_schemas == NULL) return NULL;
656 
657   result = g_hash_table_new (g_str_hash, g_str_equal);
658   g_hash_table_iter_init (&iter, priv->field_schemas);
659   while (g_hash_table_iter_next (&iter, &key, &value))
660     {
661       gchar *field, *field_name;
662       FieldSchemaInfo *info;
663 
664       field = (gchar*) key;
665       info = (FieldSchemaInfo*) value;
666       if (info->column != column) continue;
667 
668       field_name = strstr (field, "::");
669       field_name = field_name != NULL ? field_name + 2 : field;
670 
671       g_hash_table_insert (result, field_name, info->schema);
672     }
673 
674   return result;
675 }
676 
677 static const gchar* const*
dee_serializable_model_get_schema(DeeModel * self,guint * n_columns)678 dee_serializable_model_get_schema (DeeModel *self,
679                                    guint    *n_columns)
680 {
681   DeeSerializableModelPrivate *priv;
682 
683   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), NULL);
684 
685   priv = ((DeeSerializableModel*) self)->priv;
686 
687   if (n_columns != NULL)
688     *n_columns = priv->n_columns;
689 
690   return (const gchar**) priv->column_schemas;
691 }
692 
693 static const gchar*
dee_serializable_model_get_column_schema(DeeModel * self,guint column)694 dee_serializable_model_get_column_schema (DeeModel *self,
695                                        guint     column)
696 {
697   DeeSerializableModelPrivate *priv;
698 
699   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), NULL);
700 
701   priv = ((DeeSerializableModel*) self)->priv;
702   g_return_val_if_fail (column < priv->n_columns, NULL);
703 
704   return priv->column_schemas[column];
705 }
706 
707 static const gchar*
dee_serializable_model_get_field_schema(DeeModel * self,const gchar * field_name,guint * out_column)708 dee_serializable_model_get_field_schema (DeeModel    *self,
709                                          const gchar *field_name,
710                                          guint       *out_column)
711 {
712   DeeSerializableModelPrivate *priv;
713   FieldSchemaInfo *info;
714 
715   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), NULL);
716   g_return_val_if_fail (field_name, NULL);
717 
718   priv = ((DeeSerializableModel*) self)->priv;
719 
720   if (priv->field_schemas == NULL) return NULL;
721 
722   info = g_hash_table_lookup (priv->field_schemas, field_name);
723   if (info == NULL) return NULL;
724 
725   if (out_column) *out_column = info->column;
726 
727   return info->schema;
728 }
729 
730 static gint
dee_serializable_model_get_column_index(DeeModel * self,const gchar * column_name)731 dee_serializable_model_get_column_index (DeeModel    *self,
732                                          const gchar *column_name)
733 {
734   gint                         i;
735   guint                        hash;
736   DeeSerializableModelPrivate *priv;
737 
738   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), -1);
739 
740   priv = ((DeeSerializableModel*) self)->priv;
741 
742   if (priv->column_names == NULL || column_name == NULL) return -1;
743 
744   hash = g_str_hash (column_name);
745 
746   // FIXME: use a hashtable instead?
747   for (i = 0; i < priv->n_columns; i++)
748   {
749     if (priv->column_name_hashes[i] == hash &&
750         g_str_equal (priv->column_names[i], column_name)) return i;
751   }
752 
753   return -1;
754 }
755 
756 static guint
dee_serializable_model_get_n_columns(DeeModel * self)757 dee_serializable_model_get_n_columns (DeeModel *self)
758 {
759   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), 0);
760 
761   return ((DeeSerializableModel*) self)->priv->n_columns;
762 }
763 
764 static guint
dee_serializable_model_get_n_rows(DeeModel * self)765 dee_serializable_model_get_n_rows (DeeModel *self)
766 {
767   DeeModelIter *iter, *end;
768   guint         count;
769 
770   count = 0;
771   end = dee_model_get_last_iter (self);
772   iter = dee_model_get_first_iter (self);
773   while (iter != end)
774     {
775       iter = dee_model_next (self, iter);
776       count++;
777     }
778 
779   return count;
780 }
781 
782 static void
dee_serializable_model_clear(DeeModel * self)783 dee_serializable_model_clear (DeeModel *self)
784 {
785   DeeModelIter            *iter, *end;
786 
787   g_return_if_fail (DEE_IS_SERIALIZABLE_MODEL (self));
788 
789   iter = dee_model_get_first_iter (self);
790   end = dee_model_get_last_iter (self);
791 
792   while (iter != end)
793     {
794       dee_model_remove (self, iter);
795       iter = dee_model_get_first_iter (self);
796     }
797 }
798 
799 static DeeModelIter*
dee_serializable_model_prepend_row(DeeModel * self,GVariant ** row_members)800 dee_serializable_model_prepend_row (DeeModel  *self,
801                                  GVariant **row_members)
802 {
803   DeeModelIter *iter;
804 
805   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), NULL);
806 
807   iter = dee_model_get_first_iter (self);
808   return dee_model_insert_row_before (self, iter, row_members);
809 }
810 
811 static DeeModelIter*
dee_serializable_model_append_row(DeeModel * self,GVariant ** row_members)812 dee_serializable_model_append_row (DeeModel  *self,
813                                    GVariant **row_members)
814 {
815   DeeModelIter *iter;
816 
817   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), NULL);
818 
819   iter = dee_model_get_last_iter (self);
820   return dee_model_insert_row_before (self, iter, row_members);
821 }
822 
823 static DeeModelIter*
dee_serializable_model_insert_row(DeeModel * self,guint pos,GVariant ** row_members)824 dee_serializable_model_insert_row (DeeModel  *self,
825                                    guint      pos,
826                                    GVariant **row_members)
827 {
828   DeeModelIter *iter;
829 
830   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), NULL);
831 
832   if (pos > 0)
833     {
834       iter = dee_model_get_iter_at_row (self, pos);
835       return dee_model_insert_row_before (self, iter, row_members);
836     }
837   else if (pos == 0)
838     return dee_model_prepend_row (self, row_members);
839   else
840     return dee_model_append_row (self, row_members);
841 }
842 
843 static DeeModelIter*
dee_serializable_model_insert_row_before(DeeModel * self,DeeModelIter * iter,GVariant ** row_members)844 dee_serializable_model_insert_row_before (DeeModel      *self,
845                                        DeeModelIter  *iter,
846                                        GVariant     **row_members)
847 {
848   g_critical ("%s not implemented", G_STRFUNC);
849   return NULL;
850 }
851 
852 static DeeModelIter*
dee_serializable_model_insert_row_sorted(DeeModel * self,GVariant ** row_members,DeeCompareRowFunc cmp_func,gpointer user_data)853 dee_serializable_model_insert_row_sorted (DeeModel           *self,
854                                           GVariant          **row_members,
855                                           DeeCompareRowFunc   cmp_func,
856                                           gpointer            user_data)
857 {
858   DeeModelIter *iter;
859   gboolean was_found;
860 
861   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), NULL);
862   g_return_val_if_fail (row_members != NULL, NULL);
863   g_return_val_if_fail (cmp_func != NULL, NULL);
864 
865   iter = dee_model_find_row_sorted (self, row_members, cmp_func,
866                                     user_data, &was_found);
867   if (was_found)
868     iter = dee_model_next (self, iter);
869 
870   return dee_model_insert_row_before (self, iter, row_members);
871 }
872 
873 static DeeModelIter*
dee_serializable_model_find_row_sorted(DeeModel * self,GVariant ** row_spec,DeeCompareRowFunc cmp_func,gpointer user_data,gboolean * out_was_found)874 dee_serializable_model_find_row_sorted   (DeeModel           *self,
875                                           GVariant          **row_spec,
876                                           DeeCompareRowFunc   cmp_func,
877                                           gpointer            user_data,
878                                           gboolean           *out_was_found)
879 {
880   DeeModelIter  *iter, *end, *last_matching;
881   GVariant     **row_buf;
882   gint           cmp_result;
883   guint          n_cols, i;
884 
885   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), NULL);
886   g_return_val_if_fail (row_spec != NULL, NULL);
887   g_return_val_if_fail (cmp_func != NULL, NULL);
888 
889   last_matching = NULL;
890   if (out_was_found != NULL) *out_was_found = FALSE;
891   n_cols = dee_model_get_n_columns (self);
892 
893   /* Stack allocate the buffer for speed, and so we don't have to free */
894   row_buf = g_alloca (n_cols * sizeof (gpointer));
895 
896   iter = dee_model_get_first_iter (self);
897   end = dee_model_get_last_iter (self);
898   while (iter != end)
899     {
900       dee_model_get_row (self, iter, row_buf);
901       cmp_result = cmp_func (row_buf, row_spec, user_data);
902       /* we're returning last matching row to make ordering
903        * of insert_row_sorted stable and fast */
904       while (cmp_result == 0)
905         {
906           last_matching = iter;
907           iter = dee_model_next (self, iter);
908           if (iter == end)
909             {
910               iter = last_matching;
911               break;
912             }
913           for (i = 0; i < n_cols; i++) g_variant_unref (row_buf[i]);
914           dee_model_get_row (self, iter, row_buf);
915           cmp_result = cmp_func (row_buf, row_spec, user_data);
916         }
917 
918       for (i = 0; i < n_cols; i++) g_variant_unref (row_buf[i]);
919       /* if we're past the matching row, the loop can be quit */
920       if (cmp_result >= 0) break;
921       iter = dee_model_next (self, iter);
922     }
923 
924   if (out_was_found != NULL && last_matching != NULL) *out_was_found = TRUE;
925   return last_matching ? last_matching : iter;
926 }
927 
928 static void
dee_serializable_model_remove(DeeModel * self,DeeModelIter * iter_)929 dee_serializable_model_remove (DeeModel     *self,
930                             DeeModelIter *iter_)
931 {
932   g_critical ("%s not implemented", G_STRFUNC);
933 }
934 
935 static void
dee_serializable_model_set_value(DeeModel * self,DeeModelIter * iter,guint column,GVariant * value)936 dee_serializable_model_set_value (DeeModel       *self,
937                                DeeModelIter   *iter,
938                                guint           column,
939                                GVariant       *value)
940 {
941   g_critical ("%s not implemented", G_STRFUNC);
942 }
943 
944 static void
dee_serializable_model_set_row(DeeModel * self,DeeModelIter * iter,GVariant ** row_members)945 dee_serializable_model_set_row (DeeModel       *self,
946                              DeeModelIter   *iter,
947                              GVariant      **row_members)
948 {
949   g_critical ("%s not implemented", G_STRFUNC);
950 }
951 
952 static GVariant*
dee_serializable_model_get_value(DeeModel * self,DeeModelIter * iter,guint column)953 dee_serializable_model_get_value (DeeModel     *self,
954                                DeeModelIter *iter,
955                                guint         column)
956 {
957   g_critical ("%s not implemented", G_STRFUNC);
958 
959   return NULL;
960 }
961 
962 static GVariant*
dee_serializable_model_get_value_by_name(DeeModel * self,DeeModelIter * iter,const gchar * column_name)963 dee_serializable_model_get_value_by_name (DeeModel     *self,
964                                           DeeModelIter *iter,
965                                           const gchar  *column_name)
966 {
967   gint col_index;
968 
969   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), NULL);
970 
971   col_index = dee_model_get_column_index (self, column_name);
972 
973   if (col_index >= 0)
974     {
975       return dee_model_get_value (self, iter, col_index);
976     }
977   else if (dee_model_get_field_schema (self, column_name, (guint*) &col_index))
978     {
979       GVariant    *dict, *result;
980       const gchar *key_name;
981 
982       dict = dee_model_get_value (self, iter, col_index);
983       // handle full "column::field" name
984       key_name = strstr(column_name, "::");
985       key_name = key_name != NULL ? key_name + 2 : column_name;
986       result = g_variant_lookup_value (dict, key_name, NULL);
987       g_variant_unref (dict);
988 
989       return result;
990     }
991 
992   return NULL;
993 }
994 
995 static GVariant**
dee_serializable_model_get_row(DeeModel * self,DeeModelIter * iter,GVariant ** out_row_members)996 dee_serializable_model_get_row (DeeModel      *self,
997                                 DeeModelIter  *iter,
998                                 GVariant     **out_row_members)
999 {
1000   guint            col, n_cols;
1001 
1002   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), NULL);
1003 
1004   n_cols = dee_model_get_n_columns (self);
1005 
1006   if (out_row_members == NULL)
1007     out_row_members = g_new0 (GVariant*, n_cols + 1);
1008 
1009   for (col = 0; col < n_cols; col++)
1010     out_row_members[col] = dee_model_get_value (self, iter, col);
1011 
1012   return out_row_members;
1013 }
1014 
1015 static gboolean
dee_serializable_model_get_bool(DeeModel * self,DeeModelIter * iter,guint column)1016 dee_serializable_model_get_bool (DeeModel     *self,
1017                                  DeeModelIter *iter,
1018                                  guint         column)
1019 {
1020   GVariant *value;
1021   gboolean  b;
1022 
1023   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), FALSE);
1024 
1025   value = dee_model_get_value (self, iter, column);
1026 
1027   if (G_UNLIKELY (value == NULL))
1028     {
1029       g_critical ("Failed to retrieve bool from row %u column %u in %s@%p",
1030                   dee_model_get_position (self, iter), column,
1031                   G_OBJECT_TYPE_NAME (self), self);
1032       return FALSE;
1033     }
1034 
1035   b = g_variant_get_boolean (value);
1036   g_variant_unref (value);
1037 
1038   return b;
1039 }
1040 
1041 static guchar
dee_serializable_model_get_uchar(DeeModel * self,DeeModelIter * iter,guint column)1042 dee_serializable_model_get_uchar (DeeModel      *self,
1043                                   DeeModelIter  *iter,
1044                                   guint          column)
1045 {
1046   GVariant *value;
1047   guchar    u;
1048 
1049   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), '\0');
1050 
1051   value = dee_model_get_value (self, iter, column);
1052 
1053   if (G_UNLIKELY (value == NULL))
1054     {
1055       g_critical ("Failed to retrieve uchar from row %u column %u in %s@%p",
1056                   dee_model_get_position (self, iter), column,
1057                   G_OBJECT_TYPE_NAME (self), self);
1058       return '\0';
1059     }
1060 
1061   u = g_variant_get_byte(value);
1062   g_variant_unref (value);
1063 
1064   return u;
1065 }
1066 
1067 static gint32
dee_serializable_model_get_int32(DeeModel * self,DeeModelIter * iter,guint column)1068 dee_serializable_model_get_int32 (DeeModel        *self,
1069                                   DeeModelIter    *iter,
1070                                   guint            column)
1071 {
1072   GVariant *value;
1073   gint32    i;
1074 
1075   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), 0);
1076 
1077   value = dee_model_get_value (self, iter, column);
1078 
1079   if (G_UNLIKELY (value == NULL))
1080     {
1081       g_critical ("Failed to retrieve int64 from row %u column %u in %s@%p",
1082                   dee_model_get_position (self, iter), column,
1083                   G_OBJECT_TYPE_NAME (self), self);
1084       return 0;
1085     }
1086 
1087   i = g_variant_get_int32 (value);
1088   g_variant_unref (value);
1089 
1090   return i;
1091 }
1092 
1093 static guint32
dee_serializable_model_get_uint32(DeeModel * self,DeeModelIter * iter,guint column)1094 dee_serializable_model_get_uint32 (DeeModel      *self,
1095                                    DeeModelIter  *iter,
1096                                    guint          column)
1097 {
1098   GVariant *value;
1099   guint32    u;
1100 
1101   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), 0);
1102 
1103   value = dee_model_get_value (self, iter, column);
1104 
1105   if (G_UNLIKELY (value == NULL))
1106     {
1107       g_critical ("Failed to retrieve uint32 from row %u column %u in %s@%p",
1108                   dee_model_get_position (self, iter), column,
1109                   G_OBJECT_TYPE_NAME (self), self);
1110       return 0;
1111     }
1112 
1113   u = g_variant_get_uint32 (value);
1114   g_variant_unref (value);
1115 
1116   return u;
1117 }
1118 
1119 
1120 static gint64
dee_serializable_model_get_int64(DeeModel * self,DeeModelIter * iter,guint column)1121 dee_serializable_model_get_int64 (DeeModel      *self,
1122                                   DeeModelIter  *iter,
1123                                   guint          column)
1124 {
1125   GVariant *value;
1126   gint64    i;
1127 
1128   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self),
1129                         G_GINT64_CONSTANT (0));
1130 
1131   value = dee_model_get_value (self, iter, column);
1132 
1133   if (G_UNLIKELY (value == NULL))
1134     {
1135       g_critical ("Failed to retrieve int64 from row %u column %u in %s@%p",
1136                   dee_model_get_position (self, iter), column,
1137                   G_OBJECT_TYPE_NAME (self), self);
1138       return G_GINT64_CONSTANT (0);
1139     }
1140 
1141   i = g_variant_get_int64 (value);
1142   g_variant_unref (value);
1143 
1144   return i;
1145 }
1146 
1147 
1148 static guint64
dee_serializable_model_get_uint64(DeeModel * self,DeeModelIter * iter,guint column)1149 dee_serializable_model_get_uint64 (DeeModel      *self,
1150                                    DeeModelIter  *iter,
1151                                    guint          column)
1152 {
1153   GVariant *value;
1154   guint64   u;
1155 
1156   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self),
1157                         G_GUINT64_CONSTANT (0));
1158 
1159   value = dee_model_get_value (self, iter, column);
1160 
1161   if (G_UNLIKELY (value == NULL))
1162     {
1163       g_critical ("Failed to retrieve uint64 from row %u column %u in %s@%p",
1164                   dee_model_get_position (self, iter), column,
1165                   G_OBJECT_TYPE_NAME (self), self);
1166       return G_GUINT64_CONSTANT (0);
1167     }
1168 
1169   u = g_variant_get_uint64 (value);
1170   g_variant_unref (value);
1171 
1172   return u;
1173 }
1174 
1175 static gdouble
dee_serializable_model_get_double(DeeModel * self,DeeModelIter * iter,guint column)1176 dee_serializable_model_get_double (DeeModel      *self,
1177                                    DeeModelIter  *iter,
1178                                    guint          column)
1179 {
1180   GVariant *value;
1181   gdouble   d;
1182 
1183   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), 0);
1184 
1185   value = dee_model_get_value (self, iter, column);
1186 
1187   if (G_UNLIKELY (value == NULL))
1188     {
1189       g_critical ("Failed to retrieve double from row %u column %u in %s@%p",
1190                   dee_model_get_position (self, iter), column,
1191                   G_OBJECT_TYPE_NAME (self), self);
1192       return 0;
1193     }
1194 
1195   d = g_variant_get_double (value);
1196   g_variant_unref (value);
1197 
1198   return d;
1199 }
1200 
1201 static const gchar*
dee_serializable_model_get_string(DeeModel * self,DeeModelIter * iter,guint column)1202 dee_serializable_model_get_string (DeeModel      *self,
1203                                    DeeModelIter  *iter,
1204                                    guint          column)
1205 {
1206   GVariant    *value;
1207   const gchar *s;
1208 
1209   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), NULL);
1210 
1211   value = dee_model_get_value (self, iter, column);
1212 
1213   if (G_UNLIKELY (value == NULL))
1214     {
1215       g_critical ("Failed to retrieve string from row %u column %u in %s@%p",
1216                   dee_model_get_position (self, iter), column,
1217                   G_OBJECT_TYPE_NAME (self), self);
1218       return NULL;
1219     }
1220 
1221   s = g_variant_get_string (value, NULL);
1222   g_variant_unref (value);
1223 
1224   return s;
1225 }
1226 
1227 static DeeModelIter*
dee_serializable_model_get_first_iter(DeeModel * self)1228 dee_serializable_model_get_first_iter (DeeModel     *self)
1229 {
1230   g_critical ("%s not implemented", G_STRFUNC);
1231   return NULL;
1232 }
1233 
1234 static DeeModelIter*
dee_serializable_model_get_last_iter(DeeModel * self)1235 dee_serializable_model_get_last_iter (DeeModel *self)
1236 {
1237   DeeModelIter *iter;
1238 
1239   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), NULL);
1240 
1241   iter = dee_model_get_first_iter (self);
1242   while (!dee_model_is_last (self, iter))
1243     iter = dee_model_next (self, iter);
1244 
1245   return iter;
1246 }
1247 
1248 static DeeModelIter*
dee_serializable_model_get_iter_at_row(DeeModel * self,guint row)1249 dee_serializable_model_get_iter_at_row (DeeModel *self,
1250                                      guint     row)
1251 {
1252   DeeModelIter *iter;
1253   guint         pos;
1254 
1255   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), NULL);
1256 
1257   pos = 0;
1258   iter = dee_model_get_first_iter (self);
1259   while (!dee_model_is_last (self, iter) && pos < row)
1260     {
1261       iter = dee_model_next (self, iter);
1262       pos++;
1263     }
1264 
1265   if (dee_model_is_last (self, iter))
1266     {
1267       g_critical ("Index %u is out of bounds in model of size %u",
1268                   row, pos);
1269     }
1270 
1271   return iter;
1272 }
1273 
1274 static DeeModelIter*
dee_serializable_model_next(DeeModel * self,DeeModelIter * iter)1275 dee_serializable_model_next (DeeModel     *self,
1276                           DeeModelIter *iter)
1277 {
1278   g_critical ("%s not implemented", G_STRFUNC);
1279   return NULL;
1280 }
1281 
1282 static DeeModelIter*
dee_serializable_model_prev(DeeModel * self,DeeModelIter * iter)1283 dee_serializable_model_prev (DeeModel     *self,
1284                           DeeModelIter *iter)
1285 {
1286   g_critical ("%s not implemented", G_STRFUNC);
1287   return NULL;
1288 }
1289 
1290 static gboolean
dee_serializable_model_is_first(DeeModel * self,DeeModelIter * iter)1291 dee_serializable_model_is_first (DeeModel     *self,
1292                               DeeModelIter *iter)
1293 {
1294   DeeModelIter *first;
1295 
1296   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), FALSE);
1297 
1298   first = dee_model_get_first_iter (self);
1299   return first == iter;
1300 }
1301 
1302 static gboolean
dee_serializable_model_is_last(DeeModel * self,DeeModelIter * iter)1303 dee_serializable_model_is_last (DeeModel     *self,
1304                              DeeModelIter *iter)
1305 {
1306   DeeModelIter *last;
1307 
1308   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), FALSE);
1309 
1310   last = dee_model_get_last_iter (self);
1311   return last == iter;
1312 }
1313 
1314 static guint
dee_serializable_model_get_position(DeeModel * self,DeeModelIter * iter)1315 dee_serializable_model_get_position (DeeModel     *self,
1316                                   DeeModelIter *iter)
1317 {
1318   DeeModelIter *_iter;
1319   guint          pos;
1320 
1321   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), 0);
1322 
1323   pos = 0;
1324   _iter = dee_model_get_first_iter (self);
1325   while (!dee_model_is_last (self, iter) && iter != _iter)
1326     {
1327       _iter = dee_model_next (self, _iter);
1328       pos++;
1329     }
1330 
1331   if (iter == _iter)
1332     return pos;
1333   else
1334     {
1335       g_critical ("Can not find position of unknown iter %p", iter);
1336       return -1;
1337     }
1338 }
1339 
1340 static void
dee_serializable_model_begin_changeset(DeeModel * self)1341 dee_serializable_model_begin_changeset (DeeModel *self)
1342 {
1343   DeeSerializableModelPrivate  *priv;
1344 
1345   priv = DEE_SERIALIZABLE_MODEL (self)->priv;
1346 
1347   if (!priv->inside_changeset)
1348     {
1349       priv->inside_changeset = TRUE;
1350       g_signal_emit (self, sigid_changeset_started, 0);
1351     }
1352   else
1353     {
1354       g_warning ("Ignored call to dee_model_begin_changeset, finish "
1355                  "the current changeset using dee_model_end_changeset first");
1356     }
1357 }
1358 
1359 static void
dee_serializable_model_end_changeset(DeeModel * self)1360 dee_serializable_model_end_changeset (DeeModel *self)
1361 {
1362   DeeSerializableModelPrivate  *priv;
1363 
1364   priv = DEE_SERIALIZABLE_MODEL (self)->priv;
1365 
1366   if (priv->inside_changeset)
1367     {
1368       priv->inside_changeset = FALSE;
1369       g_signal_emit (self, sigid_changeset_finished, 0);
1370     }
1371   else
1372     {
1373       g_warning ("Ignored call to dee_model_end_changeset, "
1374                  "dee_model_begin_changeset has to be called first");
1375     }
1376 }
1377 
1378 static DeeModelTag*
dee_serializable_model_register_tag(DeeModel * self,GDestroyNotify tag_destroy)1379 dee_serializable_model_register_tag    (DeeModel       *self,
1380                                         GDestroyNotify  tag_destroy)
1381 {
1382   g_critical ("%s not implemented", G_STRFUNC);
1383   return NULL;
1384 }
1385 
1386 static gpointer
dee_serializable_model_get_tag(DeeModel * self,DeeModelIter * iter,DeeModelTag * tag)1387 dee_serializable_model_get_tag (DeeModel       *self,
1388                             DeeModelIter   *iter,
1389                             DeeModelTag    *tag)
1390 {
1391   g_critical ("%s not implemented", G_STRFUNC);
1392   return NULL;
1393 }
1394 
1395 static void
dee_serializable_model_set_tag(DeeModel * self,DeeModelIter * iter,DeeModelTag * tag,gpointer value)1396 dee_serializable_model_set_tag (DeeModel       *self,
1397                             DeeModelIter   *iter,
1398                             DeeModelTag    *tag,
1399                             gpointer        value)
1400 {
1401   g_critical ("%s not implemented", G_STRFUNC);
1402 }
1403 
1404 /* Build a '(sasaavauay(tt))' suitable for sending in a Clone response */
1405 static GVariant*
dee_serializable_model_serialize(DeeSerializable * self)1406 dee_serializable_model_serialize (DeeSerializable *self)
1407 {
1408   DeeModel               *_self;
1409   GVariantBuilder         aav, clone, fields, vardict;
1410   GVariant               *val, *tt, *schema, *col_names;
1411   DeeModelIter           *iter;
1412   guint                   i, j, n_rows, n_columns;
1413   guint64                 last_seqnum;
1414   const gchar* const     *column_schemas;
1415   const gchar           **column_names;
1416 
1417   g_return_val_if_fail (DEE_IS_SERIALIZABLE_MODEL (self), FALSE);
1418 
1419   trace_object (self, "Building clone");
1420 
1421   _self = DEE_MODEL (self);
1422   n_columns = dee_model_get_n_columns (_self);
1423 
1424   g_variant_builder_init (&aav, G_VARIANT_TYPE ("aav"));
1425 
1426   /* Clone the rows */
1427   i = 0;
1428   iter = dee_model_get_first_iter (_self);
1429   while (!dee_model_is_last (_self, iter))
1430     {
1431       g_variant_builder_open (&aav, G_VARIANT_TYPE ("av"));
1432       for (j = 0; j < n_columns; j++)
1433         {
1434           val = dee_model_get_value (_self, iter, j);
1435           g_variant_builder_add_value (&aav, g_variant_new_variant (val));
1436           g_variant_unref (val);
1437         }
1438       g_variant_builder_close (&aav);
1439 
1440       iter = dee_model_next (_self, iter);
1441       i++;
1442     }
1443 
1444   n_rows = i;
1445 
1446   /* Collect the schema */
1447   column_schemas = dee_model_get_schema(_self, NULL);
1448   schema = g_variant_new_strv (column_schemas, -1);
1449 
1450   /* Collect the column names */
1451   column_names = dee_model_get_column_names (_self, NULL);
1452   col_names = g_variant_new_strv (column_names,
1453                                   column_names != NULL ? n_columns : 0);
1454 
1455   g_variant_builder_init (&fields, G_VARIANT_TYPE ("a(uss)"));
1456   for (i = 0; i < n_columns; i++)
1457     {
1458       GHashTable *field_schemas;
1459       GHashTableIter ht_iter;
1460       gpointer       key, value;
1461 
1462       if (!g_variant_type_is_subtype_of (G_VARIANT_TYPE (column_schemas[i]),
1463                                          G_VARIANT_TYPE_VARDICT))
1464         continue;
1465 
1466       field_schemas = dee_model_get_vardict_schema (_self, i);
1467       if (field_schemas == NULL) continue;
1468       g_hash_table_iter_init (&ht_iter, field_schemas);
1469       while (g_hash_table_iter_next (&ht_iter, &key, &value))
1470         {
1471           g_variant_builder_add (&fields, "(uss)", i, key, value);
1472         }
1473 
1474       g_hash_table_unref (field_schemas);
1475     }
1476 
1477   /* Collect the seqnum */
1478   last_seqnum = dee_serializable_model_get_seqnum (_self);
1479   tt = g_variant_new ("(tt)", last_seqnum - n_rows, last_seqnum);
1480 
1481   /* Put all extra properties in a vardict */
1482   g_variant_builder_init (&vardict, G_VARIANT_TYPE ("a{sv}"));
1483   g_variant_builder_add (&vardict, "{sv}", "column-names", col_names);
1484   g_variant_builder_add (&vardict, "{sv}", "fields", g_variant_builder_end (&fields));
1485 
1486   /* Build the final clone */
1487   g_variant_builder_init (&clone, MODEL_VARIANT_TYPE);
1488   g_variant_builder_add_value (&clone, schema);
1489   g_variant_builder_add_value (&clone, g_variant_builder_end (&aav));
1490   g_variant_builder_add_value (&clone, tt);
1491   g_variant_builder_add_value (&clone, g_variant_builder_end (&vardict));
1492 
1493   trace_object (self, "Serialized with %i rows", dee_model_get_n_rows (_self));
1494 
1495   return g_variant_builder_end (&clone);
1496 }
1497 
1498 static GObject*
dee_serializable_model_parse_serialized(GVariant * data)1499 dee_serializable_model_parse_serialized (GVariant *data)
1500 {
1501   DeeModel      *model;
1502   GVariant      *seqnumsv, *col, *vardict;
1503   GVariantIter  *row_iter, *col_iter, *vardict_schema_iter;
1504   GVariant     **row;
1505   const gchar  **schemas;
1506   const gchar  **column_names;
1507   gsize          n_cols, i, j, tuple_items;
1508   guint64        seqnum_start, seqnum_end;
1509   static GType   default_model_type = G_TYPE_INVALID;
1510 
1511   if (default_model_type == G_TYPE_INVALID)
1512     {
1513       default_model_type = g_type_from_name ("DeeSequenceModel");
1514       if (default_model_type == 0)
1515         {
1516           g_critical ("Unable to look up default DeeModel type, DeeSequenceModel, for deserialization");
1517           return NULL;
1518         }
1519     }
1520 
1521   tuple_items = g_variant_n_children (data);
1522   /* We support schema used by both dee 1.0 and 1.2 */
1523   if (tuple_items == 3) /* "(asaav(tt))" */
1524     {
1525       g_variant_get (data, "(^a&saav@(tt))", &schemas, &row_iter, &seqnumsv);
1526       vardict = NULL;
1527     }
1528   else if (tuple_items == 4) /* "(asaav(tt)a{sv})" */
1529     {
1530       g_variant_get (data, "(^a&saav@(tt)@a{sv})", &schemas, &row_iter,
1531                      &seqnumsv, &vardict);
1532 
1533       if (!g_variant_lookup (vardict, "column-names", "^a&s", &column_names))
1534         column_names = NULL;
1535       if (!g_variant_lookup (vardict, "fields", "a(uss)", &vardict_schema_iter))
1536         vardict_schema_iter = NULL;
1537     }
1538   else
1539     {
1540       g_critical ("Unable to deserialize model: Unrecognized schema");
1541       return NULL;
1542     }
1543 
1544   n_cols = g_strv_length ((gchar**) schemas);
1545   g_variant_get (seqnumsv, "(tt)", &seqnum_start, &seqnum_end);
1546 
1547   model = DEE_MODEL (g_object_new (default_model_type, NULL));
1548   dee_model_set_schema_full (model, schemas, n_cols);
1549   dee_serializable_model_set_seqnum (model, seqnum_start);
1550 
1551   if (vardict)
1552     {
1553       if (column_names && g_strv_length ((gchar**) column_names) == n_cols)
1554         {
1555           dee_model_set_column_names_full (model, column_names, n_cols);
1556         }
1557 
1558       if (vardict_schema_iter != NULL)
1559         {
1560           GHashTable **vardict_schemas;
1561           gchar *field_name, *field_schema;
1562           guint column_index;
1563 
1564           vardict_schemas = g_alloca (n_cols * sizeof (GHashTable*));
1565           memset (vardict_schemas, 0, n_cols * sizeof (GHashTable*));
1566 
1567           while (g_variant_iter_next (vardict_schema_iter, "(uss)",
1568                                       &column_index, &field_name, &field_schema))
1569             {
1570               if (vardict_schemas[column_index] == NULL)
1571                 {
1572                   vardict_schemas[column_index] = g_hash_table_new_full (
1573                       g_str_hash, g_str_equal, g_free, g_free);
1574                 }
1575 
1576               // using g_variant_iter_next, so we own field_name & schema
1577               g_hash_table_insert (vardict_schemas[column_index],
1578                                    field_name, field_schema);
1579             }
1580 
1581           for (column_index = 0; column_index < n_cols; column_index++)
1582             {
1583               if (vardict_schemas[column_index] == NULL) continue;
1584               dee_model_register_vardict_schema (model, column_index,
1585                                                  vardict_schemas[column_index]);
1586               g_hash_table_unref (vardict_schemas[column_index]);
1587             }
1588 
1589           g_variant_iter_free (vardict_schema_iter);
1590         }
1591 
1592       g_free (column_names);
1593       g_variant_unref (vardict);
1594     }
1595 
1596   /* Note: The 'row' variable is stack allocated. No need to free it */
1597   row = g_alloca (n_cols * sizeof (GVariant *));
1598 
1599   i = 0;
1600   while (g_variant_iter_next (row_iter, "av", &col_iter))
1601     {
1602       if (g_variant_iter_n_children (col_iter) != n_cols)
1603         {
1604           g_warning ("Row %"G_GSIZE_FORMAT" of serialized DeeSerializableModel "
1605                      "data has illegal length %"G_GSIZE_FORMAT". Expected %"
1606                      G_GSIZE_FORMAT, i, g_variant_iter_n_children (col_iter),
1607                      n_cols);
1608           /* Just skip this row - parsers for DeeSerializable should
1609            * generally never return NULL */
1610           continue;
1611         }
1612 
1613       j = 0;
1614       while (g_variant_iter_next (col_iter, "v", &col))
1615         {
1616           row[j] = col; // transfering variant reference to row[j]
1617           j++;
1618         }
1619 
1620       dee_model_append_row (model, row);
1621 
1622       for (j = 0; j < n_cols; j++)
1623         {
1624           g_variant_unref (row[j]);
1625         }
1626 
1627       i++;
1628       g_variant_iter_free (col_iter);
1629     }
1630   g_variant_iter_free (row_iter);
1631   g_free (schemas);
1632   g_variant_unref (seqnumsv);
1633 
1634   return (GObject *) model;
1635 }
1636 
1637 static void
dee_serializable_model_model_iface_init(DeeModelIface * iface)1638 dee_serializable_model_model_iface_init (DeeModelIface *iface)
1639 {
1640   iface->set_schema_full       = dee_serializable_model_set_schema_full;
1641   iface->get_schema            = dee_serializable_model_get_schema;
1642   iface->get_column_schema     = dee_serializable_model_get_column_schema;
1643   iface->get_field_schema      = dee_serializable_model_get_field_schema;
1644   iface->get_column_index      = dee_serializable_model_get_column_index;
1645   iface->set_column_names_full = dee_serializable_model_set_column_names_full;
1646   iface->get_column_names      = dee_serializable_model_get_column_names;
1647   iface->get_n_columns         = dee_serializable_model_get_n_columns;
1648   iface->get_n_rows            = dee_serializable_model_get_n_rows;
1649   iface->append_row            = dee_serializable_model_append_row;
1650   iface->prepend_row           = dee_serializable_model_prepend_row;
1651   iface->insert_row            = dee_serializable_model_insert_row;
1652   iface->insert_row_before     = dee_serializable_model_insert_row_before;
1653   iface->insert_row_sorted     = dee_serializable_model_insert_row_sorted;
1654   iface->find_row_sorted       = dee_serializable_model_find_row_sorted;
1655   iface->remove                = dee_serializable_model_remove;
1656   iface->clear                 = dee_serializable_model_clear;
1657   iface->set_value             = dee_serializable_model_set_value;
1658   iface->set_row               = dee_serializable_model_set_row;
1659   iface->get_value             = dee_serializable_model_get_value;
1660   iface->get_value_by_name     = dee_serializable_model_get_value_by_name;
1661   iface->get_row               = dee_serializable_model_get_row;
1662   iface->get_first_iter        = dee_serializable_model_get_first_iter;
1663   iface->get_last_iter         = dee_serializable_model_get_last_iter;
1664   iface->get_iter_at_row       = dee_serializable_model_get_iter_at_row;
1665   iface->get_bool              = dee_serializable_model_get_bool;
1666   iface->get_uchar             = dee_serializable_model_get_uchar;
1667   iface->get_int32             = dee_serializable_model_get_int32;
1668   iface->get_uint32            = dee_serializable_model_get_uint32;
1669   iface->get_int64             = dee_serializable_model_get_int64;
1670   iface->get_uint64            = dee_serializable_model_get_uint64;
1671   iface->get_double            = dee_serializable_model_get_double;
1672   iface->get_string            = dee_serializable_model_get_string;
1673   iface->next                  = dee_serializable_model_next;
1674   iface->prev                  = dee_serializable_model_prev;
1675   iface->is_first              = dee_serializable_model_is_first;
1676   iface->is_last               = dee_serializable_model_is_last;
1677   iface->get_position          = dee_serializable_model_get_position;
1678   iface->register_tag          = dee_serializable_model_register_tag;
1679   iface->get_tag               = dee_serializable_model_get_tag;
1680   iface->set_tag               = dee_serializable_model_set_tag;
1681   iface->register_vardict_schema =
1682     dee_serializable_model_register_vardict_schema;
1683   iface->get_vardict_schema =
1684     dee_serializable_model_get_vardict_schema;
1685 
1686   iface->begin_changeset       = dee_serializable_model_begin_changeset;
1687   iface->end_changeset         = dee_serializable_model_end_changeset;
1688 }
1689 
1690 static void
dee_serializable_model_serializable_iface_init(DeeSerializableIface * iface)1691 dee_serializable_model_serializable_iface_init (DeeSerializableIface *iface)
1692 {
1693   iface->serialize      = dee_serializable_model_serialize;
1694 
1695   dee_serializable_register_parser (DEE_TYPE_SERIALIZABLE_MODEL,
1696                                     MODEL_VARIANT_TYPE_1_0,
1697                                     dee_serializable_model_parse_serialized);
1698   dee_serializable_register_parser (DEE_TYPE_SERIALIZABLE_MODEL,
1699                                     MODEL_VARIANT_TYPE,
1700                                     dee_serializable_model_parse_serialized);
1701 }
1702 
1703