Main Page | Modules | Namespace List | Class Hierarchy | Data Structures | Directories | File List | Namespace Members | Data Fields | Related Pages

dbus-gvalue-utils.c

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

Generated on Tue Sep 13 01:28:06 2005 for D-BUS by  doxygen 1.4.4