dbus-gvalue-utils.c

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

Generated on Tue Jul 7 15:13:58 2009 for D-BUS by  doxygen 1.4.6