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
GTypeFundamentalInfo
GInterfaceInfo
GTypeValueInitFunc
GTypeValueFreeFunc
GTypeValueCopyFunc
GTypeValuePeekPointerFunc
GTypeValueCollectFunc
GTypeValueLCopyFunc
GTypeValueTable
G_TYPE_FROM_INSTANCE
G_TYPE_FROM_CLASS

View File

@ -1164,179 +1164,291 @@ struct _GInterfaceInfo
GInterfaceFinalizeFunc interface_finalize;
gpointer interface_data;
};
/**
* GTypeValueInitFunc:
* @value: the value to initialize
*
* Initializes the value contents by setting the fields of the `value->data`
* array.
*
* The data array of the #GValue passed into this function was zero-filled
* 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" -->
* value->data[0].v_pointer = g_strdup ("");
* ]|
*
* Since: 2.78
*/
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" -->
* // only free strings without a specific flag for static storage
* if (!(value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS))
* g_free (value->data[0].v_pointer);
* ]|
*
* Since: 2.78
*/
GOBJECT_AVAILABLE_TYPE_IN_2_78
typedef void (* GTypeValueFreeFunc) (GValue *value);
/**
* 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" -->
* dest_value->data[0].v_pointer = g_strdup (src_value->data[0].v_pointer);
* ]|
*
* Since: 2.78
*/
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" -->
* return value->data[0].v_pointer;
* ]|
*
* Returns: (transfer none): a pointer to the value contents
*
* Since: 2.78
*/
GOBJECT_AVAILABLE_TYPE_IN_2_78
typedef gpointer (* GTypeValuePeekPointerFunc) (const GValue *value);
/**
* GTypeValueCollectFunc:
* @value: the value to initialize
* @n_collect_values: the number of collected values
* @collect_values: (array length=n_collect_values): the collected values
* @collect_flags: optional flags
*
* This function is responsible for converting the values collected from
* a variadic argument list into contents suitable for storage in a #GValue.
*
* This function should setup @value similar to #GTypeValueInitFunc; e.g.
* for a string value that does not allow `NULL` pointers, it needs to either
* emit an error, or do an implicit conversion by storing an empty string.
*
* The @value passed in to this function has a zero-filled data array, so
* just like for #GTypeValueInitFunc it is guaranteed to not contain any old
* contents that might need freeing.
*
* The @n_collect_values argument is the string length of the `collect_format`
* field of #GTypeValueTable, and `collect_values` is an array of #GTypeCValue
* with length of @n_collect_values, containing the collected values according
* 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.
*
* For our above string example, we continue with:
*
* |[<!-- language="C" -->
* if (!collect_values[0].v_pointer)
* value->data[0].v_pointer = g_strdup ("");
* else if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
* {
* value->data[0].v_pointer = collect_values[0].v_pointer;
* // keep a flag for the value_free() implementation to not free this string
* value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
* }
* else
* value->data[0].v_pointer = g_strdup (collect_values[0].v_pointer);
* return NULL;
* ]|
*
* 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
* reentrancy requirements and reference count assertions performed
* by the signal emission code, reference counts should always be
* incremented for reference counted contents stored in the `value->data`
* array. To deviate from our string example for a moment, and taking
* a look at an exemplary implementation for `GTypeValueTable.collect_value()`
* of `GObject`:
*
* |[<!-- language="C" -->
* GObject *object = G_OBJECT (collect_values[0].v_pointer);
* g_return_val_if_fail (object != NULL,
* g_strdup_printf ("Object %p passed as invalid NULL pointer", object));
* // never honour G_VALUE_NOCOPY_CONTENTS for ref-counted types
* value->data[0].v_pointer = g_object_ref (object);
* return NULL;
* ]|
*
* The reference count for valid objects is always incremented, regardless
* of `collect_flags`. For invalid objects, the example returns a newly
* allocated string without altering `value`.
*
* Upon success, `collect_value()` needs to return `NULL`. If, however,
* an error condition occurred, `collect_value()` should return a newly
* allocated string containing an error diagnostic.
*
* The calling code makes no assumptions about the `value` contents being
* valid upon error returns, `value` is simply thrown away without further
* freeing. As such, it is a good idea to not allocate `GValue` contents
* prior to returning an error; however, `collect_values()` is not obliged
* to return a correctly setup @value for error returns, simply because
* any non-`NULL` return is considered a fatal programming error, and
* further program behaviour is undefined.
*
* 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 * (* GTypeValueCollectFunc) (GValue *value,
guint n_collect_values,
GTypeCValue *collect_values,
guint collect_flags);
/**
* 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" -->
* gchar **string_p = collect_values[0].v_pointer;
* g_return_val_if_fail (string_p != NULL,
* g_strdup ("string location passed as NULL"));
*
* if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
* *string_p = value->data[0].v_pointer;
* else
* *string_p = g_strdup (value->data[0].v_pointer);
* ]|
*
* And an illustrative version of this function for reference-counted
* types:
*
* |[<!-- language="C" -->
* GObject **object_p = collect_values[0].v_pointer;
* g_return_val_if_fail (object_p != NULL,
* g_strdup ("object location passed as NULL"));
*
* if (value->data[0].v_pointer == NULL)
* *object_p = NULL;
* else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) // always honour
* *object_p = value->data[0].v_pointer;
* else
* *object_p = g_object_ref (value->data[0].v_pointer);
*
* 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: Default initialize @values contents by poking values
* directly into the value->data array. The data array of
* the #GValue passed into this function was zero-filled
* with `memset()`, so no care has to be taken to free any
* old contents. E.g. for the implementation of a string
* value that may never be %NULL, the implementation might
* look like:
* |[<!-- language="C" -->
* 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
* remain allocated through the #GValue contents after
* this function returns. E.g. for our above string type:
* |[<!-- language="C" -->
* // only free strings without a specific flag for static storage
* if (!(value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS))
* 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
* 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" -->
* 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
* the current contents. To extend on our above string example:
* |[<!-- language="C" -->
* return value->data[0].v_pointer;
* ]|
* @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: The collect_value() function is responsible for converting the
* values collected from a variable argument list into contents
* suitable for storage in a GValue. This function should setup
* @value similar to value_init(); e.g. for a string value that
* does not allow %NULL pointers, it needs to either spew an error,
* or do an implicit conversion by storing an empty string.
* The @value passed in to this function has a zero-filled data
* array, so just like for value_init() it is guaranteed to not
* contain any old contents that might need freeing.
* @n_collect_values is exactly the string length of @collect_format,
* and @collect_values is an array of unions #GTypeCValue with
* length @n_collect_values, containing the collected values
* according to @collect_format.
* @collect_flags is an 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.
* For our above string example, we continue with:
* |[<!-- language="C" -->
* if (!collect_values[0].v_pointer)
* value->data[0].v_pointer = g_strdup ("");
* else if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
* {
* value->data[0].v_pointer = collect_values[0].v_pointer;
* // keep a flag for the value_free() implementation to not free this string
* value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
* }
* else
* value->data[0].v_pointer = g_strdup (collect_values[0].v_pointer);
* return NULL;
* ]|
* 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
* reentrancy requirements and reference count assertions performed
* by the signal emission code, reference counts should always be
* incremented for reference counted contents stored in the value->data
* array. To deviate from our string example for a moment, and taking
* a look at an exemplary implementation for collect_value() of
* #GObject:
* |[<!-- language="C" -->
* GObject *object = G_OBJECT (collect_values[0].v_pointer);
* g_return_val_if_fail (object != NULL,
* g_strdup_printf ("Object passed as invalid NULL pointer"));
* // never honour G_VALUE_NOCOPY_CONTENTS for ref-counted types
* value->data[0].v_pointer = g_object_ref (object);
* return NULL;
* ]|
* The reference count for valid objects is always incremented,
* regardless of @collect_flags. For invalid objects, the example
* returns a newly allocated string without altering @value.
* Upon success, collect_value() needs to return %NULL. If, however,
* an error condition occurred, collect_value() may spew an
* error by returning a newly allocated non-%NULL string, giving
* a suitable description of the error condition.
* The calling code makes no assumptions about the @value
* contents being valid upon error returns, @value
* is simply thrown away without further freeing. As such, it is
* a good idea to not allocate #GValue contents, prior to returning
* an error, however, collect_values() is not obliged to return
* a correctly setup @value for error returns, simply because
* any non-%NULL return is considered a fatal condition so further
* program behaviour is undefined.
* 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: This function is responsible for storing the @value contents into
* arguments passed through a variable argument list which got
* collected into @collect_values according to @lcopy_format.
* @n_collect_values equals the string length of @lcopy_format,
* and @collect_flags may contain %G_VALUE_NOCOPY_CONTENTS.
* In contrast to collect_value(), lcopy_value() is obliged to
* always properly support %G_VALUE_NOCOPY_CONTENTS.
* Similar to collect_value() the function may prematurely abort
* by returning a newly allocated string describing an error condition.
* To complete the string example:
* |[<!-- language="C" -->
* gchar **string_p = collect_values[0].v_pointer;
* g_return_val_if_fail (string_p != NULL,
* g_strdup_printf ("string location passed as NULL"));
* if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
* *string_p = value->data[0].v_pointer;
* else
* *string_p = g_strdup (value->data[0].v_pointer);
* ]|
* And an illustrative version of lcopy_value() for
* reference-counted types:
* |[<!-- language="C" -->
* GObject **object_p = collect_values[0].v_pointer;
* g_return_val_if_fail (object_p != NULL,
* g_strdup_printf ("object location passed as NULL"));
* if (!value->data[0].v_pointer)
* *object_p = NULL;
* else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) // always honour
* *object_p = value->data[0].v_pointer;
* else
* *object_p = g_object_ref (value->data[0].v_pointer);
* return NULL;
* ]|
*
* 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
* implementation, to serve as a container for values of a type.
*/
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
struct _GTypeValueTable
{
void (*value_init) (GValue *value);
void (*value_free) (GValue *value);
void (*value_copy) (const GValue *src_value,
GValue *dest_value);
/* varargs functionality (optional) */
gpointer (*value_peek_pointer) (const GValue *value);
GTypeValueInitFunc value_init;
GTypeValueFreeFunc value_free;
GTypeValueCopyFunc value_copy;
GTypeValuePeekPointerFunc value_peek_pointer;
const gchar *collect_format;
gchar* (*collect_value) (GValue *value,
guint n_collect_values,
GTypeCValue *collect_values,
guint collect_flags);
GTypeValueCollectFunc collect_value;
const gchar *lcopy_format;
gchar* (*lcopy_value) (const GValue *value,
guint n_collect_values,
GTypeCValue *collect_values,
guint collect_flags);
GTypeValueLCopyFunc lcopy_value;
};
G_GNUC_END_IGNORE_DEPRECATIONS
GOBJECT_AVAILABLE_IN_ALL
GType g_type_register_static (GType parent_type,
const gchar *type_name,