Merge branch 'ebassi/type-table-docs' into 'main'

Allow proper introspection of GTypeValueTable

See merge request GNOME/glib!3441
This commit is contained in:
Emmanuele Bassi 2023-05-30 23:26:54 +00:00
commit e8440ddcf9
2 changed files with 279 additions and 161 deletions

View File

@ -25,6 +25,12 @@ GTypeClass
GTypeInfo GTypeInfo
GTypeFundamentalInfo GTypeFundamentalInfo
GInterfaceInfo GInterfaceInfo
GTypeValueInitFunc
GTypeValueFreeFunc
GTypeValueCopyFunc
GTypeValuePeekPointerFunc
GTypeValueCollectFunc
GTypeValueLCopyFunc
GTypeValueTable GTypeValueTable
G_TYPE_FROM_INSTANCE G_TYPE_FROM_INSTANCE
G_TYPE_FROM_CLASS G_TYPE_FROM_CLASS

View File

@ -1164,75 +1164,124 @@ struct _GInterfaceInfo
GInterfaceFinalizeFunc interface_finalize; GInterfaceFinalizeFunc interface_finalize;
gpointer interface_data; gpointer interface_data;
}; };
/** /**
* GTypeValueTable: * GTypeValueInitFunc:
* @value_init: Default initialize @values contents by poking values * @value: the value to initialize
* directly into the value->data array. The data array of *
* the #GValue passed into this function was zero-filled * Initializes the value contents by setting the fields of the `value->data`
* with `memset()`, so no care has to be taken to free any * array.
* old contents. E.g. for the implementation of a string *
* value that may never be %NULL, the implementation might * The data array of the #GValue passed into this function was zero-filled
* look like: * with `memset()`, so no care has to be taken to free any old contents.
* For example, in the case of a string value that may never be %NULL, the
* implementation might look like:
*
* |[<!-- language="C" --> * |[<!-- language="C" -->
* value->data[0].v_pointer = g_strdup (""); * value->data[0].v_pointer = g_strdup ("");
* ]| * ]|
* @value_free: Free any old contents that might be left in the *
* data array of the passed in @value. No resources may * Since: 2.78
* remain allocated through the #GValue contents after */
* this function returns. E.g. for our above string type: GOBJECT_AVAILABLE_TYPE_IN_2_78
typedef void (* GTypeValueInitFunc) (GValue *value);
/**
* GTypeValueFreeFunc:
* @value: the value to free
*
* Frees any old contents that might be left in the `value->data` array of
* the given value.
*
* No resources may remain allocated through the #GValue contents after this
* function returns. E.g. for our above string type:
*
* |[<!-- language="C" --> * |[<!-- language="C" -->
* // only free strings without a specific flag for static storage * // only free strings without a specific flag for static storage
* if (!(value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS)) * if (!(value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS))
* g_free (value->data[0].v_pointer); * g_free (value->data[0].v_pointer);
* ]| * ]|
* @value_copy: @dest_value is a #GValue with zero-filled data section *
* and @src_value is a properly setup #GValue of same or * Since: 2.78
* derived type. */
* The purpose of this function is to copy the contents of GOBJECT_AVAILABLE_TYPE_IN_2_78
* @src_value into @dest_value in a way, that even after typedef void (* GTypeValueFreeFunc) (GValue *value);
* @src_value has been freed, the contents of @dest_value
* remain valid. String type example: /**
* GTypeValueCopyFunc:
* @src_value: the value to copy
* @dest_value: (out): the location of the copy
*
* Copies the content of a #GValue into another.
*
* The @dest_value is a #GValue with zero-filled data section and @src_value
* is a properly initialized #GValue of same type, or derived type.
*
* The purpose of this function is to copy the contents of @src_value
* into @dest_value in a way, that even after @src_value has been freed, the
* contents of @dest_value remain valid. String type example:
*
* |[<!-- language="C" --> * |[<!-- language="C" -->
* dest_value->data[0].v_pointer = g_strdup (src_value->data[0].v_pointer); * dest_value->data[0].v_pointer = g_strdup (src_value->data[0].v_pointer);
* ]| * ]|
* @value_peek_pointer: If the value contents fit into a pointer, such as objects *
* or strings, return this pointer, so the caller can peek at * Since: 2.78
* the current contents. To extend on our above string example: */
GOBJECT_AVAILABLE_TYPE_IN_2_78
typedef void (* GTypeValueCopyFunc) (const GValue *src_value,
GValue *dest_value);
/**
* GTypeValuePeekPointerFunc:
* @value: the value to peek
*
* If the value contents fit into a pointer, such as objects or strings,
* return this pointer, so the caller can peek at the current contents.
*
* To extend on our above string example:
*
* |[<!-- language="C" --> * |[<!-- language="C" -->
* return value->data[0].v_pointer; * return value->data[0].v_pointer;
* ]| * ]|
* @collect_format: A string format describing how to collect the contents of *
* this value bit-by-bit. Each character in the format represents * Returns: (transfer none): a pointer to the value contents
* an argument to be collected, and the characters themselves indicate *
* the type of the argument. Currently supported arguments are: * Since: 2.78
* - 'i' - Integers. passed as collect_values[].v_int. */
* - 'l' - Longs. passed as collect_values[].v_long. GOBJECT_AVAILABLE_TYPE_IN_2_78
* - 'd' - Doubles. passed as collect_values[].v_double. typedef gpointer (* GTypeValuePeekPointerFunc) (const GValue *value);
* - 'p' - Pointers. passed as collect_values[].v_pointer.
* It should be noted that for variable argument list construction, /**
* ANSI C promotes every type smaller than an integer to an int, and * GTypeValueCollectFunc:
* floats to doubles. So for collection of short int or char, 'i' * @value: the value to initialize
* needs to be used, and for collection of floats 'd'. * @n_collect_values: the number of collected values
* @collect_value: The collect_value() function is responsible for converting the * @collect_values: (array length=n_collect_values): the collected values
* values collected from a variable argument list into contents * @collect_flags: optional flags
* suitable for storage in a GValue. This function should setup *
* @value similar to value_init(); e.g. for a string value that * This function is responsible for converting the values collected from
* does not allow %NULL pointers, it needs to either spew an error, * a variadic argument list into contents suitable for storage in a #GValue.
* or do an implicit conversion by storing an empty string. *
* The @value passed in to this function has a zero-filled data * This function should setup @value similar to #GTypeValueInitFunc; e.g.
* array, so just like for value_init() it is guaranteed to not * for a string value that does not allow `NULL` pointers, it needs to either
* contain any old contents that might need freeing. * emit an error, or do an implicit conversion by storing an empty string.
* @n_collect_values is exactly the string length of @collect_format, *
* and @collect_values is an array of unions #GTypeCValue with * The @value passed in to this function has a zero-filled data array, so
* length @n_collect_values, containing the collected values * just like for #GTypeValueInitFunc it is guaranteed to not contain any old
* according to @collect_format. * contents that might need freeing.
* @collect_flags is an argument provided as a hint by the caller. *
* It may contain the flag %G_VALUE_NOCOPY_CONTENTS indicating, * The @n_collect_values argument is the string length of the `collect_format`
* that the collected value contents may be considered "static" * field of #GTypeValueTable, and `collect_values` is an array of #GTypeCValue
* for the duration of the @value lifetime. * with length of @n_collect_values, containing the collected values according
* Thus an extra copy of the contents stored in @collect_values is * to `collect_format`.
*
* The @collect_flags argument provided as a hint by the caller. It may
* contain the flag %G_VALUE_NOCOPY_CONTENTS indicating that the collected
* value contents may be considered static for the duration of the @value
* lifetime. Thus an extra copy of the contents stored in @collect_values is
* not required for assignment to @value. * not required for assignment to @value.
*
* For our above string example, we continue with: * For our above string example, we continue with:
*
* |[<!-- language="C" --> * |[<!-- language="C" -->
* if (!collect_values[0].v_pointer) * if (!collect_values[0].v_pointer)
* value->data[0].v_pointer = g_strdup (""); * value->data[0].v_pointer = g_strdup ("");
@ -1246,97 +1295,160 @@ struct _GInterfaceInfo
* value->data[0].v_pointer = g_strdup (collect_values[0].v_pointer); * value->data[0].v_pointer = g_strdup (collect_values[0].v_pointer);
* return NULL; * return NULL;
* ]| * ]|
*
* It should be noted, that it is generally a bad idea to follow the * It should be noted, that it is generally a bad idea to follow the
* %G_VALUE_NOCOPY_CONTENTS hint for reference counted types. Due to * %G_VALUE_NOCOPY_CONTENTS hint for reference counted types. Due to
* reentrancy requirements and reference count assertions performed * reentrancy requirements and reference count assertions performed
* by the signal emission code, reference counts should always be * by the signal emission code, reference counts should always be
* incremented for reference counted contents stored in the value->data * incremented for reference counted contents stored in the `value->data`
* array. To deviate from our string example for a moment, and taking * array. To deviate from our string example for a moment, and taking
* a look at an exemplary implementation for collect_value() of * a look at an exemplary implementation for `GTypeValueTable.collect_value()`
* #GObject: * of `GObject`:
*
* |[<!-- language="C" --> * |[<!-- language="C" -->
* GObject *object = G_OBJECT (collect_values[0].v_pointer); * GObject *object = G_OBJECT (collect_values[0].v_pointer);
* g_return_val_if_fail (object != NULL, * g_return_val_if_fail (object != NULL,
* g_strdup_printf ("Object passed as invalid NULL pointer")); * g_strdup_printf ("Object %p passed as invalid NULL pointer", object));
* // never honour G_VALUE_NOCOPY_CONTENTS for ref-counted types * // never honour G_VALUE_NOCOPY_CONTENTS for ref-counted types
* value->data[0].v_pointer = g_object_ref (object); * value->data[0].v_pointer = g_object_ref (object);
* return NULL; * return NULL;
* ]| * ]|
* The reference count for valid objects is always incremented, *
* regardless of @collect_flags. For invalid objects, the example * The reference count for valid objects is always incremented, regardless
* returns a newly allocated string without altering @value. * of `collect_flags`. For invalid objects, the example returns a newly
* Upon success, collect_value() needs to return %NULL. If, however, * allocated string without altering `value`.
* an error condition occurred, collect_value() may spew an *
* error by returning a newly allocated non-%NULL string, giving * Upon success, `collect_value()` needs to return `NULL`. If, however,
* a suitable description of the error condition. * an error condition occurred, `collect_value()` should return a newly
* The calling code makes no assumptions about the @value * allocated string containing an error diagnostic.
* contents being valid upon error returns, @value *
* is simply thrown away without further freeing. As such, it is * The calling code makes no assumptions about the `value` contents being
* a good idea to not allocate #GValue contents, prior to returning * valid upon error returns, `value` is simply thrown away without further
* an error, however, collect_values() is not obliged to return * freeing. As such, it is a good idea to not allocate `GValue` contents
* a correctly setup @value for error returns, simply because * prior to returning an error; however, `collect_values()` is not obliged
* any non-%NULL return is considered a fatal condition so further * to return a correctly setup @value for error returns, simply because
* program behaviour is undefined. * any non-`NULL` return is considered a fatal programming error, and
* @lcopy_format: Format description of the arguments to collect for @lcopy_value, * further program behaviour is undefined.
* analogous to @collect_format. Usually, @lcopy_format string consists *
* only of 'p's to provide lcopy_value() with pointers to storage locations. * Returns: (transfer full) (nullable): `NULL` on success, otherwise a
* @lcopy_value: This function is responsible for storing the @value contents into * newly allocated error string on failure
* arguments passed through a variable argument list which got *
* collected into @collect_values according to @lcopy_format. * Since: 2.78
* @n_collect_values equals the string length of @lcopy_format, */
* and @collect_flags may contain %G_VALUE_NOCOPY_CONTENTS. GOBJECT_AVAILABLE_TYPE_IN_2_78
* In contrast to collect_value(), lcopy_value() is obliged to typedef gchar * (* GTypeValueCollectFunc) (GValue *value,
* always properly support %G_VALUE_NOCOPY_CONTENTS. guint n_collect_values,
* Similar to collect_value() the function may prematurely abort GTypeCValue *collect_values,
* by returning a newly allocated string describing an error condition. guint collect_flags);
* To complete the string example:
/**
* GTypeValueLCopyFunc:
* @value: the value to lcopy
* @n_collect_values: the number of collected values
* @collect_values: (array length=n_collect_values): the collected
* locations for storage
* @collect_flags: optional flags
*
* This function is responsible for storing the `value`
* contents into arguments passed through a variadic argument list which
* got collected into `collect_values` according to `lcopy_format`.
*
* The `n_collect_values` argument equals the string length of
* `lcopy_format`, and `collect_flags` may contain %G_VALUE_NOCOPY_CONTENTS.
*
* In contrast to #GTypeValueCollectFunc, this function is obliged to always
* properly support %G_VALUE_NOCOPY_CONTENTS.
*
* Similar to #GTypeValueCollectFunc the function may prematurely abort by
* returning a newly allocated string describing an error condition. To
* complete the string example:
*
* |[<!-- language="C" --> * |[<!-- language="C" -->
* gchar **string_p = collect_values[0].v_pointer; * gchar **string_p = collect_values[0].v_pointer;
* g_return_val_if_fail (string_p != NULL, * g_return_val_if_fail (string_p != NULL,
* g_strdup_printf ("string location passed as NULL")); * g_strdup ("string location passed as NULL"));
*
* if (collect_flags & G_VALUE_NOCOPY_CONTENTS) * if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
* *string_p = value->data[0].v_pointer; * *string_p = value->data[0].v_pointer;
* else * else
* *string_p = g_strdup (value->data[0].v_pointer); * *string_p = g_strdup (value->data[0].v_pointer);
* ]| * ]|
* And an illustrative version of lcopy_value() for *
* reference-counted types: * And an illustrative version of this function for reference-counted
* types:
*
* |[<!-- language="C" --> * |[<!-- language="C" -->
* GObject **object_p = collect_values[0].v_pointer; * GObject **object_p = collect_values[0].v_pointer;
* g_return_val_if_fail (object_p != NULL, * g_return_val_if_fail (object_p != NULL,
* g_strdup_printf ("object location passed as NULL")); * g_strdup ("object location passed as NULL"));
* if (!value->data[0].v_pointer) *
* if (value->data[0].v_pointer == NULL)
* *object_p = NULL; * *object_p = NULL;
* else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) // always honour * else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) // always honour
* *object_p = value->data[0].v_pointer; * *object_p = value->data[0].v_pointer;
* else * else
* *object_p = g_object_ref (value->data[0].v_pointer); * *object_p = g_object_ref (value->data[0].v_pointer);
*
* return NULL; * return NULL;
* ]| * ]|
* *
* Returns: (transfer full) (nullable): `NULL` on success, otherwise
* a newly allocated error string on failure
*
* Since: 2.78
*/
GOBJECT_AVAILABLE_TYPE_IN_2_78
typedef gchar * (* GTypeValueLCopyFunc) (const GValue *value,
guint n_collect_values,
GTypeCValue *collect_values,
guint collect_flags);
/**
* GTypeValueTable:
* @value_init: Function to initialize a GValue
* @value_free: Function to free a GValue
* @value_copy: Function to copy a GValue
* @value_peek_pointer: Function to peek the contents of a GValue if they fit
* into a pointer
* @collect_format: A string format describing how to collect the contents of
* this value bit-by-bit. Each character in the format represents
* an argument to be collected, and the characters themselves indicate
* the type of the argument. Currently supported arguments are:
* - `'i'`: Integers, passed as `collect_values[].v_int`
* - `'l'`: Longs, passed as `collect_values[].v_long`
* - `'d'`: Doubles, passed as `collect_values[].v_double`
* - `'p'`: Pointers, passed as `collect_values[].v_pointer`
* It should be noted that for variable argument list construction,
* ANSI C promotes every type smaller than an integer to an int, and
* floats to doubles. So for collection of short int or char, `'i'`
* needs to be used, and for collection of floats `'d'`.
* @collect_value: Function to initialize a GValue from the values
* collected from variadic arguments
* @lcopy_format: Format description of the arguments to collect for @lcopy_value,
* analogous to @collect_format. Usually, @lcopy_format string consists
* only of `'p'`s to provide lcopy_value() with pointers to storage locations.
* @lcopy_value: Function to store the contents of a value into the
* locations collected from variadic arguments
*
* The #GTypeValueTable provides the functions required by the #GValue * The #GTypeValueTable provides the functions required by the #GValue
* implementation, to serve as a container for values of a type. * implementation, to serve as a container for values of a type.
*/ */
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
struct _GTypeValueTable struct _GTypeValueTable
{ {
void (*value_init) (GValue *value); GTypeValueInitFunc value_init;
void (*value_free) (GValue *value); GTypeValueFreeFunc value_free;
void (*value_copy) (const GValue *src_value, GTypeValueCopyFunc value_copy;
GValue *dest_value); GTypeValuePeekPointerFunc value_peek_pointer;
/* varargs functionality (optional) */
gpointer (*value_peek_pointer) (const GValue *value);
const gchar *collect_format; const gchar *collect_format;
gchar* (*collect_value) (GValue *value, GTypeValueCollectFunc collect_value;
guint n_collect_values,
GTypeCValue *collect_values,
guint collect_flags);
const gchar *lcopy_format; const gchar *lcopy_format;
gchar* (*lcopy_value) (const GValue *value, GTypeValueLCopyFunc lcopy_value;
guint n_collect_values,
GTypeCValue *collect_values,
guint collect_flags);
}; };
G_GNUC_END_IGNORE_DEPRECATIONS
GOBJECT_AVAILABLE_IN_ALL GOBJECT_AVAILABLE_IN_ALL
GType g_type_register_static (GType parent_type, GType g_type_register_static (GType parent_type,
const gchar *type_name, const gchar *type_name,