Main Page | Modules | Data Structures | Directories | File List | Data Fields | Related Pages

dbus-gvalue-utils.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* dbus-gvalue-utils.c: Non-DBus-specific functions related to GType/GValue 
00003  *
00004  * Copyright (C) 2005 Red Hat, Inc.
00005  *
00006  * Licensed under the Academic Free License version 2.1
00007  * 
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  * 
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  */
00023 
00024 #include <config.h>
00025 #include "dbus/dbus-glib.h"
00026 #include "dbus-gvalue-utils.h"
00027 #include "dbus-gtest.h"
00028 #include <glib.h>
00029 #include <string.h>
00030 #include <gobject/gvaluecollector.h>
00031 
00032 
00033 static guint
00034 fixed_type_get_size (GType type)
00035 {
00036   switch (type)
00037     {
00038     case G_TYPE_CHAR:
00039     case G_TYPE_UCHAR:
00040       return sizeof (gchar);
00041     case G_TYPE_BOOLEAN:
00042       return sizeof (gboolean);
00043     case G_TYPE_LONG:
00044     case G_TYPE_ULONG:
00045       return sizeof (glong);
00046     case G_TYPE_INT:
00047     case G_TYPE_UINT:
00048       return sizeof (gint);
00049     case G_TYPE_INT64:
00050     case G_TYPE_UINT64:
00051       return sizeof (gint64);
00052     case G_TYPE_FLOAT:
00053       return sizeof (gfloat);
00054     case G_TYPE_DOUBLE:
00055       return sizeof (gdouble);
00056     default:
00057       return 0;
00058     }
00059 }
00060 
00061 gboolean
00062 _dbus_g_type_is_fixed (GType type)
00063 {
00064   return fixed_type_get_size (type) > 0;
00065 }
00066 
00067 guint
00068 _dbus_g_type_fixed_get_size (GType type)
00069 {
00070   g_assert (_dbus_g_type_is_fixed (type));
00071   return fixed_type_get_size (type);
00072 }
00073 
00074 gboolean
00075 _dbus_gvalue_store (GValue          *value,
00076                    gpointer        storage)
00077 {
00078   /* FIXME - can we use the GValue lcopy_value method
00079    * to do this in a cleaner way?
00080    */
00081   switch (g_type_fundamental (G_VALUE_TYPE (value)))
00082     {
00083     case G_TYPE_CHAR:
00084       *((gchar *) storage) = g_value_get_char (value);
00085       return TRUE;
00086     case G_TYPE_UCHAR:
00087       *((guchar *) storage) = g_value_get_uchar (value);
00088       return TRUE;
00089     case G_TYPE_BOOLEAN:
00090       *((gboolean *) storage) = g_value_get_boolean (value);
00091       return TRUE;
00092     case G_TYPE_LONG:
00093       *((glong *) storage) = g_value_get_long (value);
00094       return TRUE;
00095     case G_TYPE_ULONG:
00096       *((gulong *) storage) = g_value_get_ulong (value);
00097       return TRUE;
00098     case G_TYPE_INT:
00099       *((gint *) storage) = g_value_get_int (value);
00100       return TRUE;
00101     case G_TYPE_UINT:
00102       *((guint *) storage) = g_value_get_uint (value);
00103       return TRUE;
00104     case G_TYPE_INT64:
00105       *((gint64 *) storage) = g_value_get_int64 (value);
00106       return TRUE;
00107     case G_TYPE_UINT64:
00108       *((guint64 *) storage) = g_value_get_uint64 (value);
00109       return TRUE;
00110     case G_TYPE_DOUBLE:
00111       *((gdouble *) storage) = g_value_get_double (value);
00112       return TRUE;
00113     case G_TYPE_STRING:
00114       *((gchar **) storage) = (char*) g_value_get_string (value);
00115       return TRUE;
00116     case G_TYPE_POINTER:
00117       *((gpointer *) storage) = g_value_get_pointer (value);
00118       return TRUE;
00119     case G_TYPE_OBJECT:
00120       *((gpointer *) storage) = g_value_get_object (value);
00121       return TRUE;
00122     case G_TYPE_BOXED:
00123       *((gpointer *) storage) = g_value_get_boxed (value);
00124       return TRUE;
00125     default:
00126       return FALSE;
00127     }
00128 }
00129 
00130 gboolean
00131 _dbus_gvalue_set_from_pointer (GValue          *value,
00132                               gconstpointer    storage)
00133 {
00134   /* FIXME - is there a better way to do this? */
00135   switch (g_type_fundamental (G_VALUE_TYPE (value)))
00136     {
00137     case G_TYPE_CHAR:
00138       g_value_set_char (value, *((gchar *) storage));
00139       return TRUE;
00140     case G_TYPE_UCHAR:
00141       g_value_set_uchar (value, *((guchar *) storage));
00142       return TRUE;
00143     case G_TYPE_BOOLEAN:
00144       g_value_set_boolean (value, *((gboolean *) storage));
00145       return TRUE;
00146     case G_TYPE_LONG:
00147       g_value_set_long (value, *((glong *) storage));
00148       return TRUE;
00149     case G_TYPE_ULONG:
00150       g_value_set_ulong (value, *((gulong *) storage));
00151       return TRUE;
00152     case G_TYPE_INT:
00153       g_value_set_int (value, *((gint *) storage));
00154       return TRUE;
00155     case G_TYPE_UINT:
00156       g_value_set_uint (value, *((guint *) storage));
00157       return TRUE;
00158     case G_TYPE_INT64:
00159       g_value_set_int64 (value, *((gint64 *) storage));
00160       return TRUE;
00161     case G_TYPE_UINT64:
00162       g_value_set_uint64 (value, *((guint64 *) storage));
00163       return TRUE;
00164     case G_TYPE_DOUBLE:
00165       g_value_set_double (value, *((gdouble *) storage));
00166       return TRUE;
00167     case G_TYPE_STRING:
00168       g_value_set_string (value, *((gchar **) storage));
00169       return TRUE;
00170     case G_TYPE_POINTER:
00171       g_value_set_pointer (value, *((gpointer *) storage));
00172       return TRUE;
00173     case G_TYPE_OBJECT:
00174       g_value_set_object (value, *((gpointer *) storage));
00175       return TRUE;
00176     case G_TYPE_BOXED:
00177       g_value_set_boxed (value, *((gpointer *) storage));
00178       return TRUE;
00179     default:
00180       return FALSE;
00181     }
00182 }
00183 
00184 gboolean
00185 _dbus_gvalue_take (GValue          *value,
00186                   GTypeCValue     *cvalue)
00187 {
00188   GType g_type;
00189   GTypeValueTable *value_table;
00190   char *error_msg;
00191 
00192   g_type = G_VALUE_TYPE (value);
00193   value_table = g_type_value_table_peek (g_type);
00194 
00195   error_msg = value_table->collect_value (value, 1, cvalue, G_VALUE_NOCOPY_CONTENTS);
00196   if (error_msg)
00197     {
00198       g_warning ("%s: %s", G_STRLOC, error_msg);
00199       g_free (error_msg);
00200       return FALSE;
00201     }
00202   /* Clear the NOCOPY_CONTENTS flag; we want to take ownership
00203    * of the value.
00204    */
00205   value->data[1].v_uint &= ~(G_VALUE_NOCOPY_CONTENTS);
00206   return TRUE;
00207 }
00208 
00209 gboolean
00210 _dbus_gtype_can_signal_error (GType gtype)
00211 {
00212   switch (gtype)
00213     {
00214     case G_TYPE_BOOLEAN:
00215     case G_TYPE_INT:
00216     case G_TYPE_UINT:
00217     case G_TYPE_STRING:
00218     case G_TYPE_BOXED:
00219     case G_TYPE_OBJECT:
00220       return TRUE;
00221     default:
00222       return FALSE;
00223     }
00224 }
00225 
00226 gboolean
00227 _dbus_gvalue_signals_error (const GValue *value)
00228 {
00229   /* Hardcoded rules for return value semantics for certain
00230    * types.  Perhaps in the future we'd want an annotation
00231    * specifying which return values are errors, but in
00232    * reality people will probably just use boolean and
00233    * boxed, and there the semantics are pretty standard.
00234    */
00235   switch (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value)))
00236     {
00237     case G_TYPE_BOOLEAN:
00238       return (g_value_get_boolean (value) == FALSE);
00239       break;
00240     case G_TYPE_INT:
00241       return (g_value_get_int (value) < 0);
00242       break;
00243     case G_TYPE_UINT:
00244       return (g_value_get_uint (value) == 0);
00245       break;
00246     case G_TYPE_STRING:
00247       return (g_value_get_string (value) == NULL);
00248       break;
00249     case G_TYPE_BOXED:
00250       return (g_value_get_boxed (value) == NULL);
00251       break;
00252     case G_TYPE_OBJECT:
00253       return (g_value_get_boxed (value) == NULL);
00254       break;
00255     default:
00256       g_assert_not_reached ();
00257     }
00258 }
00259 
00260 
00261 static gboolean
00262 hash_func_from_gtype (GType gtype, GHashFunc *func)
00263 {
00264   switch (gtype)
00265     {
00266     case G_TYPE_CHAR:
00267     case G_TYPE_UCHAR:
00268     case G_TYPE_BOOLEAN:
00269     case G_TYPE_INT:
00270     case G_TYPE_UINT:
00271       *func = NULL;
00272       return TRUE;
00273     case G_TYPE_STRING:
00274       *func = g_str_hash;
00275       return TRUE;
00276     default:
00277       return FALSE;
00278     }
00279 }
00280 
00281 static void
00282 unset_and_free_g_value (gpointer val)
00283 {
00284   GValue *value = val;
00285 
00286   g_value_unset (value);
00287   g_free (value);
00288 }
00289 
00290 static gboolean
00291 hash_free_from_gtype (GType gtype, GDestroyNotify *func)
00292 {
00293   switch (gtype)
00294     {
00295     case G_TYPE_CHAR:
00296     case G_TYPE_UCHAR:
00297     case G_TYPE_BOOLEAN:
00298     case G_TYPE_INT:
00299     case G_TYPE_UINT:
00300       *func = NULL;
00301       return TRUE;
00302     case G_TYPE_STRING:
00303       *func = g_free;
00304       return TRUE;
00305     default:
00306       if (gtype == G_TYPE_VALUE)
00307         {
00308           *func = unset_and_free_g_value;
00309           return TRUE;
00310         }
00311       return FALSE;
00312     }
00313 }
00314 
00315 gboolean
00316 _dbus_gtype_is_valid_hash_key (GType type)
00317 {
00318   GHashFunc func;
00319   return hash_func_from_gtype (type, &func);
00320 }
00321 
00322 gboolean
00323 _dbus_gtype_is_valid_hash_value (GType type)
00324 {
00325   GDestroyNotify func;
00326   return hash_free_from_gtype (type, &func);
00327 }
00328 
00329 GHashFunc
00330 _dbus_g_hash_func_from_gtype (GType gtype)
00331 {
00332   GHashFunc func;
00333   gboolean ret;
00334   ret = hash_func_from_gtype (gtype, &func);
00335   g_assert (ret != FALSE);
00336   return func;
00337 }
00338 
00339 GEqualFunc
00340 _dbus_g_hash_equal_from_gtype (GType gtype)
00341 {
00342   g_assert (_dbus_gtype_is_valid_hash_key (gtype));
00343 
00344   switch (gtype)
00345     {
00346     case G_TYPE_CHAR:
00347     case G_TYPE_UCHAR:
00348     case G_TYPE_BOOLEAN:
00349     case G_TYPE_INT:
00350     case G_TYPE_UINT:
00351       return NULL;
00352     case G_TYPE_STRING:
00353       return g_str_equal;
00354     default:
00355       g_assert_not_reached ();
00356       return NULL;
00357     }
00358 }
00359 
00360 GDestroyNotify
00361 _dbus_g_hash_free_from_gtype (GType gtype)
00362 {
00363   GDestroyNotify func;
00364   gboolean ret;
00365   ret = hash_free_from_gtype (gtype, &func);
00366   g_assert (ret != FALSE);
00367   return func;
00368 }
00369 
00370 static void
00371 gvalue_from_hash_value (GValue *value, gpointer instance)
00372 {
00373   switch (g_type_fundamental (G_VALUE_TYPE (value)))
00374     {
00375     case G_TYPE_CHAR:
00376       g_value_set_char (value, (gchar) GPOINTER_TO_INT (instance));
00377       break;
00378     case G_TYPE_UCHAR:
00379       g_value_set_uchar (value, (guchar) GPOINTER_TO_UINT (instance));
00380       break;
00381     case G_TYPE_BOOLEAN:
00382       g_value_set_boolean (value, (gboolean) GPOINTER_TO_UINT (instance));
00383       break;
00384     case G_TYPE_INT:
00385       g_value_set_int (value, GPOINTER_TO_INT (instance));
00386       break;
00387     case G_TYPE_UINT:
00388       g_value_set_uint (value, GPOINTER_TO_UINT (instance));
00389       break;
00390     case G_TYPE_STRING:
00391       g_value_set_static_string (value, instance);
00392       break;
00393     case G_TYPE_POINTER:
00394       g_value_set_pointer (value, instance);
00395       break;
00396     case G_TYPE_BOXED:
00397       g_value_set_static_boxed (value, instance);
00398       break;
00399     case G_TYPE_OBJECT:
00400       g_value_set_object (value, instance);
00401       g_object_unref (g_value_get_object (value));
00402       break;
00403     default:
00404       g_assert_not_reached ();
00405       break;
00406     }
00407 }
00408 
00409 static gpointer
00410 hash_value_from_gvalue (GValue *value)
00411 {
00412   switch (g_type_fundamental (G_VALUE_TYPE (value)))
00413     {
00414     case G_TYPE_CHAR:
00415       return GINT_TO_POINTER ((int) g_value_get_char (value));
00416       break;
00417     case G_TYPE_UCHAR:
00418       return GUINT_TO_POINTER ((guint) g_value_get_uchar (value));
00419       break;
00420     case G_TYPE_BOOLEAN:
00421       return GUINT_TO_POINTER ((guint) g_value_get_boolean (value));
00422       break;
00423     case G_TYPE_INT:
00424       return GINT_TO_POINTER (g_value_get_int (value));
00425       break;
00426     case G_TYPE_UINT:
00427       return GUINT_TO_POINTER (g_value_get_uint (value));
00428       break;
00429     case G_TYPE_STRING:
00430       return (gpointer) g_value_get_string (value);
00431       break;
00432     case G_TYPE_POINTER:
00433       return g_value_get_pointer (value);
00434       break;
00435     case G_TYPE_BOXED:
00436       return g_value_get_boxed (value);
00437       break;
00438     case G_TYPE_OBJECT:
00439       return g_value_get_object (value);
00440       break;
00441     default:
00442       g_assert_not_reached ();
00443       return NULL;
00444     }
00445 }
00446 
00447 struct DBusGHashTableValueForeachData
00448 {
00449   DBusGTypeSpecializedMapIterator func;
00450   GType key_type;
00451   GType value_type;
00452   gpointer data;
00453 };
00454 
00455 static void
00456 hashtable_foreach_with_values (gpointer key, gpointer value, gpointer user_data)
00457 {
00458   GValue key_val = {0, };
00459   GValue value_val = {0, };
00460   struct DBusGHashTableValueForeachData *data = user_data;
00461   
00462   g_value_init (&key_val, data->key_type);
00463   g_value_init (&value_val, data->value_type);
00464   gvalue_from_hash_value (&key_val, key);
00465   gvalue_from_hash_value (&value_val, value);
00466 
00467   data->func (&key_val, &value_val, data->data);
00468 }
00469 
00470 
00471 static void
00472 hashtable_iterator (GType                           hash_type,
00473                     gpointer                        instance,
00474                     DBusGTypeSpecializedMapIterator iterator,
00475                     gpointer                        user_data)
00476 {
00477   struct DBusGHashTableValueForeachData data;
00478   GType key_gtype;
00479   GType value_gtype;
00480 
00481   key_gtype = dbus_g_type_get_map_key_specialization (hash_type);
00482   value_gtype = dbus_g_type_get_map_value_specialization (hash_type);
00483 
00484   data.func = iterator;
00485   data.key_type = key_gtype;
00486   data.value_type = value_gtype;
00487   data.data = user_data;
00488 
00489   g_hash_table_foreach (instance, hashtable_foreach_with_values, &data);
00490 }
00491 
00492 void
00493 _dbus_g_hash_table_insert_steal_values (GHashTable *table,
00494                                        GValue     *key_val,
00495                                        GValue     *value_val)
00496 {
00497   gpointer key, val;
00498   
00499   key = hash_value_from_gvalue (key_val);
00500   val = hash_value_from_gvalue (value_val);
00501 
00502   g_hash_table_insert (table, key, val);
00503 }
00504 
00505 static void
00506 hashtable_append (DBusGTypeSpecializedAppendContext *ctx,
00507                   GValue                            *key,
00508                   GValue                            *val)
00509 {
00510   GHashTable *table;
00511 
00512   table = g_value_get_boxed (ctx->val);
00513   _dbus_g_hash_table_insert_steal_values (table, key, val);
00514 }
00515 
00516 static gpointer
00517 hashtable_constructor (GType type)
00518 {
00519   GHashTable *ret;
00520   GType key_gtype;
00521   GType value_gtype;
00522 
00523   key_gtype = dbus_g_type_get_map_key_specialization (type);
00524   value_gtype = dbus_g_type_get_map_value_specialization (type);
00525 
00526   ret = g_hash_table_new_full (_dbus_g_hash_func_from_gtype (key_gtype),
00527                                _dbus_g_hash_equal_from_gtype (key_gtype),
00528                                _dbus_g_hash_free_from_gtype (key_gtype),
00529                                _dbus_g_hash_free_from_gtype (value_gtype));
00530   return ret;
00531 }
00532 
00533 static void
00534 hashtable_insert_values (GHashTable       *table,
00535                          const GValue     *key_val,
00536                          const GValue     *value_val)
00537 {
00538   GValue key_copy = {0, };
00539   GValue value_copy = {0, };
00540 
00541   g_value_init (&key_copy, G_VALUE_TYPE (key_val));
00542   g_value_copy (key_val, &key_copy);
00543   g_value_init (&value_copy, G_VALUE_TYPE (value_val));
00544   g_value_copy (value_val, &value_copy);
00545   
00546   _dbus_g_hash_table_insert_steal_values (table, &key_copy, &value_copy);
00547 }
00548 
00549 static void
00550 hashtable_foreach_copy (const GValue *key, const GValue *val, gpointer data)
00551 {
00552   hashtable_insert_values ((GHashTable *) data, key, val);
00553 }
00554 
00555 static gpointer
00556 hashtable_copy (GType type, gpointer src)
00557 {
00558   GHashTable *ghash;
00559   GHashTable *ret;
00560   GValue hashval = {0,};
00561 
00562   ghash = src;
00563 
00564   ret = hashtable_constructor (type);
00565 
00566   g_value_init (&hashval, type);
00567   g_value_set_static_boxed (&hashval, ghash); 
00568   dbus_g_type_map_value_iterate (&hashval, hashtable_foreach_copy, ret);
00569   return ret;
00570 }
00571 
00572 static void
00573 hashtable_free (GType type, gpointer val)
00574 {
00575   g_hash_table_destroy (val);
00576 }
00577 
00578 static gpointer
00579 array_constructor (GType type)
00580 {
00581   GArray *array;
00582   guint elt_size;
00583   GType elt_type;
00584   gboolean zero_terminated;
00585   gboolean clear;
00586 
00587   elt_type = dbus_g_type_get_collection_specialization (type);
00588   g_assert (elt_type != G_TYPE_INVALID);
00589 
00590   elt_size = _dbus_g_type_fixed_get_size (elt_type);
00591 
00592   /* These are "safe" defaults */ 
00593   zero_terminated = TRUE; /* ((struct _DBusGRealArray*) garray)->zero_terminated; */
00594   clear = TRUE; /* ((struct _DBusGRealArray*) garray)->clear; */
00595 
00596   array = g_array_new (zero_terminated, clear, elt_size);
00597   return array;
00598 }
00599 
00600 static gpointer
00601 array_copy (GType type, gpointer src)
00602 {
00603   GArray *garray;
00604   GArray *new;
00605 
00606   garray = src;
00607 
00608   new = array_constructor (type);
00609   g_array_append_vals (new, garray->data, garray->len);
00610 
00611   return new;
00612 }
00613 
00614 static void
00615 array_free (GType type, gpointer val)
00616 {
00617   GArray *array;
00618   array = val;
00619   g_array_free (array, TRUE);
00620 }
00621 
00622 static gboolean
00623 array_fixed_accessor (GType type, gpointer instance, gpointer *values, guint *len)
00624 {
00625   GType elt_type;
00626   GArray *array = instance;
00627 
00628   elt_type = dbus_g_type_get_collection_specialization (type);
00629   if (!_dbus_g_type_is_fixed (elt_type))
00630     return FALSE;
00631 
00632   *values = array->data;
00633   *len = array->len;
00634   return TRUE;
00635 }
00636 
00637 static gpointer
00638 ptrarray_constructor (GType type)
00639 {
00640   /* Later we should determine a destructor, need g_ptr_array_destroy */
00641   return g_ptr_array_new ();
00642 }
00643 
00644 static void
00645 gvalue_from_ptrarray_value (GValue *value, gpointer instance)
00646 {
00647   switch (g_type_fundamental (G_VALUE_TYPE (value)))
00648     {
00649     case G_TYPE_STRING:
00650       g_value_set_string (value, instance);
00651       break;
00652     case G_TYPE_POINTER:
00653       g_value_set_pointer (value, instance);
00654       break;
00655     case G_TYPE_BOXED:
00656       g_value_set_static_boxed (value, instance);
00657       break;
00658     case G_TYPE_OBJECT:
00659       g_value_set_object (value, instance);
00660       g_object_unref (g_value_get_object (value));
00661       break;
00662     default:
00663       g_assert_not_reached ();
00664       break;
00665     }
00666 }
00667 
00668 static gpointer
00669 ptrarray_value_from_gvalue (const GValue *value)
00670 {
00671   switch (g_type_fundamental (G_VALUE_TYPE (value)))
00672     {
00673     case G_TYPE_STRING:
00674       return (gpointer) g_value_get_string (value);
00675       break;
00676     case G_TYPE_POINTER:
00677       return g_value_get_pointer (value);
00678       break;
00679     case G_TYPE_BOXED:
00680       return g_value_get_boxed (value);
00681       break;
00682     case G_TYPE_OBJECT:
00683       return g_value_get_object (value);
00684       break;
00685     default:
00686       g_assert_not_reached ();
00687       return NULL;
00688     }
00689 }
00690 
00691 static void
00692 ptrarray_iterator (GType                                   hash_type,
00693                    gpointer                                instance,
00694                    DBusGTypeSpecializedCollectionIterator  iterator,
00695                    gpointer                                user_data)
00696 {
00697   GPtrArray *ptrarray;
00698   GType elt_gtype;
00699   guint i;
00700 
00701   ptrarray = instance;
00702 
00703   elt_gtype = dbus_g_type_get_collection_specialization (hash_type);
00704 
00705   for (i = 0; i < ptrarray->len; i++)
00706     {
00707       GValue val = {0, };
00708       g_value_init (&val, elt_gtype);
00709       gvalue_from_ptrarray_value (&val, g_ptr_array_index (ptrarray, i));
00710       iterator (&val, user_data);
00711     }
00712 }
00713 
00714 static void
00715 ptrarray_copy_elt (const GValue *val, gpointer user_data)
00716 {
00717   GPtrArray *dest = user_data;
00718   GValue val_copy = {0, }; 
00719   
00720   g_value_init (&val_copy, G_VALUE_TYPE (val));
00721   g_value_copy (val, &val_copy);
00722 
00723   g_ptr_array_add (dest, ptrarray_value_from_gvalue (&val_copy));
00724 }
00725 
00726 static gpointer
00727 ptrarray_copy (GType type, gpointer src)
00728 {
00729   GPtrArray *new;
00730   GValue array_val = {0, };
00731 
00732   g_value_init (&array_val, type);
00733   g_value_set_static_boxed (&array_val, src);
00734 
00735   new = ptrarray_constructor (type);
00736   dbus_g_type_collection_value_iterate (&array_val, ptrarray_copy_elt, new);
00737 
00738   return new;
00739 }
00740 
00741 static void
00742 ptrarray_append (DBusGTypeSpecializedAppendContext *ctx, GValue *value)
00743 {
00744   GPtrArray *array;
00745 
00746   array = g_value_get_boxed (ctx->val);
00747 
00748   g_ptr_array_add (array, ptrarray_value_from_gvalue (value));
00749 }
00750 
00751 static void
00752 ptrarray_free (GType type, gpointer val)
00753 {
00754   GPtrArray *array;
00755   array = val;
00756   g_ptr_array_free (array, TRUE);
00757 }
00758 
00759 static gpointer
00760 slist_constructor (GType type)
00761 {
00762   return NULL;
00763 }
00764 
00765 static void
00766 slist_iterator (GType                                   list_type,
00767                 gpointer                                instance,
00768                 DBusGTypeSpecializedCollectionIterator  iterator,
00769                 gpointer                                user_data)
00770 {
00771   GSList *slist;
00772   GType elt_gtype;
00773 
00774   slist = instance;
00775 
00776   elt_gtype = dbus_g_type_get_collection_specialization (list_type);
00777 
00778   while (slist != NULL)
00779     {
00780       GValue val = {0, };
00781       g_value_init (&val, elt_gtype);
00782       gvalue_from_ptrarray_value (&val, slist->data);
00783       iterator (&val, user_data);
00784     }
00785 }
00786 
00787 static void
00788 slist_copy_elt (const GValue *val, gpointer user_data)
00789 {
00790   GSList *dest = user_data;
00791   GValue val_copy = {0, }; 
00792   
00793   g_value_init (&val_copy, G_VALUE_TYPE (val));
00794   g_value_copy (val, &val_copy);
00795 
00796   g_slist_append (dest, ptrarray_value_from_gvalue (&val_copy));
00797 }
00798 
00799 static gpointer
00800 slist_copy (GType type, gpointer src)
00801 {
00802   GSList *new;
00803   GValue slist_val = {0, };
00804 
00805   g_value_init (&slist_val, type);
00806   g_value_set_static_boxed (&slist_val, src);
00807 
00808   new = slist_constructor (type);
00809   dbus_g_type_collection_value_iterate (&slist_val, slist_copy_elt, new);
00810 
00811   return new;
00812 }
00813 
00814 static void
00815 slist_append (DBusGTypeSpecializedAppendContext *ctx, GValue *value)
00816 {
00817   GSList *list;
00818 
00819   list = g_value_get_boxed (ctx->val);
00820   list = g_slist_prepend (list, ptrarray_value_from_gvalue (value));
00821   g_value_set_static_boxed (ctx->val, list);
00822 }
00823 
00824 static void
00825 slist_end_append (DBusGTypeSpecializedAppendContext *ctx)
00826 {
00827   GSList *list;
00828 
00829   list = g_value_get_boxed (ctx->val);
00830   list = g_slist_reverse (list);
00831 
00832   g_value_set_static_boxed (ctx->val, list);
00833 }
00834 
00835 static void
00836 slist_free (GType type, gpointer val)
00837 {
00838   GSList *list;
00839   list = val;
00840   g_slist_free (list);
00841 }
00842 
00843 void
00844 _dbus_g_type_specialized_builtins_init (void)
00845 {
00846   static const DBusGTypeSpecializedCollectionVtable array_vtable = {
00847     {
00848       array_constructor,
00849       array_free,
00850       array_copy,
00851     },
00852     array_fixed_accessor,
00853     NULL,
00854     NULL,
00855     NULL
00856   };
00857 
00858 
00859   static const DBusGTypeSpecializedCollectionVtable ptrarray_vtable = {
00860     {
00861       ptrarray_constructor,
00862       ptrarray_free,
00863       ptrarray_copy,
00864     },
00865     NULL,
00866     ptrarray_iterator,
00867     ptrarray_append,
00868     NULL,
00869   };
00870 
00871 
00872   static const DBusGTypeSpecializedCollectionVtable slist_vtable = {
00873     {
00874       slist_constructor,
00875       slist_free,
00876       slist_copy,
00877     },
00878     NULL,
00879     slist_iterator,
00880     slist_append,
00881     slist_end_append,
00882   };
00883 
00884   static const DBusGTypeSpecializedMapVtable hashtable_vtable = {
00885     {
00886       hashtable_constructor,
00887       hashtable_free,
00888       hashtable_copy,
00889       NULL,
00890       NULL,
00891       NULL
00892     },
00893     hashtable_iterator,
00894     hashtable_append
00895   };
00896 
00897   dbus_g_type_register_collection ("GSList", &slist_vtable, 0);
00898   dbus_g_type_register_collection ("GArray", &array_vtable, 0);
00899   dbus_g_type_register_collection ("GPtrArray", &ptrarray_vtable, 0);
00900   dbus_g_type_register_map ("GHashTable", &hashtable_vtable, 0);
00901 }
00902 
00903 #ifdef DBUS_BUILD_TESTS
00904 
00905 typedef struct
00906 {
00907   gboolean seen_foo;
00908   gboolean seen_baz;
00909 } TestSpecializedHashData;
00910 
00911 static void
00912 test_specialized_hash (const GValue *key, const GValue *val, gpointer user_data)
00913 {
00914   TestSpecializedHashData *data = user_data;
00915 
00916   g_assert (G_VALUE_HOLDS_STRING (key));
00917   g_assert (G_VALUE_HOLDS_STRING (val));
00918 
00919   if (!strcmp (g_value_get_string (key), "foo"))
00920     {
00921       data->seen_foo = TRUE;
00922       g_assert (!strcmp (g_value_get_string (val), "bar"));
00923     }
00924   else if (!strcmp (g_value_get_string (key), "baz"))
00925     {
00926       data->seen_baz = TRUE;
00927       g_assert (!strcmp (g_value_get_string (val), "moo"));
00928     }
00929   else
00930     {
00931       g_assert_not_reached ();
00932     }
00933 }
00934 
00935 static void
00936 test_specialized_hash_2 (const GValue *key, const GValue *val, gpointer user_data)
00937 {
00938   TestSpecializedHashData *data = user_data;
00939   const GValue *realval;
00940 
00941   g_assert (G_VALUE_HOLDS_STRING (key));
00942   g_assert (G_VALUE_TYPE (val) == G_TYPE_VALUE);
00943 
00944   realval = g_value_get_boxed (val);
00945 
00946   if (!strcmp (g_value_get_string (key), "foo"))
00947     {
00948       data->seen_foo = TRUE;
00949       g_assert (G_VALUE_HOLDS_UINT (realval));
00950       g_assert (g_value_get_uint (realval) == 20);
00951     }
00952   else if (!strcmp (g_value_get_string (key), "baz"))
00953     {
00954       data->seen_baz = TRUE;
00955       g_assert (G_VALUE_HOLDS_STRING (realval));
00956       g_assert (!strcmp ("bar", g_value_get_string (realval)));
00957     }
00958   else
00959     {
00960       g_assert_not_reached ();
00961     }
00962 }
00963 
00964 gboolean
00965 _dbus_gvalue_utils_test (const char *datadir)
00966 {
00967   GType type;
00968 
00969   dbus_g_type_specialized_init ();
00970  _dbus_g_type_specialized_builtins_init ();
00971 
00972   type = dbus_g_type_get_collection ("GArray", G_TYPE_UINT);
00973   g_assert (dbus_g_type_is_collection (type));
00974   g_assert (dbus_g_type_get_collection_specialization (type) == G_TYPE_UINT);
00975   {
00976     GArray *instance;
00977 
00978     instance = dbus_g_type_specialized_construct (type);
00979 
00980     g_assert (instance->len == 0);
00981 
00982     g_array_free (instance, TRUE);
00983   }
00984 
00985   type = dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING);
00986   g_assert (dbus_g_type_is_map (type));
00987   g_assert (dbus_g_type_get_map_key_specialization (type) == G_TYPE_STRING);
00988   g_assert (dbus_g_type_get_map_value_specialization (type) == G_TYPE_STRING);
00989   {
00990     GHashTable *instance;
00991     GValue val = { 0, };
00992     TestSpecializedHashData hashdata;
00993 
00994     instance = dbus_g_type_specialized_construct (type);
00995 
00996     g_assert (g_hash_table_size (instance) == 0);
00997     g_hash_table_insert (instance, g_strdup ("foo"), g_strdup ("bar"));
00998     g_hash_table_insert (instance, g_strdup ("baz"), g_strdup ("moo"));
00999     g_assert (g_hash_table_size (instance) == 2);
01000 
01001     g_value_init (&val, type);
01002     g_value_set_boxed_take_ownership (&val, instance);
01003     hashdata.seen_foo = FALSE;
01004     hashdata.seen_baz = FALSE;
01005     dbus_g_type_map_value_iterate (&val,
01006                                    test_specialized_hash, 
01007                                    &hashdata);
01008     
01009     g_assert (hashdata.seen_foo);
01010     g_assert (hashdata.seen_baz);
01011 
01012     g_value_unset (&val);
01013   }
01014 
01015   type = dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE);
01016   g_assert (dbus_g_type_is_map (type));
01017   g_assert (dbus_g_type_get_map_key_specialization (type) == G_TYPE_STRING);
01018   g_assert (dbus_g_type_get_map_value_specialization (type) == G_TYPE_VALUE);
01019   {
01020     GHashTable *instance;
01021     GValue val = { 0, };
01022     TestSpecializedHashData hashdata;
01023     DBusGTypeSpecializedAppendContext ctx;
01024     GValue *eltval;
01025 
01026     instance = dbus_g_type_specialized_construct (type);
01027     g_value_init (&val, type);
01028     g_value_set_boxed_take_ownership (&val, instance);
01029 
01030     dbus_g_type_specialized_init_append (&val, &ctx);
01031 
01032     {
01033       GValue keyval = { 0, };
01034       GValue valval = { 0, };
01035       g_value_init (&keyval, G_TYPE_STRING);
01036       g_value_set_string (&keyval, "foo"); 
01037 
01038       g_value_init (&valval, G_TYPE_VALUE);
01039       eltval = g_new0 (GValue, 1);
01040       g_value_init (eltval, G_TYPE_UINT);
01041       g_value_set_uint (eltval, 20);
01042       g_value_set_boxed_take_ownership (&valval, eltval);
01043       dbus_g_type_specialized_map_append (&ctx, &keyval, &valval);
01044     }
01045 
01046     {
01047       GValue keyval = { 0, };
01048       GValue valval = { 0, };
01049       g_value_init (&keyval, G_TYPE_STRING);
01050       g_value_set_string (&keyval, "baz"); 
01051       g_value_init (&valval, G_TYPE_VALUE);
01052       eltval = g_new0 (GValue, 1);
01053       g_value_init (eltval, G_TYPE_STRING);
01054       g_value_set_string (eltval, "bar");
01055       g_value_set_boxed_take_ownership (&valval, eltval);
01056       dbus_g_type_specialized_map_append (&ctx, &keyval, &valval);
01057     }
01058 
01059     hashdata.seen_foo = FALSE;
01060     hashdata.seen_baz = FALSE;
01061     dbus_g_type_map_value_iterate (&val,
01062                                    test_specialized_hash_2, 
01063                                    &hashdata);
01064     
01065     g_assert (hashdata.seen_foo);
01066     g_assert (hashdata.seen_baz);
01067 
01068     g_value_unset (&val);
01069   }
01070 
01071   type = dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING);
01072   g_assert (dbus_g_type_is_collection (type));
01073   g_assert (dbus_g_type_get_collection_specialization (type) == G_TYPE_STRING);
01074   {
01075     GPtrArray *instance;
01076     DBusGTypeSpecializedAppendContext ctx;
01077     GValue val = {0, };
01078     GValue eltval = {0, };
01079 
01080     instance = dbus_g_type_specialized_construct (type);
01081 
01082     g_assert (instance->len == 0);
01083 
01084     g_value_init (&val, type);
01085     g_value_set_boxed_take_ownership (&val, instance);
01086 
01087     dbus_g_type_specialized_init_append (&val, &ctx);
01088 
01089     g_value_init (&eltval, G_TYPE_STRING);
01090     g_value_set_static_string (&eltval, "foo");
01091     dbus_g_type_specialized_collection_append (&ctx, &eltval);
01092 
01093     g_value_reset (&eltval);
01094     g_value_set_static_string (&eltval, "bar");
01095     dbus_g_type_specialized_collection_append (&ctx, &eltval);
01096 
01097     g_value_reset (&eltval);
01098     g_value_set_static_string (&eltval, "baz");
01099     dbus_g_type_specialized_collection_append (&ctx, &eltval);
01100 
01101     dbus_g_type_specialized_collection_end_append (&ctx);
01102 
01103     g_assert (instance->len == 3);
01104 
01105     g_assert (!strcmp ("foo", g_ptr_array_index (instance, 0)));
01106     g_assert (!strcmp ("bar", g_ptr_array_index (instance, 1)));
01107     g_assert (!strcmp ("baz", g_ptr_array_index (instance, 2)));
01108 
01109     g_value_unset (&val);
01110   }
01111 
01112   return TRUE;
01113 }
01114 
01115 
01116 
01117 #endif /* DBUS_BUILD_TESTS */

Generated on Wed Jan 3 04:49:04 2007 for D-BUS by  doxygen 1.4.4