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     }
00252 }
00253 
00254 
00255 static gboolean
00256 hash_func_from_gtype (GType gtype, GHashFunc *func)
00257 {
00258   switch (gtype)
00259     {
00260     case G_TYPE_CHAR:
00261     case G_TYPE_UCHAR:
00262     case G_TYPE_BOOLEAN:
00263     case G_TYPE_INT:
00264     case G_TYPE_UINT:
00265       *func = NULL;
00266       return TRUE;
00267     case G_TYPE_STRING:
00268       *func = g_str_hash;
00269       return TRUE;
00270     default:
00271       return FALSE;
00272     }
00273 }
00274 
00275 static void
00276 unset_and_free_g_value (gpointer val)
00277 {
00278   GValue *value = val;
00279 
00280   g_value_unset (value);
00281   g_free (value);
00282 }
00283 
00284 static gboolean
00285 hash_free_from_gtype (GType gtype, GDestroyNotify *func)
00286 {
00287   switch (gtype)
00288     {
00289     case G_TYPE_CHAR:
00290     case G_TYPE_UCHAR:
00291     case G_TYPE_BOOLEAN:
00292     case G_TYPE_INT:
00293     case G_TYPE_UINT:
00294       *func = NULL;
00295       return TRUE;
00296     case G_TYPE_DOUBLE:
00297     case G_TYPE_STRING:
00298       *func = g_free;
00299       return TRUE;
00300     default:
00301       if (gtype == G_TYPE_VALUE)
00302         {
00303           *func = unset_and_free_g_value;
00304           return TRUE;
00305         }
00306       else if (gtype == G_TYPE_VALUE_ARRAY)
00307         {
00308           *func = (GDestroyNotify) g_value_array_free;
00309           return TRUE;
00310         }
00311       else if (dbus_g_type_is_collection (gtype))
00312         {
00313           const DBusGTypeSpecializedCollectionVtable* vtable;
00314           vtable = dbus_g_type_collection_peek_vtable (gtype);
00315           if (vtable->base_vtable.simple_free_func)
00316             {
00317               *func = vtable->base_vtable.simple_free_func;
00318               return TRUE;
00319             }
00320         }
00321       else if (dbus_g_type_is_map (gtype))
00322         {
00323           const DBusGTypeSpecializedMapVtable* vtable;
00324           vtable = dbus_g_type_map_peek_vtable (gtype);
00325           if (vtable->base_vtable.simple_free_func)
00326             {
00327               *func = vtable->base_vtable.simple_free_func;
00328               return TRUE;
00329             }
00330         }
00331       else if (dbus_g_type_is_struct (gtype))
00332         {
00333           const DBusGTypeSpecializedStructVtable *vtable;
00334           vtable = dbus_g_type_struct_peek_vtable (gtype);
00335           if (vtable->base_vtable.simple_free_func)
00336             {
00337               *func = vtable->base_vtable.simple_free_func;
00338               return TRUE;
00339             }
00340         }
00341       return FALSE;
00342     }
00343 }
00344 
00345 gboolean
00346 _dbus_gtype_is_valid_hash_key (GType type)
00347 {
00348   GHashFunc func;
00349   return hash_func_from_gtype (type, &func);
00350 }
00351 
00352 gboolean
00353 _dbus_gtype_is_valid_hash_value (GType type)
00354 {
00355   GDestroyNotify func;
00356   return hash_free_from_gtype (type, &func);
00357 }
00358 
00359 GHashFunc
00360 _dbus_g_hash_func_from_gtype (GType gtype)
00361 {
00362   GHashFunc func;
00363   gboolean ret;
00364   ret = hash_func_from_gtype (gtype, &func);
00365   g_assert (ret != FALSE);
00366   return func;
00367 }
00368 
00369 GEqualFunc
00370 _dbus_g_hash_equal_from_gtype (GType gtype)
00371 {
00372   g_assert (_dbus_gtype_is_valid_hash_key (gtype));
00373 
00374   switch (gtype)
00375     {
00376     case G_TYPE_CHAR:
00377     case G_TYPE_UCHAR:
00378     case G_TYPE_BOOLEAN:
00379     case G_TYPE_INT:
00380     case G_TYPE_UINT:
00381       return NULL;
00382     case G_TYPE_STRING:
00383       return g_str_equal;
00384     default:
00385       g_assert_not_reached ();
00386       return NULL;
00387     }
00388 }
00389 
00390 GDestroyNotify
00391 _dbus_g_hash_free_from_gtype (GType gtype)
00392 {
00393   GDestroyNotify func;
00394   gboolean ret;
00395   ret = hash_free_from_gtype (gtype, &func);
00396   g_assert (ret != FALSE);
00397   return func;
00398 }
00399 
00400 static void gvalue_take_ptrarray_value (GValue *value, gpointer instance);
00401 
00402 static void
00403 gvalue_take_hash_value (GValue *value, gpointer instance)
00404 {
00405   switch (g_type_fundamental (G_VALUE_TYPE (value)))
00406     {
00407     case G_TYPE_CHAR:
00408       g_value_set_char (value, (gchar) GPOINTER_TO_INT (instance));
00409       break;
00410     case G_TYPE_UCHAR:
00411       g_value_set_uchar (value, (guchar) GPOINTER_TO_UINT (instance));
00412       break;
00413     case G_TYPE_BOOLEAN:
00414       g_value_set_boolean (value, (gboolean) GPOINTER_TO_UINT (instance));
00415       break;
00416     case G_TYPE_INT:
00417       g_value_set_int (value, GPOINTER_TO_INT (instance));
00418       break;
00419     case G_TYPE_UINT:
00420       g_value_set_uint (value, GPOINTER_TO_UINT (instance));
00421       break;
00422     case G_TYPE_DOUBLE:
00423       g_value_set_double (value, *(gdouble *) instance);
00424       break;
00425     default:
00426       gvalue_take_ptrarray_value (value, instance);
00427       break;
00428     }
00429 }
00430 
00431 static gpointer ptrarray_value_from_gvalue (const GValue *value);
00432 
00433 static gpointer
00434 hash_value_from_gvalue (GValue *value)
00435 {
00436   switch (g_type_fundamental (G_VALUE_TYPE (value)))
00437     {
00438     case G_TYPE_CHAR:
00439       return GINT_TO_POINTER ((int) g_value_get_char (value));
00440       break;
00441     case G_TYPE_UCHAR:
00442       return GUINT_TO_POINTER ((guint) g_value_get_uchar (value));
00443       break;
00444     case G_TYPE_BOOLEAN:
00445       return GUINT_TO_POINTER ((guint) g_value_get_boolean (value));
00446       break;
00447     case G_TYPE_INT:
00448       return GINT_TO_POINTER (g_value_get_int (value));
00449       break;
00450     case G_TYPE_UINT:
00451       return GUINT_TO_POINTER (g_value_get_uint (value));
00452       break;
00453     case G_TYPE_DOUBLE:
00454       {
00455         gdouble *p = (gdouble *) g_malloc0 (sizeof (gdouble));
00456         *p = g_value_get_double (value);
00457         return (gpointer) p;
00458       }
00459       break;
00460     default:
00461       return ptrarray_value_from_gvalue (value);
00462       break;
00463     }
00464 }
00465 
00466 struct DBusGHashTableValueForeachData
00467 {
00468   DBusGTypeSpecializedMapIterator func;
00469   GType key_type;
00470   GType value_type;
00471   gpointer data;
00472 };
00473 
00474 static void
00475 hashtable_foreach_with_values (gpointer key, gpointer value, gpointer user_data)
00476 {
00477   GValue key_val = {0, };
00478   GValue value_val = {0, };
00479   struct DBusGHashTableValueForeachData *data = user_data;
00480   
00481   g_value_init (&key_val, data->key_type);
00482   g_value_init (&value_val, data->value_type);
00483   gvalue_take_hash_value (&key_val, key);
00484   gvalue_take_hash_value (&value_val, value);
00485 
00486   data->func (&key_val, &value_val, data->data);
00487 }
00488 
00489 
00490 static void
00491 hashtable_iterator (GType                           hash_type,
00492                     gpointer                        instance,
00493                     DBusGTypeSpecializedMapIterator iterator,
00494                     gpointer                        user_data)
00495 {
00496   struct DBusGHashTableValueForeachData data;
00497   GType key_gtype;
00498   GType value_gtype;
00499 
00500   key_gtype = dbus_g_type_get_map_key_specialization (hash_type);
00501   value_gtype = dbus_g_type_get_map_value_specialization (hash_type);
00502 
00503   data.func = iterator;
00504   data.key_type = key_gtype;
00505   data.value_type = value_gtype;
00506   data.data = user_data;
00507 
00508   g_hash_table_foreach (instance, hashtable_foreach_with_values, &data);
00509 }
00510 
00511 void
00512 _dbus_g_hash_table_insert_steal_values (GHashTable *table,
00513                                        GValue     *key_val,
00514                                        GValue     *value_val)
00515 {
00516   gpointer key, val;
00517   
00518   key = hash_value_from_gvalue (key_val);
00519   val = hash_value_from_gvalue (value_val);
00520 
00521   g_hash_table_insert (table, key, val);
00522 }
00523 
00524 static void
00525 hashtable_append (DBusGTypeSpecializedAppendContext *ctx,
00526                   GValue                            *key,
00527                   GValue                            *val)
00528 {
00529   GHashTable *table;
00530 
00531   table = g_value_get_boxed (ctx->val);
00532   _dbus_g_hash_table_insert_steal_values (table, key, val);
00533 }
00534 
00535 static gpointer
00536 hashtable_constructor (GType type)
00537 {
00538   GHashTable *ret;
00539   GType key_gtype;
00540   GType value_gtype;
00541 
00542   key_gtype = dbus_g_type_get_map_key_specialization (type);
00543   value_gtype = dbus_g_type_get_map_value_specialization (type);
00544 
00545   ret = g_hash_table_new_full (_dbus_g_hash_func_from_gtype (key_gtype),
00546                                _dbus_g_hash_equal_from_gtype (key_gtype),
00547                                _dbus_g_hash_free_from_gtype (key_gtype),
00548                                _dbus_g_hash_free_from_gtype (value_gtype));
00549   return ret;
00550 }
00551 
00552 static void
00553 hashtable_insert_values (GHashTable       *table,
00554                          const GValue     *key_val,
00555                          const GValue     *value_val)
00556 {
00557   GValue key_copy = {0, };
00558   GValue value_copy = {0, };
00559 
00560   g_value_init (&key_copy, G_VALUE_TYPE (key_val));
00561   g_value_copy (key_val, &key_copy);
00562   g_value_init (&value_copy, G_VALUE_TYPE (value_val));
00563   g_value_copy (value_val, &value_copy);
00564   
00565   _dbus_g_hash_table_insert_steal_values (table, &key_copy, &value_copy);
00566 }
00567 
00568 static void
00569 hashtable_foreach_copy (const GValue *key, const GValue *val, gpointer data)
00570 {
00571   hashtable_insert_values ((GHashTable *) data, key, val);
00572 }
00573 
00574 static gpointer
00575 hashtable_copy (GType type, gpointer src)
00576 {
00577   GHashTable *ghash;
00578   GHashTable *ret;
00579   GValue hashval = {0,};
00580 
00581   ghash = src;
00582 
00583   ret = hashtable_constructor (type);
00584 
00585   g_value_init (&hashval, type);
00586   g_value_set_static_boxed (&hashval, ghash); 
00587   dbus_g_type_map_value_iterate (&hashval, hashtable_foreach_copy, ret);
00588   return ret;
00589 }
00590 
00591 static void
00592 hashtable_simple_free (gpointer val)
00593 {
00594   g_hash_table_destroy (val);
00595 }
00596 
00597 static gpointer
00598 valuearray_constructor (GType type)
00599 {
00600   GValueArray *ret;
00601   guint size = dbus_g_type_get_struct_size (type);
00602   guint i;
00603   ret = g_value_array_new (size);
00604   for (i=0; i < size; i++)
00605     {
00606       GValue val = {0,};
00607       g_value_init (&val, dbus_g_type_get_struct_member_type (type, i));
00608       g_value_array_append(ret, &val);
00609     }
00610   return (gpointer)ret;
00611 }
00612 
00613 static gpointer
00614 valuearray_copy (GType type, gpointer src)
00615 {
00616   return g_value_array_copy ((GValueArray*) src);
00617 }
00618 
00619 static void
00620 valuearray_simple_free (gpointer val)
00621 {
00622   g_value_array_free (val);
00623 }
00624 
00625 static gboolean
00626 valuearray_get_member (GType type, gpointer instance,
00627                        guint member, GValue *ret)
00628 {
00629   GValueArray *va = (GValueArray*) instance;
00630   const GValue *val;
00631   if (member < dbus_g_type_get_struct_size (type))
00632     {
00633       val = g_value_array_get_nth (va, member);
00634       g_value_copy (val, ret);
00635       return TRUE;
00636     }
00637   else
00638     return FALSE;
00639 }
00640 
00641 static gboolean
00642 valuearray_set_member (GType type, gpointer instance,
00643                        guint member, const GValue *member_type)
00644 {
00645   GValueArray *va = (GValueArray*) instance;
00646   GValue *vp;
00647   if (member < dbus_g_type_get_struct_size (type))
00648     {
00649       vp = g_value_array_get_nth (va, member);
00650       g_value_copy (member_type, vp);
00651       return TRUE;
00652     }
00653   else
00654     return FALSE;
00655 }
00656 
00657 
00658 static gpointer
00659 array_constructor (GType type)
00660 {
00661   GArray *array;
00662   guint elt_size;
00663   GType elt_type;
00664   gboolean zero_terminated;
00665   gboolean clear;
00666 
00667   elt_type = dbus_g_type_get_collection_specialization (type);
00668   g_assert (elt_type != G_TYPE_INVALID);
00669 
00670   elt_size = _dbus_g_type_fixed_get_size (elt_type);
00671 
00672   /* These are "safe" defaults */ 
00673   zero_terminated = TRUE; /* ((struct _DBusGRealArray*) garray)->zero_terminated; */
00674   clear = TRUE; /* ((struct _DBusGRealArray*) garray)->clear; */
00675 
00676   array = g_array_new (zero_terminated, clear, elt_size);
00677   return array;
00678 }
00679 
00680 static gpointer
00681 array_copy (GType type, gpointer src)
00682 {
00683   GArray *garray;
00684   GArray *new;
00685 
00686   garray = src;
00687 
00688   new = array_constructor (type);
00689   g_array_append_vals (new, garray->data, garray->len);
00690 
00691   return new;
00692 }
00693 
00694 static void
00695 array_simple_free (gpointer val)
00696 {
00697   GArray *array;
00698   array = val;
00699   g_array_free (array, TRUE);
00700 }
00701 
00702 static gboolean
00703 array_fixed_accessor (GType type, gpointer instance, gpointer *values, guint *len)
00704 {
00705   GType elt_type;
00706   GArray *array = instance;
00707 
00708   elt_type = dbus_g_type_get_collection_specialization (type);
00709   if (!_dbus_g_type_is_fixed (elt_type))
00710     return FALSE;
00711 
00712   *values = array->data;
00713   *len = array->len;
00714   return TRUE;
00715 }
00716 
00717 static gpointer
00718 ptrarray_constructor (GType type)
00719 {
00720   /* Later we should determine a destructor, need g_ptr_array_destroy */
00721   return g_ptr_array_new ();
00722 }
00723 
00724 static void
00725 gvalue_take_ptrarray_value (GValue *value, gpointer instance)
00726 {
00727   switch (g_type_fundamental (G_VALUE_TYPE (value)))
00728     {
00729     case G_TYPE_STRING:
00730       g_value_take_string (value, instance);
00731       break;
00732     case G_TYPE_BOXED:
00733       g_value_take_boxed (value, instance);
00734       break;
00735     case G_TYPE_OBJECT:
00736       g_value_take_object (value, instance);
00737       break;
00738     default:
00739       g_assert_not_reached ();
00740       break;
00741     }
00742 }
00743 
00744 static gpointer
00745 ptrarray_value_from_gvalue (const GValue *value)
00746 {
00747   GValue tmp = {0, };
00748 
00749   /* if the NOCOPY flag is set, then value was created via set_static and hence
00750    * is not owned by us. in order to preserve the "take" semantics that the API
00751    * has in general (which avoids copying in the common case), we must copy any
00752    * static values so that we can indiscriminately free the entire collection
00753    * later. */
00754   if (value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS)
00755     {
00756       g_value_init (&tmp, G_VALUE_TYPE (value));
00757       g_value_copy (value, &tmp);
00758       value = &tmp;
00759     }
00760 
00761   switch (g_type_fundamental (G_VALUE_TYPE (value)))
00762     {
00763     case G_TYPE_STRING:
00764       return (gpointer) g_value_get_string (value);
00765       break;
00766     case G_TYPE_BOXED:
00767       return g_value_get_boxed (value);
00768       break;
00769     case G_TYPE_OBJECT:
00770       return g_value_get_object (value);
00771       break;
00772     default:
00773       g_assert_not_reached ();
00774       return NULL;
00775     }
00776 }
00777 
00778 static void
00779 ptrarray_iterator (GType                                   ptrarray_type,
00780                    gpointer                                instance,
00781                    DBusGTypeSpecializedCollectionIterator  iterator,
00782                    gpointer                                user_data)
00783 {
00784   GPtrArray *ptrarray;
00785   GType elt_gtype;
00786   guint i;
00787 
00788   ptrarray = instance;
00789 
00790   elt_gtype = dbus_g_type_get_collection_specialization (ptrarray_type);
00791 
00792   for (i = 0; i < ptrarray->len; i++)
00793     {
00794       GValue val = {0, };
00795       g_value_init (&val, elt_gtype);
00796       gvalue_take_ptrarray_value (&val, g_ptr_array_index (ptrarray, i));
00797       iterator (&val, user_data);
00798     }
00799 }
00800 
00801 static void
00802 ptrarray_copy_elt (const GValue *val, gpointer user_data)
00803 {
00804   GPtrArray *dest = user_data;
00805   GValue val_copy = {0, };
00806 
00807   g_value_init (&val_copy, G_VALUE_TYPE (val));
00808   g_value_copy (val, &val_copy);
00809 
00810   g_ptr_array_add (dest, ptrarray_value_from_gvalue (&val_copy));
00811 }
00812 
00813 static gpointer
00814 ptrarray_copy (GType type, gpointer src)
00815 {
00816   GPtrArray *new;
00817   GValue array_val = {0, };
00818 
00819   g_value_init (&array_val, type);
00820   g_value_set_static_boxed (&array_val, src);
00821 
00822   new = ptrarray_constructor (type);
00823   dbus_g_type_collection_value_iterate (&array_val, ptrarray_copy_elt, new);
00824 
00825   return new;
00826 }
00827 
00828 static void
00829 ptrarray_append (DBusGTypeSpecializedAppendContext *ctx, GValue *value)
00830 {
00831   GPtrArray *array;
00832 
00833   array = g_value_get_boxed (ctx->val);
00834 
00835   g_ptr_array_add (array, ptrarray_value_from_gvalue (value));
00836 }
00837 
00838 static void
00839 ptrarray_free (GType type, gpointer val)
00840 {
00841   GPtrArray *array;
00842   GValue elt_val = {0, };
00843   GType elt_gtype;
00844   unsigned int i;
00845 
00846   array = val;
00847 
00848   elt_gtype = dbus_g_type_get_collection_specialization (type);
00849 
00850   for (i = 0; i < array->len; i++)
00851     {
00852       g_value_init (&elt_val, elt_gtype);
00853       gvalue_take_ptrarray_value (&elt_val, g_ptr_array_index (array, i));
00854       g_value_unset (&elt_val);
00855     }
00856 
00857   g_ptr_array_free (array, TRUE);
00858 }
00859 
00860 static gpointer
00861 slist_constructor (GType type)
00862 {
00863   return NULL;
00864 }
00865 
00866 static void
00867 slist_iterator (GType                                   list_type,
00868                 gpointer                                instance,
00869                 DBusGTypeSpecializedCollectionIterator  iterator,
00870                 gpointer                                user_data)
00871 {
00872   GSList *slist;
00873   GType elt_gtype;
00874 
00875   slist = instance;
00876 
00877   elt_gtype = dbus_g_type_get_collection_specialization (list_type);
00878 
00879   for (slist = instance; slist != NULL; slist = slist->next)
00880     {
00881       GValue val = {0, };
00882       g_value_init (&val, elt_gtype);
00883       gvalue_take_ptrarray_value (&val, slist->data);
00884       iterator (&val, user_data);
00885     }
00886 }
00887 
00888 static void
00889 slist_copy_elt (const GValue *val, gpointer user_data)
00890 {
00891   GSList **dest = user_data;
00892   GValue val_copy = {0, };
00893 
00894   g_value_init (&val_copy, G_VALUE_TYPE (val));
00895   g_value_copy (val, &val_copy);
00896 
00897   *dest = g_slist_append (*dest, ptrarray_value_from_gvalue (&val_copy));
00898 }
00899 
00900 static gpointer
00901 slist_copy (GType type, gpointer src)
00902 {
00903   GSList *new;
00904   GValue slist_val = {0, };
00905 
00906   g_value_init (&slist_val, type);
00907   g_value_set_static_boxed (&slist_val, src);
00908 
00909   new = slist_constructor (type);
00910   dbus_g_type_collection_value_iterate (&slist_val, slist_copy_elt, &new);
00911 
00912   return new;
00913 }
00914 
00915 static void
00916 slist_append (DBusGTypeSpecializedAppendContext *ctx, GValue *value)
00917 {
00918   GSList *list;
00919 
00920   list = g_value_get_boxed (ctx->val);
00921   list = g_slist_prepend (list, ptrarray_value_from_gvalue (value));
00922   g_value_set_static_boxed (ctx->val, list);
00923 }
00924 
00925 static void
00926 slist_end_append (DBusGTypeSpecializedAppendContext *ctx)
00927 {
00928   GSList *list;
00929 
00930   /* if you append multiple times to the slist, this will reverse the existing
00931    * elements... we need an init_append function */
00932   list = g_value_get_boxed (ctx->val);
00933   list = g_slist_reverse (list);
00934 
00935   g_value_take_boxed (ctx->val, list);
00936 }
00937 
00938 static void
00939 slist_free (GType type, gpointer val)
00940 {
00941   GSList *list;
00942   GType elt_gtype;
00943   list = val;
00944 
00945   elt_gtype = dbus_g_type_get_collection_specialization (type);
00946 
00947   while (list != NULL)
00948     {
00949       GValue elt_val = {0, };
00950       g_value_init (&elt_val, elt_gtype);
00951       gvalue_take_ptrarray_value (&elt_val, list->data);
00952       g_value_unset (&elt_val);
00953       list = g_slist_next(list);
00954     }
00955   list=val;
00956   g_slist_free (list);
00957 }
00958 
00959 void
00960 _dbus_g_type_specialized_builtins_init (void)
00961 {
00962   /* types with a simple_free function can be freed at run-time without
00963    * the destroy function needing to know the type, so they can be
00964    * stored in hash tables */
00965 
00966   static const DBusGTypeSpecializedCollectionVtable array_vtable = {
00967     {
00968       array_constructor,
00969       NULL,
00970       array_copy,
00971       array_simple_free,
00972       NULL,
00973       NULL,
00974     },
00975     array_fixed_accessor,
00976     NULL,
00977     NULL,
00978     NULL
00979   };
00980 
00981 
00982   static const DBusGTypeSpecializedCollectionVtable ptrarray_vtable = {
00983     {
00984       ptrarray_constructor,
00985       ptrarray_free,
00986       ptrarray_copy,
00987       NULL,
00988       NULL,
00989       NULL,
00990     },
00991     NULL,
00992     ptrarray_iterator,
00993     ptrarray_append,
00994     NULL,
00995   };
00996 
00997 
00998   static const DBusGTypeSpecializedCollectionVtable slist_vtable = {
00999     {
01000       slist_constructor,
01001       slist_free,
01002       slist_copy,
01003       NULL,
01004       NULL,
01005       NULL,
01006     },
01007     NULL,
01008     slist_iterator,
01009     slist_append,
01010     slist_end_append,
01011   };
01012 
01013   static const DBusGTypeSpecializedMapVtable hashtable_vtable = {
01014     {
01015       hashtable_constructor,
01016       NULL,
01017       hashtable_copy,
01018       hashtable_simple_free,
01019       NULL,
01020       NULL
01021     },
01022     hashtable_iterator,
01023     hashtable_append
01024   };
01025 
01026   static const DBusGTypeSpecializedStructVtable valuearray_vtable = {
01027     {
01028       valuearray_constructor,
01029       NULL,
01030       valuearray_copy,
01031       valuearray_simple_free,
01032       NULL,
01033       NULL
01034     },
01035     valuearray_get_member,
01036     valuearray_set_member
01037   };
01038 
01039   dbus_g_type_register_collection ("GSList", &slist_vtable, 0);
01040   dbus_g_type_register_collection ("GArray", &array_vtable, 0);
01041   dbus_g_type_register_collection ("GPtrArray", &ptrarray_vtable, 0);
01042   dbus_g_type_register_map ("GHashTable", &hashtable_vtable, 0);
01043   dbus_g_type_register_struct ("GValueArray", &valuearray_vtable, 0);
01044 }
01045 
01046 #ifdef DBUS_BUILD_TESTS
01047 
01048 typedef struct
01049 {
01050   gboolean seen_foo;
01051   gboolean seen_baz;
01052 } TestSpecializedHashData;
01053 
01054 static void
01055 test_specialized_hash (const GValue *key, const GValue *val, gpointer user_data)
01056 {
01057   TestSpecializedHashData *data = user_data;
01058 
01059   g_assert (G_VALUE_HOLDS_STRING (key));
01060   g_assert (G_VALUE_HOLDS_STRING (val));
01061 
01062   if (!strcmp (g_value_get_string (key), "foo"))
01063     {
01064       data->seen_foo = TRUE;
01065       g_assert (!strcmp (g_value_get_string (val), "bar"));
01066     }
01067   else if (!strcmp (g_value_get_string (key), "baz"))
01068     {
01069       data->seen_baz = TRUE;
01070       g_assert (!strcmp (g_value_get_string (val), "moo"));
01071     }
01072   else
01073     {
01074       g_assert_not_reached ();
01075     }
01076 }
01077 
01078 static void
01079 test_specialized_hash_2 (const GValue *key, const GValue *val, gpointer user_data)
01080 {
01081   TestSpecializedHashData *data = user_data;
01082   const GValue *realval;
01083 
01084   g_assert (G_VALUE_HOLDS_STRING (key));
01085   g_assert (G_VALUE_TYPE (val) == G_TYPE_VALUE);
01086 
01087   realval = g_value_get_boxed (val);
01088 
01089   if (!strcmp (g_value_get_string (key), "foo"))
01090     {
01091       data->seen_foo = TRUE;
01092       g_assert (G_VALUE_HOLDS_UINT (realval));
01093       g_assert (g_value_get_uint (realval) == 20);
01094     }
01095   else if (!strcmp (g_value_get_string (key), "baz"))
01096     {
01097       data->seen_baz = TRUE;
01098       g_assert (G_VALUE_HOLDS_STRING (realval));
01099       g_assert (!strcmp ("bar", g_value_get_string (realval)));
01100     }
01101   else
01102     {
01103       g_assert_not_reached ();
01104     }
01105 }
01106 
01107 gboolean
01108 _dbus_gvalue_utils_test (const char *datadir)
01109 {
01110   GType type;
01111 
01112   dbus_g_type_specialized_init ();
01113  _dbus_g_type_specialized_builtins_init ();
01114 
01115   type = dbus_g_type_get_collection ("GArray", G_TYPE_UINT);
01116   g_assert (dbus_g_type_is_collection (type));
01117   g_assert (dbus_g_type_get_collection_specialization (type) == G_TYPE_UINT);
01118   {
01119     GArray *instance;
01120 
01121     instance = dbus_g_type_specialized_construct (type);
01122 
01123     g_assert (instance->len == 0);
01124 
01125     g_array_free (instance, TRUE);
01126   }
01127 
01128   type = dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING);
01129   g_assert (dbus_g_type_is_map (type));
01130   g_assert (dbus_g_type_get_map_key_specialization (type) == G_TYPE_STRING);
01131   g_assert (dbus_g_type_get_map_value_specialization (type) == G_TYPE_STRING);
01132   {
01133     GHashTable *instance;
01134     GValue val = { 0, };
01135     TestSpecializedHashData hashdata;
01136 
01137     instance = dbus_g_type_specialized_construct (type);
01138 
01139     g_assert (g_hash_table_size (instance) == 0);
01140     g_hash_table_insert (instance, g_strdup ("foo"), g_strdup ("bar"));
01141     g_hash_table_insert (instance, g_strdup ("baz"), g_strdup ("moo"));
01142     g_assert (g_hash_table_size (instance) == 2);
01143 
01144     g_value_init (&val, type);
01145     g_value_set_boxed_take_ownership (&val, instance);
01146     hashdata.seen_foo = FALSE;
01147     hashdata.seen_baz = FALSE;
01148     dbus_g_type_map_value_iterate (&val,
01149                                    test_specialized_hash, 
01150                                    &hashdata);
01151     
01152     g_assert (hashdata.seen_foo);
01153     g_assert (hashdata.seen_baz);
01154 
01155     g_value_unset (&val);
01156   }
01157 
01158   type = dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE);
01159   g_assert (dbus_g_type_is_map (type));
01160   g_assert (dbus_g_type_get_map_key_specialization (type) == G_TYPE_STRING);
01161   g_assert (dbus_g_type_get_map_value_specialization (type) == G_TYPE_VALUE);
01162   {
01163     GHashTable *instance;
01164     GValue val = { 0, };
01165     TestSpecializedHashData hashdata;
01166     DBusGTypeSpecializedAppendContext ctx;
01167     GValue *eltval;
01168 
01169     instance = dbus_g_type_specialized_construct (type);
01170     g_value_init (&val, type);
01171     g_value_set_boxed_take_ownership (&val, instance);
01172 
01173     dbus_g_type_specialized_init_append (&val, &ctx);
01174 
01175     {
01176       GValue keyval = { 0, };
01177       GValue valval = { 0, };
01178       g_value_init (&keyval, G_TYPE_STRING);
01179       g_value_set_string (&keyval, "foo"); 
01180 
01181       g_value_init (&valval, G_TYPE_VALUE);
01182       eltval = g_new0 (GValue, 1);
01183       g_value_init (eltval, G_TYPE_UINT);
01184       g_value_set_uint (eltval, 20);
01185       g_value_set_boxed_take_ownership (&valval, eltval);
01186       dbus_g_type_specialized_map_append (&ctx, &keyval, &valval);
01187     }
01188 
01189     {
01190       GValue keyval = { 0, };
01191       GValue valval = { 0, };
01192       g_value_init (&keyval, G_TYPE_STRING);
01193       g_value_set_string (&keyval, "baz"); 
01194       g_value_init (&valval, G_TYPE_VALUE);
01195       eltval = g_new0 (GValue, 1);
01196       g_value_init (eltval, G_TYPE_STRING);
01197       g_value_set_string (eltval, "bar");
01198       g_value_set_boxed_take_ownership (&valval, eltval);
01199       dbus_g_type_specialized_map_append (&ctx, &keyval, &valval);
01200     }
01201 
01202     hashdata.seen_foo = FALSE;
01203     hashdata.seen_baz = FALSE;
01204     dbus_g_type_map_value_iterate (&val,
01205                                    test_specialized_hash_2, 
01206                                    &hashdata);
01207     
01208     g_assert (hashdata.seen_foo);
01209     g_assert (hashdata.seen_baz);
01210 
01211     g_value_unset (&val);
01212   }
01213 
01214   type = dbus_g_type_get_collection ("GSList", G_TYPE_OBJECT);
01215   g_assert (dbus_g_type_is_collection (type));
01216   g_assert (dbus_g_type_get_collection_specialization (type) == G_TYPE_OBJECT);
01217   {
01218     GSList *instance, *tmp, *copy;
01219     GValue val = {0, };
01220     GValue copyval = {0, };
01221     DBusGTypeSpecializedAppendContext ctx;
01222     GObject *objects[3];
01223     int i;
01224 
01225     instance = dbus_g_type_specialized_construct (type);
01226     g_assert (instance == NULL);
01227 
01228     g_value_init (&val, type);
01229     g_value_take_boxed (&val, instance);
01230 
01231     dbus_g_type_specialized_init_append (&val, &ctx);
01232 
01233     for (i = 0; i < 3; i++)
01234       {
01235         GValue eltval = { 0, };
01236         GObject *obj = g_object_new (G_TYPE_OBJECT, NULL);
01237 
01238         g_assert (obj != NULL);
01239         objects[i] = obj;
01240         g_object_add_weak_pointer (obj, (gpointer) (objects + i));
01241 
01242         g_value_init (&eltval, G_TYPE_OBJECT);
01243         g_value_take_object (&eltval, obj);
01244         dbus_g_type_specialized_collection_append (&ctx, &eltval);
01245       }
01246 
01247     dbus_g_type_specialized_collection_end_append (&ctx);
01248 
01249     instance = g_value_get_boxed (&val);
01250     g_assert (g_slist_length (instance) == 3);
01251 
01252     for (tmp = instance; tmp; tmp = tmp->next)
01253       {
01254         GObject *obj = tmp->data;
01255         g_assert (G_IS_OBJECT (obj));
01256         g_assert (obj->ref_count == 1);
01257       }
01258 
01259     g_value_init (&copyval, type);
01260     g_value_copy (&val, &copyval);
01261 
01262     copy = g_value_get_boxed (&copyval);
01263     g_assert (g_slist_length (copy) == 3);
01264 
01265     for (tmp = copy; tmp; tmp = tmp->next)
01266       {
01267         GObject *obj = tmp->data;
01268         g_assert (G_IS_OBJECT (obj));
01269         g_assert (obj->ref_count == 2);
01270       }
01271 
01272     g_value_unset (&copyval);
01273 
01274     for (i = 0; i < 3; i++)
01275       {
01276         g_assert (objects[i] != NULL);
01277       }
01278 
01279     for (tmp = instance; tmp; tmp = tmp->next)
01280       {
01281         GObject *obj = tmp->data;
01282         g_assert (G_IS_OBJECT (obj));
01283         g_assert (obj->ref_count == 1);
01284       }
01285 
01286     g_value_unset (&val);
01287 
01288     for (i = 0; i < 3; i++)
01289       {
01290         g_assert (objects[i] == NULL);
01291       }
01292   }
01293 
01294   type = dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING);
01295   g_assert (dbus_g_type_is_collection (type));
01296   g_assert (dbus_g_type_get_collection_specialization (type) == G_TYPE_STRING);
01297   {
01298     GPtrArray *instance;
01299     DBusGTypeSpecializedAppendContext ctx;
01300     GValue val = {0, };
01301     GValue eltval = {0, };
01302 
01303     instance = dbus_g_type_specialized_construct (type);
01304 
01305     g_assert (instance->len == 0);
01306 
01307     g_value_init (&val, type);
01308     g_value_set_boxed_take_ownership (&val, instance);
01309 
01310     dbus_g_type_specialized_init_append (&val, &ctx);
01311 
01312     g_value_init (&eltval, G_TYPE_STRING);
01313     g_value_set_static_string (&eltval, "foo");
01314     dbus_g_type_specialized_collection_append (&ctx, &eltval);
01315 
01316     g_value_reset (&eltval);
01317     g_value_set_static_string (&eltval, "bar");
01318     dbus_g_type_specialized_collection_append (&ctx, &eltval);
01319 
01320     g_value_reset (&eltval);
01321     g_value_set_static_string (&eltval, "baz");
01322     dbus_g_type_specialized_collection_append (&ctx, &eltval);
01323 
01324     dbus_g_type_specialized_collection_end_append (&ctx);
01325 
01326     g_assert (instance->len == 3);
01327 
01328     g_assert (!strcmp ("foo", g_ptr_array_index (instance, 0)));
01329     g_assert (!strcmp ("bar", g_ptr_array_index (instance, 1)));
01330     g_assert (!strcmp ("baz", g_ptr_array_index (instance, 2)));
01331 
01332     g_value_unset (&val);
01333   }
01334 
01335   type = dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_UINT, DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
01336   g_assert (dbus_g_type_is_struct (type));
01337   g_assert (dbus_g_type_get_struct_size (type) == 3);
01338   g_assert (dbus_g_type_get_struct_member_type (type, 0) == G_TYPE_STRING);
01339   g_assert (dbus_g_type_get_struct_member_type (type, 1) == G_TYPE_UINT);
01340   g_assert (dbus_g_type_get_struct_member_type (type, 2) == DBUS_TYPE_G_OBJECT_PATH);
01341   {
01342     GValueArray *instance;
01343     GValue val = {0, };
01344     GValue memval = {0, };
01345 
01346     instance = dbus_g_type_specialized_construct (type);
01347 
01348     g_assert (instance->n_values == 3);
01349 
01350     g_value_init (&val, type);
01351     g_value_set_boxed_take_ownership (&val, instance);
01352 
01353     g_value_init (&memval, G_TYPE_STRING);
01354     g_value_set_static_string (&memval, "foo");
01355     dbus_g_type_struct_set_member (&val, 0, &memval);
01356     g_value_unset (&memval);
01357 
01358     g_value_init (&memval, G_TYPE_UINT);
01359     g_value_set_uint (&memval, 42);
01360     dbus_g_type_struct_set_member (&val, 1, &memval);
01361     g_value_unset (&memval);
01362 
01363     g_value_init (&memval, DBUS_TYPE_G_OBJECT_PATH);
01364     g_value_set_static_boxed (&memval, "/bar/moo/foo/baz");
01365     dbus_g_type_struct_set_member (&val, 2, &memval);
01366     g_value_unset (&memval);
01367 
01368     g_assert (instance->n_values == 3);
01369 
01370     g_value_init (&memval, G_TYPE_STRING);
01371     dbus_g_type_struct_get_member (&val, 0, &memval);
01372     g_assert (0 == strcmp (g_value_get_string (&memval), "foo"));
01373     g_value_unset (&memval);
01374 
01375     g_value_init (&memval, G_TYPE_UINT);
01376     dbus_g_type_struct_get_member (&val, 1, &memval);
01377     g_assert (g_value_get_uint (&memval) == 42);
01378     g_value_unset (&memval);
01379 
01380     g_value_init (&memval, DBUS_TYPE_G_OBJECT_PATH);
01381     dbus_g_type_struct_get_member (&val, 2, &memval);
01382     g_assert (0 == strcmp ((gchar*) g_value_get_boxed (&memval),
01383                            "/bar/moo/foo/baz"));
01384     g_value_unset (&memval);
01385 
01386     g_value_unset (&val);
01387   }
01388 
01389   type = dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_UINT, DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
01390   g_assert (dbus_g_type_is_struct (type));
01391   g_assert (dbus_g_type_get_struct_size (type) == 3);
01392   g_assert (dbus_g_type_get_struct_member_type (type, 0) == G_TYPE_STRING);
01393   g_assert (dbus_g_type_get_struct_member_type (type, 1) == G_TYPE_UINT);
01394   g_assert (dbus_g_type_get_struct_member_type (type, 2) == DBUS_TYPE_G_OBJECT_PATH);
01395   {
01396     GValueArray *instance;
01397     GValue val = {0, };
01398 
01399     instance = dbus_g_type_specialized_construct (type);
01400 
01401     g_assert (instance->n_values == 3);
01402 
01403     g_value_init (&val, type);
01404     g_value_set_boxed_take_ownership (&val, instance);
01405 
01406     dbus_g_type_struct_set (&val,
01407                             0,"foo",
01408                             1, 42,
01409                             2, "/bar/moo/foo/baz",
01410                             G_MAXUINT);
01411 
01412     g_assert (instance->n_values == 3);
01413 
01414     {
01415       gchar *string;
01416       guint intval;
01417       gchar *path;
01418 
01419       dbus_g_type_struct_get (&val,
01420                               0, &string,
01421                               1, &intval,
01422                               2, &path,
01423                               G_MAXUINT);
01424 
01425       g_assert (0 == strcmp (string, "foo"));
01426       g_assert (intval == 42);
01427       g_assert (0 == strcmp (path, "/bar/moo/foo/baz"));
01428     }
01429 
01430     g_value_unset (&val);
01431   }
01432 
01433 
01434   return TRUE;
01435 }
01436 
01437 
01438 
01439 #endif /* DBUS_BUILD_TESTS */

Generated on Sat Dec 6 19:56:17 2008 for D-BUSGLibBindings by  doxygen 1.5.1