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_OBJECT:
00117       *((gpointer *) storage) = g_value_get_object (value);
00118       return TRUE;
00119     case G_TYPE_BOXED:
00120       *((gpointer *) storage) = g_value_get_boxed (value);
00121       return TRUE;
00122     default:
00123       return FALSE;
00124     }
00125 }
00126 
00127 gboolean
00128 _dbus_gvalue_set_from_pointer (GValue          *value,
00129                               gconstpointer    storage)
00130 {
00131   /* FIXME - is there a better way to do this? */
00132   switch (g_type_fundamental (G_VALUE_TYPE (value)))
00133     {
00134     case G_TYPE_CHAR:
00135       g_value_set_char (value, *((gchar *) storage));
00136       return TRUE;
00137     case G_TYPE_UCHAR:
00138       g_value_set_uchar (value, *((guchar *) storage));
00139       return TRUE;
00140     case G_TYPE_BOOLEAN:
00141       g_value_set_boolean (value, *((gboolean *) storage));
00142       return TRUE;
00143     case G_TYPE_LONG:
00144       g_value_set_long (value, *((glong *) storage));
00145       return TRUE;
00146     case G_TYPE_ULONG:
00147       g_value_set_ulong (value, *((gulong *) storage));
00148       return TRUE;
00149     case G_TYPE_INT:
00150       g_value_set_int (value, *((gint *) storage));
00151       return TRUE;
00152     case G_TYPE_UINT:
00153       g_value_set_uint (value, *((guint *) storage));
00154       return TRUE;
00155     case G_TYPE_INT64:
00156       g_value_set_int64 (value, *((gint64 *) storage));
00157       return TRUE;
00158     case G_TYPE_UINT64:
00159       g_value_set_uint64 (value, *((guint64 *) storage));
00160       return TRUE;
00161     case G_TYPE_DOUBLE:
00162       g_value_set_double (value, *((gdouble *) storage));
00163       return TRUE;
00164     case G_TYPE_STRING:
00165       g_value_set_string (value, *((gchar **) storage));
00166       return TRUE;
00167     case G_TYPE_OBJECT:
00168       g_value_set_object (value, *((gpointer *) storage));
00169       return TRUE;
00170     case G_TYPE_BOXED:
00171       g_value_set_boxed (value, *((gpointer *) storage));
00172       return TRUE;
00173     default:
00174       return FALSE;
00175     }
00176 }
00177 
00178 gboolean
00179 _dbus_gvalue_take (GValue          *value,
00180                   GTypeCValue     *cvalue)
00181 {
00182   GType g_type;
00183   GTypeValueTable *value_table;
00184   char *error_msg;
00185 
00186   g_type = G_VALUE_TYPE (value);
00187   value_table = g_type_value_table_peek (g_type);
00188 
00189   error_msg = value_table->collect_value (value, 1, cvalue, G_VALUE_NOCOPY_CONTENTS);
00190   if (error_msg)
00191     {
00192       g_warning ("%s: %s", G_STRLOC, error_msg);
00193       g_free (error_msg);
00194       return FALSE;
00195     }
00196   /* Clear the NOCOPY_CONTENTS flag; we want to take ownership
00197    * of the value.
00198    */
00199   value->data[1].v_uint &= ~(G_VALUE_NOCOPY_CONTENTS);
00200   return TRUE;
00201 }
00202 
00203 gboolean
00204 _dbus_gtype_can_signal_error (GType gtype)
00205 {
00206   switch (gtype)
00207     {
00208     case G_TYPE_BOOLEAN:
00209     case G_TYPE_INT:
00210     case G_TYPE_UINT:
00211     case G_TYPE_STRING:
00212     case G_TYPE_BOXED:
00213     case G_TYPE_OBJECT:
00214       return TRUE;
00215     default:
00216       return FALSE;
00217     }
00218 }
00219 
00220 gboolean
00221 _dbus_gvalue_signals_error (const GValue *value)
00222 {
00223   /* Hardcoded rules for return value semantics for certain
00224    * types.  Perhaps in the future we'd want an annotation
00225    * specifying which return values are errors, but in
00226    * reality people will probably just use boolean and
00227    * boxed, and there the semantics are pretty standard.
00228    */
00229   switch (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value)))
00230     {
00231     case G_TYPE_BOOLEAN:
00232       return (g_value_get_boolean (value) == FALSE);
00233       break;
00234     case G_TYPE_INT:
00235       return (g_value_get_int (value) < 0);
00236       break;
00237     case G_TYPE_UINT:
00238       return (g_value_get_uint (value) == 0);
00239       break;
00240     case G_TYPE_STRING:
00241       return (g_value_get_string (value) == NULL);
00242       break;
00243     case G_TYPE_BOXED:
00244       return (g_value_get_boxed (value) == NULL);
00245       break;
00246     case G_TYPE_OBJECT:
00247       return (g_value_get_object (value) == NULL);
00248       break;
00249     default:
00250       g_assert_not_reached ();
00251       return FALSE;
00252     }
00253 }
00254 
00255 
00256 static gboolean
00257 hash_func_from_gtype (GType gtype, GHashFunc *func)
00258 {
00259   switch (gtype)
00260     {
00261     case G_TYPE_CHAR:
00262     case G_TYPE_UCHAR:
00263     case G_TYPE_BOOLEAN:
00264     case G_TYPE_INT:
00265     case G_TYPE_UINT:
00266       *func = NULL;
00267       return TRUE;
00268     case G_TYPE_STRING:
00269       *func = g_str_hash;
00270       return TRUE;
00271     default:
00272       if (gtype == DBUS_TYPE_G_OBJECT_PATH)
00273         {
00274           *func = g_str_hash;
00275           return TRUE;
00276         }
00277       else if (gtype == DBUS_TYPE_G_SIGNATURE)
00278         {
00279           *func = g_str_hash;
00280           return TRUE;
00281         }
00282       return FALSE;
00283     }
00284 }
00285 
00286 static void
00287 unset_and_free_g_value (gpointer val)
00288 {
00289   GValue *value = val;
00290 
00291   g_value_unset (value);
00292   g_free (value);
00293 }
00294 
00295 static gboolean
00296 gtype_can_simple_free (GType type);
00297 
00298 static gboolean
00299 hash_simple_free_from_gtype (GType gtype, GDestroyNotify *func)
00300 {
00301   switch (gtype)
00302     {
00303     case G_TYPE_CHAR:
00304     case G_TYPE_UCHAR:
00305     case G_TYPE_BOOLEAN:
00306     case G_TYPE_INT:
00307     case G_TYPE_UINT:
00308       *func = NULL;
00309       return TRUE;
00310     case G_TYPE_DOUBLE:
00311     case G_TYPE_STRING:
00312       *func = g_free;
00313       return TRUE;
00314     default:
00315       if (gtype == G_TYPE_VALUE)
00316         {
00317           *func = unset_and_free_g_value;
00318           return TRUE;
00319         }
00320       else if (gtype == G_TYPE_VALUE_ARRAY)
00321         {
00322           *func = (GDestroyNotify) g_value_array_free;
00323           return TRUE;
00324         }
00325       else if (gtype == G_TYPE_STRV)
00326         {
00327           *func = (GDestroyNotify) g_strfreev;
00328           return TRUE;
00329         }
00330       else if (gtype == DBUS_TYPE_G_OBJECT_PATH)
00331         {
00332           *func = g_free;
00333           return TRUE;
00334         }
00335       else if (gtype == DBUS_TYPE_G_SIGNATURE)
00336         {
00337           *func = g_free;
00338           return TRUE;
00339         }
00340       else if (dbus_g_type_is_collection (gtype))
00341         {
00342           const DBusGTypeSpecializedCollectionVtable* vtable;
00343           vtable = dbus_g_type_collection_peek_vtable (gtype);
00344           if (vtable->base_vtable.simple_free_func)
00345             {
00346               *func = vtable->base_vtable.simple_free_func;
00347               return TRUE;
00348             }
00349         }
00350       else if (dbus_g_type_is_map (gtype))
00351         {
00352           const DBusGTypeSpecializedMapVtable* vtable;
00353           GType key_gtype, value_gtype;
00354 
00355           key_gtype = dbus_g_type_get_map_key_specialization (gtype);
00356           value_gtype = dbus_g_type_get_map_value_specialization (gtype);
00357 
00358           /* if either the key or the value don't have "simple" (without a
00359            * GType) free functions, then the hashtable's contents must be freed
00360            * with hashtable_free, so the hashtable itself can't have a simple
00361            * free function. */
00362           if (!gtype_can_simple_free (key_gtype) ||
00363               !gtype_can_simple_free (value_gtype))
00364             return FALSE;
00365 
00366           vtable = dbus_g_type_map_peek_vtable (gtype);
00367           if (vtable->base_vtable.simple_free_func)
00368             {
00369               *func = vtable->base_vtable.simple_free_func;
00370               return TRUE;
00371             }
00372         }
00373       else if (dbus_g_type_is_struct (gtype))
00374         {
00375           const DBusGTypeSpecializedStructVtable *vtable;
00376           vtable = dbus_g_type_struct_peek_vtable (gtype);
00377           if (vtable->base_vtable.simple_free_func)
00378             {
00379               *func = vtable->base_vtable.simple_free_func;
00380               return TRUE;
00381             }
00382         }
00383       return FALSE;
00384     }
00385 }
00386 
00387 static gboolean
00388 gtype_can_simple_free (GType type)
00389 {
00390   GDestroyNotify func;
00391   return hash_simple_free_from_gtype (type, &func);
00392 }
00393 
00394 gboolean
00395 _dbus_gtype_is_valid_hash_key (GType type)
00396 {
00397   GHashFunc func;
00398   return hash_func_from_gtype (type, &func);
00399 }
00400 
00401 gboolean
00402 _dbus_gtype_is_valid_hash_value (GType gtype)
00403 {
00404   /* anything we can take into a GValue using gvalue_take_hash_value is fine */
00405   switch (g_type_fundamental (gtype))
00406     {
00407     case G_TYPE_CHAR:
00408     case G_TYPE_UCHAR:
00409     case G_TYPE_BOOLEAN:
00410     case G_TYPE_INT:
00411     case G_TYPE_UINT:
00412     case G_TYPE_DOUBLE:
00413     case G_TYPE_STRING:
00414     case G_TYPE_BOXED:
00415     case G_TYPE_OBJECT:
00416       return TRUE;
00417     }
00418 
00419   return FALSE;
00420 }
00421 
00422 GHashFunc
00423 _dbus_g_hash_func_from_gtype (GType gtype)
00424 {
00425   GHashFunc func;
00426   gboolean ret;
00427   ret = hash_func_from_gtype (gtype, &func);
00428   g_assert (ret != FALSE);
00429   return func;
00430 }
00431 
00432 GEqualFunc
00433 _dbus_g_hash_equal_from_gtype (GType gtype)
00434 {
00435   g_assert (_dbus_gtype_is_valid_hash_key (gtype));
00436 
00437   switch (gtype)
00438     {
00439     case G_TYPE_CHAR:
00440     case G_TYPE_UCHAR:
00441     case G_TYPE_BOOLEAN:
00442     case G_TYPE_INT:
00443     case G_TYPE_UINT:
00444       return NULL;
00445     case G_TYPE_STRING:
00446       return g_str_equal;
00447     default:
00448       if (gtype == DBUS_TYPE_G_OBJECT_PATH)
00449         return g_str_equal;
00450       else if (gtype == DBUS_TYPE_G_SIGNATURE)
00451         return g_str_equal;
00452       g_assert_not_reached ();
00453       return NULL;
00454     }
00455 }
00456 
00457 static void
00458 hash_fake_simple_free_func (gpointer val)
00459 {
00460   /* Havoc would be proud... :P */
00461   g_critical ("If you see this message then the author of this application or "
00462       "one of its libraries has tried to remove or replace the value %p in a "
00463       "hash table which was constructed by the D-Bus Glib bindings.\n\n"
00464 
00465       "However, it was not possible for the bindings to provide a destroy "
00466       "function to g_hash_table_new_full which is able to free this value, as "
00467       "its GType must be known in order to free it. This means the memory "
00468       "allocated to store the value has most likely just been leaked.\n\n"
00469 
00470       "To avoid this error, the GHashTable (or keys/values \"stolen\" from "
00471       "it) should be freed by using g_boxed_free as follows:\n"
00472       "  g_boxed_free (dbus_g_type_get_map (\"GHashTable\", key_gtype, "
00473       "value_gtype), hash_table);\n", val);
00474 }
00475 
00476 GDestroyNotify
00477 _dbus_g_hash_free_from_gtype (GType gtype)
00478 {
00479   GDestroyNotify func;
00480   gboolean ret;
00481 
00482   ret = hash_simple_free_from_gtype (gtype, &func);
00483 
00484   /* if the value doesn't have a simple free function, we cannot define a
00485    * meaningful free function here. instead, this hash table must be freed
00486    * using g_boxed_free so that the hash_free function gets invoked. if the
00487    * user does not do so, we provide a fake free function to provide a warning
00488    * in this case. */
00489   if (ret == FALSE)
00490     {
00491       g_assert (_dbus_gtype_is_valid_hash_value (gtype));
00492 
00493       func = hash_fake_simple_free_func;
00494     }
00495 
00496   return func;
00497 }
00498 
00499 static void gvalue_take_ptrarray_value (GValue *value, gpointer instance);
00500 
00501 static void
00502 gvalue_take_hash_value (GValue *value, gpointer instance)
00503 {
00504   switch (g_type_fundamental (G_VALUE_TYPE (value)))
00505     {
00506     case G_TYPE_CHAR:
00507       g_value_set_char (value, (gchar) GPOINTER_TO_INT (instance));
00508       break;
00509     case G_TYPE_UCHAR:
00510       g_value_set_uchar (value, (guchar) GPOINTER_TO_UINT (instance));
00511       break;
00512     case G_TYPE_BOOLEAN:
00513       g_value_set_boolean (value, (gboolean) GPOINTER_TO_UINT (instance));
00514       break;
00515     case G_TYPE_INT:
00516       g_value_set_int (value, GPOINTER_TO_INT (instance));
00517       break;
00518     case G_TYPE_UINT:
00519       g_value_set_uint (value, GPOINTER_TO_UINT (instance));
00520       break;
00521     case G_TYPE_DOUBLE:
00522       g_value_set_double (value, *(gdouble *) instance);
00523       break;
00524     default:
00525       gvalue_take_ptrarray_value (value, instance);
00526       break;
00527     }
00528 }
00529 
00530 static gpointer ptrarray_value_from_gvalue (const GValue *value);
00531 
00532 static gpointer
00533 hash_value_from_gvalue (GValue *value)
00534 {
00535   switch (g_type_fundamental (G_VALUE_TYPE (value)))
00536     {
00537     case G_TYPE_CHAR:
00538       return GINT_TO_POINTER ((int) g_value_get_char (value));
00539       break;
00540     case G_TYPE_UCHAR:
00541       return GUINT_TO_POINTER ((guint) g_value_get_uchar (value));
00542       break;
00543     case G_TYPE_BOOLEAN:
00544       return GUINT_TO_POINTER ((guint) g_value_get_boolean (value));
00545       break;
00546     case G_TYPE_INT:
00547       return GINT_TO_POINTER (g_value_get_int (value));
00548       break;
00549     case G_TYPE_UINT:
00550       return GUINT_TO_POINTER (g_value_get_uint (value));
00551       break;
00552     case G_TYPE_DOUBLE:
00553       {
00554         gdouble *p = (gdouble *) g_malloc0 (sizeof (gdouble));
00555         *p = g_value_get_double (value);
00556         return (gpointer) p;
00557       }
00558       break;
00559     default:
00560       return ptrarray_value_from_gvalue (value);
00561       break;
00562     }
00563 }
00564 
00565 struct DBusGHashTableValueForeachData
00566 {
00567   DBusGTypeSpecializedMapIterator func;
00568   GType key_type;
00569   GType value_type;
00570   gpointer data;
00571 };
00572 
00573 static void
00574 hashtable_foreach_with_values (gpointer key, gpointer value, gpointer user_data)
00575 {
00576   GValue key_val = {0, };
00577   GValue value_val = {0, };
00578   struct DBusGHashTableValueForeachData *data = user_data;
00579   
00580   g_value_init (&key_val, data->key_type);
00581   g_value_init (&value_val, data->value_type);
00582   gvalue_take_hash_value (&key_val, key);
00583   gvalue_take_hash_value (&value_val, value);
00584 
00585   data->func (&key_val, &value_val, data->data);
00586 }
00587 
00588 
00589 static void
00590 hashtable_iterator (GType                           hash_type,
00591                     gpointer                        instance,
00592                     DBusGTypeSpecializedMapIterator iterator,
00593                     gpointer                        user_data)
00594 {
00595   struct DBusGHashTableValueForeachData data;
00596   GType key_gtype;
00597   GType value_gtype;
00598 
00599   key_gtype = dbus_g_type_get_map_key_specialization (hash_type);
00600   value_gtype = dbus_g_type_get_map_value_specialization (hash_type);
00601 
00602   data.func = iterator;
00603   data.key_type = key_gtype;
00604   data.value_type = value_gtype;
00605   data.data = user_data;
00606 
00607   g_hash_table_foreach (instance, hashtable_foreach_with_values, &data);
00608 }
00609 
00610 void
00611 _dbus_g_hash_table_insert_steal_values (GHashTable *table,
00612                                        GValue     *key_val,
00613                                        GValue     *value_val)
00614 {
00615   gpointer key, val;
00616   
00617   key = hash_value_from_gvalue (key_val);
00618   val = hash_value_from_gvalue (value_val);
00619 
00620   g_hash_table_insert (table, key, val);
00621 }
00622 
00623 static void
00624 hashtable_append (DBusGTypeSpecializedAppendContext *ctx,
00625                   GValue                            *key,
00626                   GValue                            *val)
00627 {
00628   GHashTable *table;
00629 
00630   table = g_value_get_boxed (ctx->val);
00631   _dbus_g_hash_table_insert_steal_values (table, key, val);
00632 }
00633 
00634 static gpointer
00635 hashtable_constructor (GType type)
00636 {
00637   GHashTable *ret;
00638   GType key_gtype;
00639   GType value_gtype;
00640 
00641   key_gtype = dbus_g_type_get_map_key_specialization (type);
00642   value_gtype = dbus_g_type_get_map_value_specialization (type);
00643 
00644   ret = g_hash_table_new_full (_dbus_g_hash_func_from_gtype (key_gtype),
00645                                _dbus_g_hash_equal_from_gtype (key_gtype),
00646                                _dbus_g_hash_free_from_gtype (key_gtype),
00647                                _dbus_g_hash_free_from_gtype (value_gtype));
00648   return ret;
00649 }
00650 
00651 static void
00652 hashtable_insert_values (GHashTable       *table,
00653                          const GValue     *key_val,
00654                          const GValue     *value_val)
00655 {
00656   GValue key_copy = {0, };
00657   GValue value_copy = {0, };
00658 
00659   g_value_init (&key_copy, G_VALUE_TYPE (key_val));
00660   g_value_copy (key_val, &key_copy);
00661   g_value_init (&value_copy, G_VALUE_TYPE (value_val));
00662   g_value_copy (value_val, &value_copy);
00663   
00664   _dbus_g_hash_table_insert_steal_values (table, &key_copy, &value_copy);
00665 }
00666 
00667 static void
00668 hashtable_foreach_copy (const GValue *key, const GValue *val, gpointer data)
00669 {
00670   hashtable_insert_values ((GHashTable *) data, key, val);
00671 }
00672 
00673 static gpointer
00674 hashtable_copy (GType type, gpointer src)
00675 {
00676   GHashTable *ghash;
00677   GHashTable *ret;
00678   GValue hashval = {0,};
00679 
00680   ghash = src;
00681 
00682   ret = hashtable_constructor (type);
00683 
00684   g_value_init (&hashval, type);
00685   g_value_set_static_boxed (&hashval, ghash); 
00686   dbus_g_type_map_value_iterate (&hashval, hashtable_foreach_copy, ret);
00687   return ret;
00688 }
00689 
00690 /* we leave this here for backwards compatibility - any hash tables nested
00691  * inside hash tables will use this as their free function if users were
00692  * already relying on it, but dbus-glib itself will never use it directly as
00693  * hashtable_free is also defined. */
00694 static void
00695 hashtable_simple_free (gpointer val)
00696 {
00697   g_hash_table_unref (val);
00698 }
00699 
00700 struct DBusGHashTableFreeData
00701 {
00702   GType key_gtype;
00703   GType value_gtype;
00704 };
00705 
00706 static gboolean
00707 hashtable_free_foreach_steal (gpointer key,
00708                               gpointer value,
00709                               gpointer user_data)
00710 {
00711   struct DBusGHashTableFreeData *data = user_data;
00712   GValue val = { 0, };
00713 
00714   g_value_init (&val, data->key_gtype);
00715   gvalue_take_hash_value (&val, key);
00716   g_value_unset (&val);
00717 
00718   g_value_init (&val, data->value_gtype);
00719   gvalue_take_hash_value (&val, value);
00720   g_value_unset (&val);
00721 
00722   return TRUE;
00723 }
00724 
00725 static void
00726 hashtable_free (GType type,
00727                 gpointer val)
00728 {
00729   struct DBusGHashTableFreeData data = { 0, };
00730   GHashTable *hash = val;
00731 
00732   data.key_gtype = dbus_g_type_get_map_key_specialization (type);
00733   data.value_gtype = dbus_g_type_get_map_value_specialization (type);
00734 
00735   /* wheee, fun. two cases here. either:
00736    *
00737    * a) the keys and value types both have simple (ie, no * GType parameter is
00738    * needed to know how to free them) free functions, in which case they were
00739    * set as the hash free functions when the hash table was constructed.  in
00740    * this case, it's sufficient for us to unref the hash table as before. we
00741    * have to keep doing this in order to maintain compatibility with the ABI
00742    * which was around before hash tables could contain types which don't have
00743    * simple free functions (such as GPtrArrays of other stuff). for these
00744    * tables, users were able to ref the hash tables and add/remove values, and
00745    * rely on meaningful free functions.
00746    *
00747    * b) for any other key or value types where /do/ need to know the GType in
00748    * order to free it, this function is the only "right" way to free the hash
00749    * table. both the key and value free functions were set to print a big nasty
00750    * warning, and we free the contents of the hashtable with foreach_steal.
00751    */
00752   if (gtype_can_simple_free (data.key_gtype) &&
00753       gtype_can_simple_free (data.value_gtype))
00754     {
00755       g_hash_table_unref (hash);
00756     }
00757   else
00758     {
00759       g_hash_table_foreach_steal (hash, hashtable_free_foreach_steal, &data);
00760       g_hash_table_unref (hash);
00761     }
00762 }
00763 
00764 static gpointer
00765 valuearray_constructor (GType type)
00766 {
00767   GValueArray *ret;
00768   guint size = dbus_g_type_get_struct_size (type);
00769   guint i;
00770   ret = g_value_array_new (size);
00771   for (i=0; i < size; i++)
00772     {
00773       GValue val = {0,};
00774       g_value_init (&val, dbus_g_type_get_struct_member_type (type, i));
00775       g_value_array_append(ret, &val);
00776     }
00777   return (gpointer)ret;
00778 }
00779 
00780 static gpointer
00781 valuearray_copy (GType type, gpointer src)
00782 {
00783   return g_value_array_copy ((GValueArray*) src);
00784 }
00785 
00786 static void
00787 valuearray_simple_free (gpointer val)
00788 {
00789   g_value_array_free (val);
00790 }
00791 
00792 static gboolean
00793 valuearray_get_member (GType type, gpointer instance,
00794                        guint member, GValue *ret)
00795 {
00796   GValueArray *va = (GValueArray*) instance;
00797   const GValue *val;
00798   if (member < dbus_g_type_get_struct_size (type))
00799     {
00800       val = g_value_array_get_nth (va, member);
00801       g_value_copy (val, ret);
00802       return TRUE;
00803     }
00804   else
00805     return FALSE;
00806 }
00807 
00808 static gboolean
00809 valuearray_set_member (GType type, gpointer instance,
00810                        guint member, const GValue *member_type)
00811 {
00812   GValueArray *va = (GValueArray*) instance;
00813   GValue *vp;
00814   if (member < dbus_g_type_get_struct_size (type))
00815     {
00816       vp = g_value_array_get_nth (va, member);
00817       g_value_copy (member_type, vp);
00818       return TRUE;
00819     }
00820   else
00821     return FALSE;
00822 }
00823 
00824 
00825 static gpointer
00826 array_constructor (GType type)
00827 {
00828   GArray *array;
00829   guint elt_size;
00830   GType elt_type;
00831   gboolean zero_terminated;
00832   gboolean clear;
00833 
00834   elt_type = dbus_g_type_get_collection_specialization (type);
00835   g_assert (elt_type != G_TYPE_INVALID);
00836 
00837   elt_size = _dbus_g_type_fixed_get_size (elt_type);
00838 
00839   /* These are "safe" defaults */ 
00840   zero_terminated = TRUE; /* ((struct _DBusGRealArray*) garray)->zero_terminated; */
00841   clear = TRUE; /* ((struct _DBusGRealArray*) garray)->clear; */
00842 
00843   array = g_array_new (zero_terminated, clear, elt_size);
00844   return array;
00845 }
00846 
00847 static gpointer
00848 array_copy (GType type, gpointer src)
00849 {
00850   GArray *garray;
00851   GArray *new;
00852 
00853   garray = src;
00854 
00855   new = array_constructor (type);
00856   g_array_append_vals (new, garray->data, garray->len);
00857 
00858   return new;
00859 }
00860 
00861 static void
00862 array_simple_free (gpointer val)
00863 {
00864   GArray *array;
00865   array = val;
00866   g_array_free (array, TRUE);
00867 }
00868 
00869 static gboolean
00870 array_fixed_accessor (GType type, gpointer instance, gpointer *values, guint *len)
00871 {
00872   GType elt_type;
00873   GArray *array = instance;
00874 
00875   elt_type = dbus_g_type_get_collection_specialization (type);
00876   if (!_dbus_g_type_is_fixed (elt_type))
00877     return FALSE;
00878 
00879   *values = array->data;
00880   *len = array->len;
00881   return TRUE;
00882 }
00883 
00884 static gpointer
00885 ptrarray_constructor (GType type)
00886 {
00887   /* Later we should determine a destructor, need g_ptr_array_destroy */
00888   return g_ptr_array_new ();
00889 }
00890 
00891 static void
00892 gvalue_take_ptrarray_value (GValue *value, gpointer instance)
00893 {
00894   switch (g_type_fundamental (G_VALUE_TYPE (value)))
00895     {
00896     case G_TYPE_STRING:
00897       g_value_take_string (value, instance);
00898       break;
00899     case G_TYPE_BOXED:
00900       g_value_take_boxed (value, instance);
00901       break;
00902     case G_TYPE_OBJECT:
00903       g_value_take_object (value, instance);
00904       break;
00905     default:
00906       g_assert_not_reached ();
00907       break;
00908     }
00909 }
00910 
00911 static gpointer
00912 ptrarray_value_from_gvalue (const GValue *value)
00913 {
00914   GValue tmp = {0, };
00915 
00916   /* if the NOCOPY flag is set, then value was created via set_static and hence
00917    * is not owned by us. in order to preserve the "take" semantics that the API
00918    * has in general (which avoids copying in the common case), we must copy any
00919    * static values so that we can indiscriminately free the entire collection
00920    * later. */
00921   if (value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS)
00922     {
00923       g_value_init (&tmp, G_VALUE_TYPE (value));
00924       g_value_copy (value, &tmp);
00925       value = &tmp;
00926     }
00927 
00928   switch (g_type_fundamental (G_VALUE_TYPE (value)))
00929     {
00930     case G_TYPE_STRING:
00931       return (gpointer) g_value_get_string (value);
00932       break;
00933     case G_TYPE_BOXED:
00934       return g_value_get_boxed (value);
00935       break;
00936     case G_TYPE_OBJECT:
00937       return g_value_get_object (value);
00938       break;
00939     default:
00940       g_assert_not_reached ();
00941       return NULL;
00942     }
00943 }
00944 
00945 static void
00946 ptrarray_iterator (GType                                   ptrarray_type,
00947                    gpointer                                instance,
00948                    DBusGTypeSpecializedCollectionIterator  iterator,
00949                    gpointer                                user_data)
00950 {
00951   GPtrArray *ptrarray;
00952   GType elt_gtype;
00953   guint i;
00954 
00955   ptrarray = instance;
00956 
00957   elt_gtype = dbus_g_type_get_collection_specialization (ptrarray_type);
00958 
00959   for (i = 0; i < ptrarray->len; i++)
00960     {
00961       GValue val = {0, };
00962       g_value_init (&val, elt_gtype);
00963       gvalue_take_ptrarray_value (&val, g_ptr_array_index (ptrarray, i));
00964       iterator (&val, user_data);
00965     }
00966 }
00967 
00968 static void
00969 ptrarray_copy_elt (const GValue *val, gpointer user_data)
00970 {
00971   GPtrArray *dest = user_data;
00972   GValue val_copy = {0, };
00973 
00974   g_value_init (&val_copy, G_VALUE_TYPE (val));
00975   g_value_copy (val, &val_copy);
00976 
00977   g_ptr_array_add (dest, ptrarray_value_from_gvalue (&val_copy));
00978 }
00979 
00980 static gpointer
00981 ptrarray_copy (GType type, gpointer src)
00982 {
00983   GPtrArray *new;
00984   GValue array_val = {0, };
00985 
00986   g_value_init (&array_val, type);
00987   g_value_set_static_boxed (&array_val, src);
00988 
00989   new = ptrarray_constructor (type);
00990   dbus_g_type_collection_value_iterate (&array_val, ptrarray_copy_elt, new);
00991 
00992   return new;
00993 }
00994 
00995 static void
00996 ptrarray_append (DBusGTypeSpecializedAppendContext *ctx, GValue *value)
00997 {
00998   GPtrArray *array;
00999 
01000   array = g_value_get_boxed (ctx->val);
01001 
01002   g_ptr_array_add (array, ptrarray_value_from_gvalue (value));
01003 }
01004 
01005 static void
01006 ptrarray_free (GType type, gpointer val)
01007 {
01008   GPtrArray *array;
01009   GValue elt_val = {0, };
01010   GType elt_gtype;
01011   unsigned int i;
01012 
01013   array = val;
01014 
01015   elt_gtype = dbus_g_type_get_collection_specialization (type);
01016 
01017   for (i = 0; i < array->len; i++)
01018     {
01019       g_value_init (&elt_val, elt_gtype);
01020       gvalue_take_ptrarray_value (&elt_val, g_ptr_array_index (array, i));
01021       g_value_unset (&elt_val);
01022     }
01023 
01024   g_ptr_array_free (array, TRUE);
01025 }
01026 
01027 static gpointer
01028 slist_constructor (GType type)
01029 {
01030   return NULL;
01031 }
01032 
01033 static void
01034 slist_iterator (GType                                   list_type,
01035                 gpointer                                instance,
01036                 DBusGTypeSpecializedCollectionIterator  iterator,
01037                 gpointer                                user_data)
01038 {
01039   GSList *slist;
01040   GType elt_gtype;
01041 
01042   slist = instance;
01043 
01044   elt_gtype = dbus_g_type_get_collection_specialization (list_type);
01045 
01046   for (slist = instance; slist != NULL; slist = slist->next)
01047     {
01048       GValue val = {0, };
01049       g_value_init (&val, elt_gtype);
01050       gvalue_take_ptrarray_value (&val, slist->data);
01051       iterator (&val, user_data);
01052     }
01053 }
01054 
01055 static void
01056 slist_copy_elt (const GValue *val, gpointer user_data)
01057 {
01058   GSList **dest = user_data;
01059   GValue val_copy = {0, };
01060 
01061   g_value_init (&val_copy, G_VALUE_TYPE (val));
01062   g_value_copy (val, &val_copy);
01063 
01064   *dest = g_slist_append (*dest, ptrarray_value_from_gvalue (&val_copy));
01065 }
01066 
01067 static gpointer
01068 slist_copy (GType type, gpointer src)
01069 {
01070   GSList *new;
01071   GValue slist_val = {0, };
01072 
01073   g_value_init (&slist_val, type);
01074   g_value_set_static_boxed (&slist_val, src);
01075 
01076   new = slist_constructor (type);
01077   dbus_g_type_collection_value_iterate (&slist_val, slist_copy_elt, &new);
01078 
01079   return new;
01080 }
01081 
01082 static void
01083 slist_append (DBusGTypeSpecializedAppendContext *ctx, GValue *value)
01084 {
01085   GSList *list;
01086 
01087   list = g_value_get_boxed (ctx->val);
01088   list = g_slist_prepend (list, ptrarray_value_from_gvalue (value));
01089   g_value_set_static_boxed (ctx->val, list);
01090 }
01091 
01092 static void
01093 slist_end_append (DBusGTypeSpecializedAppendContext *ctx)
01094 {
01095   GSList *list;
01096 
01097   /* if you append multiple times to the slist, this will reverse the existing
01098    * elements... we need an init_append function */
01099   list = g_value_get_boxed (ctx->val);
01100   list = g_slist_reverse (list);
01101 
01102   g_value_take_boxed (ctx->val, list);
01103 }
01104 
01105 static void
01106 slist_free (GType type, gpointer val)
01107 {
01108   GSList *list;
01109   GType elt_gtype;
01110   list = val;
01111 
01112   elt_gtype = dbus_g_type_get_collection_specialization (type);
01113 
01114   while (list != NULL)
01115     {
01116       GValue elt_val = {0, };
01117       g_value_init (&elt_val, elt_gtype);
01118       gvalue_take_ptrarray_value (&elt_val, list->data);
01119       g_value_unset (&elt_val);
01120       list = g_slist_next(list);
01121     }
01122   list=val;
01123   g_slist_free (list);
01124 }
01125 
01126 void
01127 _dbus_g_type_specialized_builtins_init (void)
01128 {
01129   /* types with a simple_free function can be freed at run-time without
01130    * the destroy function needing to know the type, so they can be
01131    * stored in hash tables */
01132 
01133   static const DBusGTypeSpecializedCollectionVtable array_vtable = {
01134     {
01135       array_constructor,
01136       NULL,
01137       array_copy,
01138       array_simple_free,
01139       NULL,
01140       NULL,
01141     },
01142     array_fixed_accessor,
01143     NULL,
01144     NULL,
01145     NULL
01146   };
01147 
01148 
01149   static const DBusGTypeSpecializedCollectionVtable ptrarray_vtable = {
01150     {
01151       ptrarray_constructor,
01152       ptrarray_free,
01153       ptrarray_copy,
01154       NULL,
01155       NULL,
01156       NULL,
01157     },
01158     NULL,
01159     ptrarray_iterator,
01160     ptrarray_append,
01161     NULL,
01162   };
01163 
01164 
01165   static const DBusGTypeSpecializedCollectionVtable slist_vtable = {
01166     {
01167       slist_constructor,
01168       slist_free,
01169       slist_copy,
01170       NULL,
01171       NULL,
01172       NULL,
01173     },
01174     NULL,
01175     slist_iterator,
01176     slist_append,
01177     slist_end_append,
01178   };
01179 
01180   static const DBusGTypeSpecializedMapVtable hashtable_vtable = {
01181     {
01182       hashtable_constructor,
01183       hashtable_free,
01184       hashtable_copy,
01185       hashtable_simple_free,
01186       NULL,
01187       NULL
01188     },
01189     hashtable_iterator,
01190     hashtable_append
01191   };
01192 
01193   static const DBusGTypeSpecializedStructVtable valuearray_vtable = {
01194     {
01195       valuearray_constructor,
01196       NULL,
01197       valuearray_copy,
01198       valuearray_simple_free,
01199       NULL,
01200       NULL
01201     },
01202     valuearray_get_member,
01203     valuearray_set_member
01204   };
01205 
01206   dbus_g_type_register_collection ("GSList", &slist_vtable, 0);
01207   dbus_g_type_register_collection ("GArray", &array_vtable, 0);
01208   dbus_g_type_register_collection ("GPtrArray", &ptrarray_vtable, 0);
01209   dbus_g_type_register_map ("GHashTable", &hashtable_vtable, 0);
01210   dbus_g_type_register_struct ("GValueArray", &valuearray_vtable, 0);
01211 }
01212 
01213 #ifdef DBUS_BUILD_TESTS
01214 
01215 typedef struct
01216 {
01217   gboolean seen_foo;
01218   gboolean seen_baz;
01219 } TestSpecializedHashData;
01220 
01221 static void
01222 test_specialized_hash (const GValue *key, const GValue *val, gpointer user_data)
01223 {
01224   TestSpecializedHashData *data = user_data;
01225 
01226   g_assert (G_VALUE_HOLDS_STRING (key));
01227   g_assert (G_VALUE_HOLDS_STRING (val));
01228 
01229   if (!strcmp (g_value_get_string (key), "foo"))
01230     {
01231       data->seen_foo = TRUE;
01232       g_assert (!strcmp (g_value_get_string (val), "bar"));
01233     }
01234   else if (!strcmp (g_value_get_string (key), "baz"))
01235     {
01236       data->seen_baz = TRUE;
01237       g_assert (!strcmp (g_value_get_string (val), "moo"));
01238     }
01239   else
01240     {
01241       g_assert_not_reached ();
01242     }
01243 }
01244 
01245 static void
01246 test_specialized_hash_2 (const GValue *key, const GValue *val, gpointer user_data)
01247 {
01248   TestSpecializedHashData *data = user_data;
01249   const GValue *realval;
01250 
01251   g_assert (G_VALUE_HOLDS_STRING (key));
01252   g_assert (G_VALUE_TYPE (val) == G_TYPE_VALUE);
01253 
01254   realval = g_value_get_boxed (val);
01255 
01256   if (!strcmp (g_value_get_string (key), "foo"))
01257     {
01258       data->seen_foo = TRUE;
01259       g_assert (G_VALUE_HOLDS_UINT (realval));
01260       g_assert (g_value_get_uint (realval) == 20);
01261     }
01262   else if (!strcmp (g_value_get_string (key), "baz"))
01263     {
01264       data->seen_baz = TRUE;
01265       g_assert (G_VALUE_HOLDS_STRING (realval));
01266       g_assert (!strcmp ("bar", g_value_get_string (realval)));
01267     }
01268   else
01269     {
01270       g_assert_not_reached ();
01271     }
01272 }
01273 
01274 gboolean
01275 _dbus_gvalue_utils_test (const char *datadir)
01276 {
01277   GType type;
01278 
01279   dbus_g_type_specialized_init ();
01280  _dbus_g_type_specialized_builtins_init ();
01281 
01282   type = dbus_g_type_get_collection ("GArray", G_TYPE_UINT);
01283   g_assert (dbus_g_type_is_collection (type));
01284   g_assert (dbus_g_type_get_collection_specialization (type) == G_TYPE_UINT);
01285   {
01286     GArray *instance;
01287 
01288     instance = dbus_g_type_specialized_construct (type);
01289 
01290     g_assert (instance->len == 0);
01291 
01292     g_array_free (instance, TRUE);
01293   }
01294 
01295   type = dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING);
01296   g_assert (dbus_g_type_is_map (type));
01297   g_assert (dbus_g_type_get_map_key_specialization (type) == G_TYPE_STRING);
01298   g_assert (dbus_g_type_get_map_value_specialization (type) == G_TYPE_STRING);
01299   {
01300     GHashTable *instance;
01301     GValue val = { 0, };
01302     TestSpecializedHashData hashdata;
01303 
01304     instance = dbus_g_type_specialized_construct (type);
01305 
01306     g_assert (g_hash_table_size (instance) == 0);
01307     g_hash_table_insert (instance, g_strdup ("foo"), g_strdup ("bar"));
01308     g_hash_table_insert (instance, g_strdup ("baz"), g_strdup ("moo"));
01309     g_assert (g_hash_table_size (instance) == 2);
01310 
01311     g_value_init (&val, type);
01312     g_value_set_boxed_take_ownership (&val, instance);
01313     hashdata.seen_foo = FALSE;
01314     hashdata.seen_baz = FALSE;
01315     dbus_g_type_map_value_iterate (&val,
01316                                    test_specialized_hash, 
01317                                    &hashdata);
01318     
01319     g_assert (hashdata.seen_foo);
01320     g_assert (hashdata.seen_baz);
01321 
01322     g_value_unset (&val);
01323   }
01324 
01325   type = dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE);
01326   g_assert (dbus_g_type_is_map (type));
01327   g_assert (dbus_g_type_get_map_key_specialization (type) == G_TYPE_STRING);
01328   g_assert (dbus_g_type_get_map_value_specialization (type) == G_TYPE_VALUE);
01329   {
01330     GHashTable *instance;
01331     GValue val = { 0, };
01332     TestSpecializedHashData hashdata;
01333     DBusGTypeSpecializedAppendContext ctx;
01334     GValue *eltval;
01335 
01336     instance = dbus_g_type_specialized_construct (type);
01337     g_value_init (&val, type);
01338     g_value_set_boxed_take_ownership (&val, instance);
01339 
01340     dbus_g_type_specialized_init_append (&val, &ctx);
01341 
01342     {
01343       GValue keyval = { 0, };
01344       GValue valval = { 0, };
01345       g_value_init (&keyval, G_TYPE_STRING);
01346       g_value_set_string (&keyval, "foo"); 
01347 
01348       g_value_init (&valval, G_TYPE_VALUE);
01349       eltval = g_new0 (GValue, 1);
01350       g_value_init (eltval, G_TYPE_UINT);
01351       g_value_set_uint (eltval, 20);
01352       g_value_set_boxed_take_ownership (&valval, eltval);
01353       dbus_g_type_specialized_map_append (&ctx, &keyval, &valval);
01354     }
01355 
01356     {
01357       GValue keyval = { 0, };
01358       GValue valval = { 0, };
01359       g_value_init (&keyval, G_TYPE_STRING);
01360       g_value_set_string (&keyval, "baz"); 
01361       g_value_init (&valval, G_TYPE_VALUE);
01362       eltval = g_new0 (GValue, 1);
01363       g_value_init (eltval, G_TYPE_STRING);
01364       g_value_set_string (eltval, "bar");
01365       g_value_set_boxed_take_ownership (&valval, eltval);
01366       dbus_g_type_specialized_map_append (&ctx, &keyval, &valval);
01367     }
01368 
01369     hashdata.seen_foo = FALSE;
01370     hashdata.seen_baz = FALSE;
01371     dbus_g_type_map_value_iterate (&val,
01372                                    test_specialized_hash_2, 
01373                                    &hashdata);
01374     
01375     g_assert (hashdata.seen_foo);
01376     g_assert (hashdata.seen_baz);
01377 
01378     g_value_unset (&val);
01379   }
01380 
01381   type = dbus_g_type_get_collection ("GSList", G_TYPE_OBJECT);
01382   g_assert (dbus_g_type_is_collection (type));
01383   g_assert (dbus_g_type_get_collection_specialization (type) == G_TYPE_OBJECT);
01384   {
01385     GSList *instance, *tmp, *copy;
01386     GValue val = {0, };
01387     GValue copyval = {0, };
01388     DBusGTypeSpecializedAppendContext ctx;
01389     GObject *objects[3];
01390     int i;
01391 
01392     instance = dbus_g_type_specialized_construct (type);
01393     g_assert (instance == NULL);
01394 
01395     g_value_init (&val, type);
01396     g_value_take_boxed (&val, instance);
01397 
01398     dbus_g_type_specialized_init_append (&val, &ctx);
01399 
01400     for (i = 0; i < 3; i++)
01401       {
01402         GValue eltval = { 0, };
01403         GObject *obj = g_object_new (G_TYPE_OBJECT, NULL);
01404 
01405         g_assert (obj != NULL);
01406         objects[i] = obj;
01407         g_object_add_weak_pointer (obj, (gpointer) (objects + i));
01408 
01409         g_value_init (&eltval, G_TYPE_OBJECT);
01410         g_value_take_object (&eltval, obj);
01411         dbus_g_type_specialized_collection_append (&ctx, &eltval);
01412       }
01413 
01414     dbus_g_type_specialized_collection_end_append (&ctx);
01415 
01416     instance = g_value_get_boxed (&val);
01417     g_assert (g_slist_length (instance) == 3);
01418 
01419     for (tmp = instance; tmp; tmp = tmp->next)
01420       {
01421         GObject *obj = tmp->data;
01422         g_assert (G_IS_OBJECT (obj));
01423         g_assert (obj->ref_count == 1);
01424       }
01425 
01426     g_value_init (&copyval, type);
01427     g_value_copy (&val, &copyval);
01428 
01429     copy = g_value_get_boxed (&copyval);
01430     g_assert (g_slist_length (copy) == 3);
01431 
01432     for (tmp = copy; tmp; tmp = tmp->next)
01433       {
01434         GObject *obj = tmp->data;
01435         g_assert (G_IS_OBJECT (obj));
01436         g_assert (obj->ref_count == 2);
01437       }
01438 
01439     g_value_unset (&copyval);
01440 
01441     for (i = 0; i < 3; i++)
01442       {
01443         g_assert (objects[i] != NULL);
01444       }
01445 
01446     for (tmp = instance; tmp; tmp = tmp->next)
01447       {
01448         GObject *obj = tmp->data;
01449         g_assert (G_IS_OBJECT (obj));
01450         g_assert (obj->ref_count == 1);
01451       }
01452 
01453     g_value_unset (&val);
01454 
01455     for (i = 0; i < 3; i++)
01456       {
01457         g_assert (objects[i] == NULL);
01458       }
01459   }
01460 
01461   type = dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING);
01462   g_assert (dbus_g_type_is_collection (type));
01463   g_assert (dbus_g_type_get_collection_specialization (type) == G_TYPE_STRING);
01464   {
01465     GPtrArray *instance;
01466     DBusGTypeSpecializedAppendContext ctx;
01467     GValue val = {0, };
01468     GValue eltval = {0, };
01469 
01470     instance = dbus_g_type_specialized_construct (type);
01471 
01472     g_assert (instance->len == 0);
01473 
01474     g_value_init (&val, type);
01475     g_value_set_boxed_take_ownership (&val, instance);
01476 
01477     dbus_g_type_specialized_init_append (&val, &ctx);
01478 
01479     g_value_init (&eltval, G_TYPE_STRING);
01480     g_value_set_static_string (&eltval, "foo");
01481     dbus_g_type_specialized_collection_append (&ctx, &eltval);
01482 
01483     g_value_reset (&eltval);
01484     g_value_set_static_string (&eltval, "bar");
01485     dbus_g_type_specialized_collection_append (&ctx, &eltval);
01486 
01487     g_value_reset (&eltval);
01488     g_value_set_static_string (&eltval, "baz");
01489     dbus_g_type_specialized_collection_append (&ctx, &eltval);
01490 
01491     dbus_g_type_specialized_collection_end_append (&ctx);
01492 
01493     g_assert (instance->len == 3);
01494 
01495     g_assert (!strcmp ("foo", g_ptr_array_index (instance, 0)));
01496     g_assert (!strcmp ("bar", g_ptr_array_index (instance, 1)));
01497     g_assert (!strcmp ("baz", g_ptr_array_index (instance, 2)));
01498 
01499     g_value_unset (&val);
01500   }
01501 
01502   type = dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_UINT, DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
01503   g_assert (dbus_g_type_is_struct (type));
01504   g_assert (dbus_g_type_get_struct_size (type) == 3);
01505   g_assert (dbus_g_type_get_struct_member_type (type, 0) == G_TYPE_STRING);
01506   g_assert (dbus_g_type_get_struct_member_type (type, 1) == G_TYPE_UINT);
01507   g_assert (dbus_g_type_get_struct_member_type (type, 2) == DBUS_TYPE_G_OBJECT_PATH);
01508   {
01509     GValueArray *instance;
01510     GValue val = {0, };
01511     GValue memval = {0, };
01512 
01513     instance = dbus_g_type_specialized_construct (type);
01514 
01515     g_assert (instance->n_values == 3);
01516 
01517     g_value_init (&val, type);
01518     g_value_set_boxed_take_ownership (&val, instance);
01519 
01520     g_value_init (&memval, G_TYPE_STRING);
01521     g_value_set_static_string (&memval, "foo");
01522     dbus_g_type_struct_set_member (&val, 0, &memval);
01523     g_value_unset (&memval);
01524 
01525     g_value_init (&memval, G_TYPE_UINT);
01526     g_value_set_uint (&memval, 42);
01527     dbus_g_type_struct_set_member (&val, 1, &memval);
01528     g_value_unset (&memval);
01529 
01530     g_value_init (&memval, DBUS_TYPE_G_OBJECT_PATH);
01531     g_value_set_static_boxed (&memval, "/bar/moo/foo/baz");
01532     dbus_g_type_struct_set_member (&val, 2, &memval);
01533     g_value_unset (&memval);
01534 
01535     g_assert (instance->n_values == 3);
01536 
01537     g_value_init (&memval, G_TYPE_STRING);
01538     dbus_g_type_struct_get_member (&val, 0, &memval);
01539     g_assert (0 == strcmp (g_value_get_string (&memval), "foo"));
01540     g_value_unset (&memval);
01541 
01542     g_value_init (&memval, G_TYPE_UINT);
01543     dbus_g_type_struct_get_member (&val, 1, &memval);
01544     g_assert (g_value_get_uint (&memval) == 42);
01545     g_value_unset (&memval);
01546 
01547     g_value_init (&memval, DBUS_TYPE_G_OBJECT_PATH);
01548     dbus_g_type_struct_get_member (&val, 2, &memval);
01549     g_assert (0 == strcmp ((gchar*) g_value_get_boxed (&memval),
01550                            "/bar/moo/foo/baz"));
01551     g_value_unset (&memval);
01552 
01553     g_value_unset (&val);
01554   }
01555 
01556   type = dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_UINT, DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
01557   g_assert (dbus_g_type_is_struct (type));
01558   g_assert (dbus_g_type_get_struct_size (type) == 3);
01559   g_assert (dbus_g_type_get_struct_member_type (type, 0) == G_TYPE_STRING);
01560   g_assert (dbus_g_type_get_struct_member_type (type, 1) == G_TYPE_UINT);
01561   g_assert (dbus_g_type_get_struct_member_type (type, 2) == DBUS_TYPE_G_OBJECT_PATH);
01562   {
01563     GValueArray *instance;
01564     GValue val = {0, };
01565 
01566     instance = dbus_g_type_specialized_construct (type);
01567 
01568     g_assert (instance->n_values == 3);
01569 
01570     g_value_init (&val, type);
01571     g_value_set_boxed_take_ownership (&val, instance);
01572 
01573     dbus_g_type_struct_set (&val,
01574                             0,"foo",
01575                             1, 42,
01576                             2, "/bar/moo/foo/baz",
01577                             G_MAXUINT);
01578 
01579     g_assert (instance->n_values == 3);
01580 
01581     {
01582       gchar *string;
01583       guint intval;
01584       gchar *path;
01585 
01586       dbus_g_type_struct_get (&val,
01587                               0, &string,
01588                               1, &intval,
01589                               2, &path,
01590                               G_MAXUINT);
01591 
01592       g_assert (0 == strcmp (string, "foo"));
01593       g_assert (intval == 42);
01594       g_assert (0 == strcmp (path, "/bar/moo/foo/baz"));
01595     }
01596 
01597     g_value_unset (&val);
01598   }
01599 
01600 
01601   return TRUE;
01602 }
01603 
01604 
01605 
01606 #endif /* DBUS_BUILD_TESTS */

Generated on Tue Feb 24 16:47:59 2009 for D-BUSGLibBindings by  doxygen 1.5.1