/* -*- mode: C; c-file-style: "gnu" -*- */ /* dbus-gtype-specialized.c: Non-DBus-specific functions for specialized GTypes * * Copyright (C) 2005 Red Hat, Inc. * Copyright (C) 2007 Codethink Ltd. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "dbus-gtype-specialized.h" #include #include #include /** * SECTION:dbus-gtype-specialized * @short_description: Specialized GTypes * @stability: Unstable * * Specialized gtypes are basically a way to allow the definition of * recursive GTypes. It allows the definition of 'containers' which is * basically a user defined structure capabale of holding other data and a * set of functions defining how to access that structure. Containers come in * 3 flavors: collections, maps and structs. * * A collection is a container that holds an ordered set of items, all * of which must be the same type. * * A map is a container that holds a set of key/value pairs. * The keys have one type, and the values another. * * A struct is a container that holds a fixed number of members, each member * having a predefined type. * * A specialization is a GType detailing a particular container with * particular types (a type specialization). * * Functions are provided for constructing and manipulating specializations. * * This documentation needs splitting into two pages, one for defining new * containers and using existing containers. I expect most users to only do * the latter. I also need to add some examples. */ typedef enum { DBUS_G_SPECTYPE_COLLECTION, DBUS_G_SPECTYPE_MAP, DBUS_G_SPECTYPE_STRUCT } DBusGTypeSpecializedType; typedef struct { DBusGTypeSpecializedType type; const DBusGTypeSpecializedVtable *vtable; } DBusGTypeSpecializedContainer; typedef struct { guint num_types; GType *types; const DBusGTypeSpecializedContainer *klass; } DBusGTypeSpecializedData; static GHashTable /* char * -> data* */ *specialized_containers; static GQuark specialized_type_data_quark () { static GQuark quark; if (!quark) quark = g_quark_from_static_string ("DBusGTypeSpecializedData"); return quark; } void dbus_g_type_specialized_init (void) { specialized_containers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); } static gboolean specialized_types_is_initialized (void) { return specialized_containers != NULL; } static DBusGTypeSpecializedData * lookup_specialization_data (GType type) { return g_type_get_qdata (type, specialized_type_data_quark ()); } /* Copied from gboxed.c */ static void proxy_value_init (GValue *value) { value->data[0].v_pointer = NULL; } /* Adapted from gboxed.c */ static void proxy_value_free (GValue *value) { if (value->data[0].v_pointer && !(value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS)) { DBusGTypeSpecializedData *data; GType type; type = G_VALUE_TYPE (value); data = lookup_specialization_data (type); g_assert (data != NULL); if (data->klass->vtable->free_func) { data->klass->vtable->free_func (type, value->data[0].v_pointer); } else { g_assert (data->klass->vtable->simple_free_func != NULL); data->klass->vtable->simple_free_func (value->data[0].v_pointer); } } } /* Adapted from gboxed.c */ static void proxy_value_copy (const GValue *src_value, GValue *dest_value) { if (src_value->data[0].v_pointer) { DBusGTypeSpecializedData *data; GType type; type = G_VALUE_TYPE (src_value); data = lookup_specialization_data (type); g_assert (data != NULL); dest_value->data[0].v_pointer = data->klass->vtable->copy_func (type, src_value->data[0].v_pointer); } else dest_value->data[0].v_pointer = src_value->data[0].v_pointer; } /* Copied from gboxed.c */ static gpointer proxy_value_peek_pointer (const GValue *value) { return value->data[0].v_pointer; } /* Adapted from gboxed.c */ static gchar* proxy_collect_value (GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags) { DBusGTypeSpecializedData *data; GType type; type = G_VALUE_TYPE (value); data = lookup_specialization_data (type); if (!collect_values[0].v_pointer) value->data[0].v_pointer = NULL; else { if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { value->data[0].v_pointer = collect_values[0].v_pointer; value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS; } else { value->data[0].v_pointer = data->klass->vtable->copy_func (type, collect_values[0].v_pointer); } } return NULL; } /* Adapted from gboxed.c */ static gchar* proxy_lcopy_value (const GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags) { gpointer *boxed_p = collect_values[0].v_pointer; if (!boxed_p) return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); if (!value->data[0].v_pointer) *boxed_p = NULL; else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) *boxed_p = value->data[0].v_pointer; else { DBusGTypeSpecializedData *data; GType type; type = G_VALUE_TYPE (value); data = lookup_specialization_data (type); *boxed_p = data->klass->vtable->copy_func (type, value->data[0].v_pointer); } return NULL; } static char * build_specialization_name (const char *prefix, guint num_types, const GType *types) { GString *fullname; guint i; fullname = g_string_new (prefix); g_string_append_c (fullname, '_'); for (i=0; i < num_types; i++) { if (i!=0) g_string_append_c (fullname, '+'); g_string_append (fullname, g_type_name (types[i])); } g_string_append_c (fullname, '_'); return g_string_free (fullname, FALSE); } static void register_container (const char *name, DBusGTypeSpecializedType type, const DBusGTypeSpecializedVtable *vtable) { DBusGTypeSpecializedContainer *klass; klass = g_new0 (DBusGTypeSpecializedContainer, 1); klass->type = type; klass->vtable = vtable; g_hash_table_insert (specialized_containers, g_strdup (name), klass); } /** * dbus_g_type_register_collection: * @name: The name of a new collection container * @vtable: the vtable defining the new container * @flags: As yet unused. * * Defines a new collection container. */ void dbus_g_type_register_collection (const char *name, const DBusGTypeSpecializedCollectionVtable *vtable, guint flags) { g_return_if_fail (specialized_types_is_initialized ()); register_container (name, DBUS_G_SPECTYPE_COLLECTION, (const DBusGTypeSpecializedVtable*) vtable); } /** * dbus_g_type_register_map: * @name: The name of a new map container * @vtable: the vtable defining the new container * @flags: As yet unused. * * Defines a new map container. */ void dbus_g_type_register_map (const char *name, const DBusGTypeSpecializedMapVtable *vtable, guint flags) { g_return_if_fail (specialized_types_is_initialized ()); register_container (name, DBUS_G_SPECTYPE_MAP, (const DBusGTypeSpecializedVtable*) vtable); } /** * dbus_g_type_register_struct: * @name: The name of a new struct container * @vtable: the vtable defining the new container * @flags: As yet unused. * * Defines a new struct container. */ void dbus_g_type_register_struct (const char *name, const DBusGTypeSpecializedStructVtable *vtable, guint flags) { g_return_if_fail (specialized_types_is_initialized ()); register_container (name, DBUS_G_SPECTYPE_STRUCT, (const DBusGTypeSpecializedVtable*) vtable); } /** * dbus_g_type_map_peek_vtable: * @map_type: a gtype of a map specialization * * Peek the vtable for a given map specialization */ const DBusGTypeSpecializedMapVtable* dbus_g_type_map_peek_vtable (GType map_type) { DBusGTypeSpecializedData *data; g_return_val_if_fail (dbus_g_type_is_map(map_type), NULL); data = lookup_specialization_data (map_type); g_assert (data != NULL); return (DBusGTypeSpecializedMapVtable *)(data->klass->vtable); } /** * dbus_g_type_collection_peek_vtable: * @collection_type: a gtype of a collection specialization * * Peek the vtable for a given collection specialization */ const DBusGTypeSpecializedCollectionVtable* dbus_g_type_collection_peek_vtable (GType collection_type) { DBusGTypeSpecializedData *data; g_return_val_if_fail (dbus_g_type_is_collection(collection_type), NULL); data = lookup_specialization_data (collection_type); g_assert (data != NULL); return (DBusGTypeSpecializedCollectionVtable *)(data->klass->vtable); } /** * dbus_g_type_struct_peek_vtable: * @collection_type: a gtype of a struct specialization * * Peek the vtable for a given struct specialization */ const DBusGTypeSpecializedStructVtable* dbus_g_type_struct_peek_vtable (GType struct_type) { DBusGTypeSpecializedData *data; g_return_val_if_fail (dbus_g_type_is_struct (struct_type), NULL); data = lookup_specialization_data (struct_type); g_assert (data != NULL); return (DBusGTypeSpecializedStructVtable *)(data->klass->vtable); } static GType register_specialized_instance (const DBusGTypeSpecializedContainer *klass, const char *name, guint num_types, const GType *types) { GType ret; static const GTypeValueTable vtable = { proxy_value_init, proxy_value_free, proxy_value_copy, proxy_value_peek_pointer, "p", proxy_collect_value, "p", proxy_lcopy_value, }; static const GTypeInfo derived_info = { 0, /* class_size */ NULL, /* base_init */ NULL, /* base_finalize */ NULL, /* class_init */ NULL, /* class_finalize */ NULL, /* class_data */ 0, /* instance_size */ 0, /* n_preallocs */ NULL, /* instance_init */ &vtable, /* value_table */ }; ret = g_type_register_static (G_TYPE_BOXED, name, &derived_info, 0); /* install proxy functions upon successfull registration */ if (ret != G_TYPE_INVALID) { DBusGTypeSpecializedData *data; data = g_new0 (DBusGTypeSpecializedData, 1); data->num_types = num_types; data->types = g_memdup (types, sizeof (GType) * num_types); data->klass = klass; g_type_set_qdata (ret, specialized_type_data_quark (), data); } return ret; } static GType lookup_or_register_specialized (const char *container, guint num_types, const GType *types) { GType ret; char *name; const DBusGTypeSpecializedContainer *klass; g_return_val_if_fail (specialized_types_is_initialized (), G_TYPE_INVALID); klass = g_hash_table_lookup (specialized_containers, container); g_return_val_if_fail (klass != NULL, G_TYPE_INVALID); name = build_specialization_name (container, num_types, types); ret = g_type_from_name (name); if (ret == G_TYPE_INVALID) { /* Take ownership of name */ ret = register_specialized_instance (klass, name, num_types, types); } g_free (name); return ret; } /** * dbus_g_type_get_collection: * @container: a string specifying a registered collection type * @specialization: #GType of collection elements * * Gets a #GType for a particular collection instance, * creating the type if not already created. * * Returns: the #GType of that instance */ GType dbus_g_type_get_collection (const char *container, GType specialization) { return lookup_or_register_specialized (container, 1, &specialization); } /** * dbus_g_type_get_map: * @container: a string specifying a registered map type * @key_specialization: #GType of keys * @value_specialization: #GType of values * * Gets a #GType for a particular map instance, * creating the type if not already created. * * Returns: the #GType of that instance */ GType dbus_g_type_get_map (const char *container, GType key_specialization, GType value_specialization) { GType types[2] = {key_specialization, value_specialization}; return lookup_or_register_specialized (container, 2, types); } /** * dbus_g_type_get_structv: * @container: a string specifying a registered struct type * @num_members: number of members in the struct * @types: an array specufying a GType for each struct element * * Gets a #GType for a particular struct instance, * creating the type if not already created. * * Returns: the #GType of that instance */ GType dbus_g_type_get_structv (const char *container, guint num_members, GType *types) { return lookup_or_register_specialized (container, num_members, types); } /** * dbus_g_type_get_struct: * @container: a string specifying a registered struct type * @first_type: #GType for the struct's first member * @...: more GTypes for the struct's members, terminated by G_TYPE_INVALID * * Varags methsod to get a #GType for a particular struct instance, * creating the type if not already created. * * Returns: the #GType of that instance */ GType dbus_g_type_get_struct (const char *container, GType first_type, ...) { GArray *types; GType curtype, ret; va_list args; va_start (args, first_type); types = g_array_new (FALSE, FALSE, sizeof (GType)); curtype = first_type; while (curtype != G_TYPE_INVALID) { g_array_append_val (types, curtype); curtype = va_arg (args, GType); } va_end (args); ret = lookup_or_register_specialized (container, types->len, (GType *) types->data); g_array_free (types, TRUE); return ret; } /** * dbus_g_type_is_collection: * @gtype: a GType to test * * Tests if a given GType is a collection. * * Returns: true if the given GType is a collection */ gboolean dbus_g_type_is_collection (GType gtype) { DBusGTypeSpecializedData *data; data = lookup_specialization_data (gtype); if (data == NULL) return FALSE; return data->klass->type == DBUS_G_SPECTYPE_COLLECTION; } /** * dbus_g_type_is_map: * @gtype: a GType to test * * Tests if a given GType is a map, * i.e. it was created with #dbus_g_type_get_map. * * Returns: true if the given GType is a map */ gboolean dbus_g_type_is_map (GType gtype) { DBusGTypeSpecializedData *data; data = lookup_specialization_data (gtype); if (data == NULL) return FALSE; return data->klass->type == DBUS_G_SPECTYPE_MAP; } /** * dbus_g_type_is_struct: * @gtype: a GType to test * * Tests if a given GType is a struct, * i.e. it was created with #dbus_g_type_get_struct * * Returns: true if the given GType is a struct */ gboolean dbus_g_type_is_struct (GType gtype) { DBusGTypeSpecializedData *data; data = lookup_specialization_data (gtype); if (data == NULL) return FALSE; return data->klass->type == DBUS_G_SPECTYPE_STRUCT; } static GType get_specialization_index (GType gtype, guint i) { DBusGTypeSpecializedData *data; data = lookup_specialization_data (gtype); if (i < data->num_types) return data->types[i]; else return G_TYPE_INVALID; } /** * dbus_g_type_get_collection_specialization: * @gtype: a collection GType, as created by #dbus_g_type_get_collection. * * Returns: the element type for a given collection GType. * Returns G_TYPE_INVALID if not a collection GType */ GType dbus_g_type_get_collection_specialization (GType gtype) { g_return_val_if_fail (dbus_g_type_is_collection (gtype), G_TYPE_INVALID); return get_specialization_index (gtype, 0); } /** * dbus_g_type_get_map_key_specialization: * @gtype: a map GType, as created by #dbus_g_type_get_map. * * Returns: the key type for a given map GType. * Returns G_TYPE_INVALID if not a map GType */ GType dbus_g_type_get_map_key_specialization (GType gtype) { g_return_val_if_fail (dbus_g_type_is_map (gtype), G_TYPE_INVALID); return get_specialization_index (gtype, 0); } /** * dbus_g_type_get_map_value_specialization: * @gtype: a map GType, as created by #dbus_g_type_get_map. * * Returns: the value type for a given map GType. * Returns G_TYPE_INVALID if not a map GType */ GType dbus_g_type_get_map_value_specialization (GType gtype) { g_return_val_if_fail (dbus_g_type_is_map (gtype), G_TYPE_INVALID); return get_specialization_index (gtype, 1); } /** * dbus_g_type_get_struct_member_type * @gtype: a struct GType, as created with #dbus_g_type_get_struct * @member: the index of a struct member * * Returns: the type for a given member of a struct #GType. * Returns G_TYPE_INVALID if not a struct GType */ GType dbus_g_type_get_struct_member_type (GType gtype, guint member) { g_return_val_if_fail (dbus_g_type_is_struct (gtype), G_TYPE_INVALID); return get_specialization_index (gtype, member); } /** * dbus_g_type_get_struct_size * @gtype: a struct GType, as created with #dbus_g_type_get_struct. * * Returns: the number of members in a given struct #GType. * Returns G_TYPE_INVALID if not a struct GType */ guint dbus_g_type_get_struct_size (GType gtype) { DBusGTypeSpecializedData *data; g_return_val_if_fail (dbus_g_type_is_struct (gtype), G_TYPE_INVALID); data = lookup_specialization_data (gtype); return data->num_types; } /** * dbus_g_type_specialized_construct: * @gtype: a specialized #GType, as created by #dbus_g_type_get_collection, #dbus_g_type_get_map or #dbus_g_type_get_struct. * * Create an instance of a given specialized type. * The structure created and returned will depend on the container type of the * GType. E.g. If the given type was created by * dbus_g_type_get_collection("GArray", G_TYPE_INT), * then this will return a GArray with element_size of sizeof(int) * * Returns: a pointer to a newly constructed instance of the given type. */ gpointer dbus_g_type_specialized_construct (GType gtype) { DBusGTypeSpecializedData *data; g_return_val_if_fail (specialized_types_is_initialized (), FALSE); data = lookup_specialization_data (gtype); g_return_val_if_fail (data != NULL, FALSE); return data->klass->vtable->constructor (gtype); } /** * dbus_g_type_collection_get_fixed: * @deprecated: maybe? * * if the collection has elements of fixed size (i.e. a fundamental type), * return the contents of the array. * Its pretty obscure and I don't think anyone uses it. */ gboolean dbus_g_type_collection_get_fixed (GValue *value, gpointer *data_ret, guint *len_ret) { DBusGTypeSpecializedData *data; GType gtype; g_return_val_if_fail (specialized_types_is_initialized (), FALSE); g_return_val_if_fail (G_VALUE_HOLDS_BOXED (value), FALSE); gtype = G_VALUE_TYPE (value); data = lookup_specialization_data (gtype); g_return_val_if_fail (data != NULL, FALSE); return ((DBusGTypeSpecializedCollectionVtable *) (data->klass->vtable))->fixed_accessor (gtype, g_value_get_boxed (value), data_ret, len_ret); } /** * dbus_g_type_collection_value_iterate: * @value: a #GValue holding a collection type. * @iterator: a function to call for each element * @user_data: user data to pass to the @iterator * * Calls the given function for each element of the collection. * The function is passed a #GValue containing the element and the given * @user_data parameter. The collection may not be modified while iterating over * it. */ void dbus_g_type_collection_value_iterate (const GValue *value, DBusGTypeSpecializedCollectionIterator iterator, gpointer user_data) { DBusGTypeSpecializedData *data; GType gtype; g_return_if_fail (specialized_types_is_initialized ()); g_return_if_fail (G_VALUE_HOLDS_BOXED (value)); gtype = G_VALUE_TYPE (value); data = lookup_specialization_data (gtype); g_return_if_fail (data != NULL); ((DBusGTypeSpecializedCollectionVtable *) data->klass->vtable)->iterator (gtype, g_value_get_boxed (value), iterator, user_data); } typedef struct { GValue *val; GType specialization_type; DBusGTypeSpecializedData *specdata; } DBusGTypeSpecializedAppendContextReal; /** * dbus_g_type_specialized_init_append: * @value: a #GValue containing an instance of specialized type * @ctx: a #DBusGTypeSpecializedAppendContext in which to return a new appending context. * @deprecated: maybe i'll deprecate this as its a bit wank. * * Create a new context for adding elements to a collection or key/value pairs * to a map. You generally don't need or want to use this.. */ void dbus_g_type_specialized_init_append (GValue *value, DBusGTypeSpecializedAppendContext *ctx) { DBusGTypeSpecializedAppendContextReal *realctx = (DBusGTypeSpecializedAppendContextReal *) ctx; GType gtype; DBusGTypeSpecializedData *specdata; g_return_if_fail (specialized_types_is_initialized ()); g_return_if_fail (G_VALUE_HOLDS_BOXED (value)); gtype = G_VALUE_TYPE (value); specdata = lookup_specialization_data (gtype); g_return_if_fail (specdata != NULL); g_return_if_fail (specdata->num_types != 0); realctx->val = value; realctx->specialization_type = specdata->types[0]; realctx->specdata = specdata; } /** * dbus_g_type_specialized_collection_append: * @ctx: a context created by #dbus_g_type_specialized_init_append * @elt: a GValue containing an element to append to the collection. * @deprecated: maybe i'll deprecate this as its a bit wank. * * Appends a given element to the end of a collection. */ void dbus_g_type_specialized_collection_append (DBusGTypeSpecializedAppendContext *ctx, GValue *elt) { DBusGTypeSpecializedAppendContextReal *realctx = (DBusGTypeSpecializedAppendContextReal *) ctx; ((DBusGTypeSpecializedCollectionVtable *) realctx->specdata->klass->vtable)->append_func (ctx, elt); } /** * dbus_g_type_specialized_collection_end_append: * @ctx: a context created by #dbus_g_type_specialized_init_append * @deprecated: maybe i'll deprecate this as its a bit wank. * * Finish appending elements to a given collection */ void dbus_g_type_specialized_collection_end_append (DBusGTypeSpecializedAppendContext *ctx) { DBusGTypeSpecializedAppendContextReal *realctx = (DBusGTypeSpecializedAppendContextReal *) ctx; if (((DBusGTypeSpecializedCollectionVtable *) realctx->specdata->klass->vtable)->end_append_func != NULL) ((DBusGTypeSpecializedCollectionVtable *) realctx->specdata->klass->vtable)->end_append_func (ctx); } /** * dbus_g_type_specialized_map_append: * @ctx: a context created by #dbus_g_type_specialized_init_append * @key: a GValue containing a key * @val: a GValue containing a value * @deprecated: maybe i'll deprecate this as its a bit wank. * * Inserts the given key/value pair into the map instance. */ void dbus_g_type_specialized_map_append (DBusGTypeSpecializedAppendContext *ctx, GValue *key, GValue *val) { DBusGTypeSpecializedAppendContextReal *realctx = (DBusGTypeSpecializedAppendContextReal *) ctx; ((DBusGTypeSpecializedMapVtable *) realctx->specdata->klass->vtable)->append_func (ctx, key, val); } /** * dbus_g_type_map_value_iterate: * @value: a #GValue holding a collection type. * @iterator: a function to call for each element * @user_data: user data to pass to the @iterator * * Calls the given function for each key/value pair of the map. * The function is passed two GValues containing the key/value pair and the given * @user_data parameter. The map may not be modified while iterating over * it. */ void dbus_g_type_map_value_iterate (const GValue *value, DBusGTypeSpecializedMapIterator iterator, gpointer user_data) { DBusGTypeSpecializedData *data; GType gtype; g_return_if_fail (specialized_types_is_initialized ()); g_return_if_fail (G_VALUE_HOLDS_BOXED (value)); gtype = G_VALUE_TYPE (value); data = lookup_specialization_data (gtype); g_return_if_fail (data != NULL); ((DBusGTypeSpecializedMapVtable *) data->klass->vtable)->iterator (gtype, g_value_get_boxed (value), iterator, user_data); } /** * dbus_g_type_struct_get_member: * @value: a #GValue containing a struct instance * @member: the index of a given member * @dest: an initialised #GValue in which to return the struct member * * Fetches a given member of a given struct instance. @dest must be initialised * was the correct type for that member, e.g. as returned by * @dbus_g_type_get_struct_member_type * * Returns: TRUE if sucessful */ gboolean dbus_g_type_struct_get_member (const GValue *value, guint member, GValue *dest) { DBusGTypeSpecializedData *data; GType gtype; g_return_val_if_fail (specialized_types_is_initialized (), FALSE); g_return_val_if_fail (G_VALUE_HOLDS_BOXED (value), FALSE); gtype = G_VALUE_TYPE (value); data = lookup_specialization_data (gtype); g_return_val_if_fail (data != NULL, FALSE); return ((DBusGTypeSpecializedStructVtable *) (data->klass->vtable))->get_member(gtype, g_value_get_boxed (value), member, dest); } /** * dbus_g_type_struct_set_member: * @value: a #GValue containing a struct instance * @member: the index of a given member * @src: an #GValue containing the new value for that struct member * * Sets a given member of a struct to a new value. The type of @src must match * the exiting type of @member member of the struct. * * Returns: TRUE if sucessful */ gboolean dbus_g_type_struct_set_member (GValue *value, guint member, const GValue *src) { DBusGTypeSpecializedData *data; GType gtype; g_return_val_if_fail (specialized_types_is_initialized (), FALSE); g_return_val_if_fail (G_VALUE_HOLDS_BOXED (value), FALSE); gtype = G_VALUE_TYPE (value); data = lookup_specialization_data (gtype); g_return_val_if_fail (data != NULL, FALSE); return ((DBusGTypeSpecializedStructVtable *) (data->klass->vtable))->set_member(gtype, g_value_get_boxed (value), member, src); } /** * dbus_g_type_struct_get: * @value: a #GValue containing a #DBusGTypeStruct type * @member: struct member to get * @...: location in which to return the value of this member, * followed optionally by more member/return locations pairs, followed by * by #G_MAXUINT * * Collects the selected values of this struct into the return locations * provided. * * Returns: #FALSE on failure */ gboolean dbus_g_type_struct_get (const GValue *value, guint first_member, ...) { va_list var_args; GType type; guint size,i; gchar *error; GValue val = {0,}; g_return_val_if_fail (dbus_g_type_is_struct (G_VALUE_TYPE (value)), FALSE); va_start (var_args, first_member); size = dbus_g_type_get_struct_size (G_VALUE_TYPE (value)); i = first_member; while (i != G_MAXUINT) { if (i >= size) goto error; type = dbus_g_type_get_struct_member_type (G_VALUE_TYPE (value),i); g_value_init (&val, type); dbus_g_type_struct_get_member (value, i, &val); G_VALUE_LCOPY (&val, var_args, 0, &error); if (error) { g_warning ("%s, %s", G_STRFUNC, error); g_free (error); g_value_unset (&val); goto error; } g_value_unset (&val); i = va_arg (var_args, guint); } va_end (var_args); return TRUE; error: va_end (var_args); return FALSE; } /** * dbus_g_type_struct_set: * @value: a #GValue containing a #DBusGTypeStruct type * @member: struct member to set * @...: value for the first member, followed optionally by * more member/value pairs, followed by #G_MAXUINT * * Sets the selected members of the struct in @value. * * Returns: #FALSE on failure */ gboolean dbus_g_type_struct_set (GValue *value, guint first_member, ...) { va_list var_args; GType type; guint size,i; gchar *error; GValue val = {0,}; g_return_val_if_fail (dbus_g_type_is_struct (G_VALUE_TYPE (value)), FALSE); va_start (var_args, first_member); size = dbus_g_type_get_struct_size (G_VALUE_TYPE (value)); i = first_member; while (i != G_MAXUINT) { if (i >= size) goto error; type = dbus_g_type_get_struct_member_type (G_VALUE_TYPE (value),i); g_value_init (&val, type); G_VALUE_COLLECT (&val, var_args, 0, &error); if (error) { g_warning ("%s, %s", G_STRFUNC, error); g_free (error); g_value_unset (&val); goto error; } dbus_g_type_struct_set_member (value, i, &val); g_value_unset (&val); i = va_arg (var_args, guint); } va_end (var_args); return TRUE; error: va_end (var_args); return FALSE; }