Add copy and free function annotations for POD types

Plain Old Data (POD) types with or without a representation in the GType
type system can still have a copy and/or a free function. We should
allow annotating these types with their corresponding functions for
copying their data into a new instance, and freeing their data.

From a language bindings perspective, POD types should have a boxed
GType wrapper around them, so they can use the generic GBoxed API to
copy and free instances; from a documentation perspective, though, it'd
be good to have a way to match a structured type, like a struct or a
union, with its copy and free functions.

In order to do that, we add two new header block annotations:

- (copy-func function_name)
- (free-func function_name)

These annotations work exactly like ref-func and unref-func for typed
instances:

    /**
     * GdkRGBA: (copy-func gdk_rgba_copy)
     *   (free-func gdk_rgba_free)
     * @red: ...
     * @green: ...
     * @blue: ...
     * @alpha: ...
     *
     * ...
     */

The function is stored in the GIR data as two new attributes for the
`<record>` and `<union>` elements:

    <record name="RGBA"
            c:type="GdkRGBA"
            copy-function="gdk_rgba_copy"
            free-function="gdk_rgba_free"
            glib:type-name="GdkRGBA"
            glib:get-type="gdk_rgba_get_type"
            c:symbol-prefix="gdk_rgba">

The annotations are not mandatory.

See: #14
This commit is contained in:
Emmanuele Bassi 2022-10-29 18:09:23 +01:00
parent 47b674d30f
commit 605fdf7046
9 changed files with 194 additions and 10 deletions

View File

@ -370,6 +370,8 @@ _g_ir_node_free (GIrNode *node)
g_free (node->name);
g_free (struct_->gtype_name);
g_free (struct_->gtype_init);
g_free (struct_->copy_func);
g_free (struct_->free_func);
for (l = struct_->members; l; l = l->next)
_g_ir_node_free ((GIrNode *)l->data);
@ -403,6 +405,8 @@ _g_ir_node_free (GIrNode *node)
g_free (node->name);
g_free (union_->gtype_name);
g_free (union_->gtype_init);
g_free (union_->copy_func);
g_free (union_->free_func);
_g_ir_node_free ((GIrNode *)union_->discriminator_type);
for (l = union_->members; l; l = l->next)
@ -755,6 +759,10 @@ _g_ir_node_get_full_size_internal (GIrNode *parent,
size += ALIGN_VALUE (strlen (struct_->gtype_name) + 1, 4);
if (struct_->gtype_init)
size += ALIGN_VALUE (strlen (struct_->gtype_init) + 1, 4);
if (struct_->copy_func)
size += ALIGN_VALUE (strlen (struct_->copy_func) + 1, 4);
if (struct_->free_func)
size += ALIGN_VALUE (strlen (struct_->free_func) + 1, 4);
for (l = struct_->members; l; l = l->next)
size += _g_ir_node_get_full_size_internal (node, (GIrNode *)l->data);
}
@ -855,6 +863,10 @@ _g_ir_node_get_full_size_internal (GIrNode *parent,
size += ALIGN_VALUE (strlen (union_->gtype_name) + 1, 4);
if (union_->gtype_init)
size += ALIGN_VALUE (strlen (union_->gtype_init) + 1, 4);
if (union_->copy_func)
size += ALIGN_VALUE (strlen (union_->copy_func) + 1, 4);
if (union_->free_func)
size += ALIGN_VALUE (strlen (union_->free_func) + 1, 4);
for (l = union_->members; l; l = l->next)
size += _g_ir_node_get_full_size_internal (node, (GIrNode *)l->data);
for (l = union_->discriminators; l; l = l->next)
@ -1956,6 +1968,11 @@ _g_ir_node_build_typelib (GIrNode *node,
blob->gtype_init = 0;
}
if (struct_->copy_func)
blob->copy_func = _g_ir_write_string (struct_->copy_func, strings, data, offset2);
if (struct_->free_func)
blob->free_func = _g_ir_write_string (struct_->free_func, strings, data, offset2);
blob->n_fields = 0;
blob->n_methods = 0;
@ -2040,6 +2057,11 @@ _g_ir_node_build_typelib (GIrNode *node,
blob->discriminator_offset = union_->discriminator_offset;
if (union_->copy_func)
blob->copy_func = _g_ir_write_string (union_->copy_func, strings, data, offset2);
if (union_->free_func)
blob->free_func = _g_ir_write_string (union_->free_func, strings, data, offset2);
/* We don't support Union discriminators right now. */
/*
if (union_->discriminator_type)

View File

@ -328,6 +328,9 @@ struct _GIrNodeStruct
gchar *gtype_name;
gchar *gtype_init;
gchar *copy_func;
gchar *free_func;
gint alignment;
gint size;
@ -346,6 +349,9 @@ struct _GIrNodeUnion
gchar *gtype_name;
gchar *gtype_init;
gchar *copy_func;
gchar *free_func;
gint alignment;
gint size;

View File

@ -477,7 +477,9 @@ parse_basic (const char *str)
static GIrNodeType *
parse_type_internal (GIrModule *module,
const gchar *str, char **next, gboolean in_glib,
const gchar *str,
char **next,
gboolean in_glib,
gboolean in_gobject)
{
const BasicTypeInfo *basic;
@ -2560,6 +2562,8 @@ start_struct (GMarkupParseContext *context,
const gchar *gtype_init;
const gchar *gtype_struct;
const gchar *foreign;
const gchar *copy_func;
const gchar *free_func;
GIrNodeStruct *struct_;
if (!(strcmp (element_name, "record") == 0 &&
@ -2579,6 +2583,8 @@ start_struct (GMarkupParseContext *context,
gtype_init = find_attribute ("glib:get-type", attribute_names, attribute_values);
gtype_struct = find_attribute ("glib:is-gtype-struct-for", attribute_names, attribute_values);
foreign = find_attribute ("foreign", attribute_names, attribute_values);
copy_func = find_attribute ("copy-function", attribute_names, attribute_values);
free_func = find_attribute ("free-function", attribute_names, attribute_values);
if (name == NULL && ctx->node_stack == NULL)
{
@ -2615,6 +2621,9 @@ start_struct (GMarkupParseContext *context,
struct_->foreign = (g_strcmp0 (foreign, "1") == 0);
struct_->copy_func = g_strdup (copy_func);
struct_->free_func = g_strdup (free_func);
if (ctx->node_stack == NULL)
ctx->current_module->entries =
g_list_append (ctx->current_module->entries, struct_);
@ -2634,6 +2643,8 @@ start_union (GMarkupParseContext *context,
const gchar *deprecated;
const gchar *typename;
const gchar *typeinit;
const gchar *copy_func;
const gchar *free_func;
GIrNodeUnion *union_;
if (!(strcmp (element_name, "union") == 0 &&
@ -2650,6 +2661,8 @@ start_union (GMarkupParseContext *context,
deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
copy_func = find_attribute ("copy-function", attribute_names, attribute_values);
free_func = find_attribute ("free-function", attribute_names, attribute_values);
if (name == NULL && ctx->node_stack == NULL)
{
@ -2663,6 +2676,8 @@ start_union (GMarkupParseContext *context,
((GIrNode *)union_)->name = g_strdup (name ? name : "");
union_->gtype_name = g_strdup (typename);
union_->gtype_init = g_strdup (typeinit);
union_->copy_func = g_strdup (copy_func);
union_->free_func = g_strdup (free_func);
if (deprecated)
union_->deprecated = TRUE;
else

View File

@ -642,6 +642,7 @@ write_struct_info (const gchar *namespace,
const gchar *name;
const gchar *type_name;
const gchar *type_init;
const gchar *func;
gboolean deprecated;
gboolean is_gtype_struct;
gboolean foreign;
@ -676,6 +677,14 @@ write_struct_info (const gchar *namespace,
if (is_gtype_struct)
xml_printf (file, " glib:is-gtype-struct=\"1\"");
func = g_struct_info_get_copy_function (info);
if (func)
xml_printf (file, " copy-function=\"%s\"", func);
func = g_struct_info_get_free_function (info);
if (func)
xml_printf (file, " free-function=\"%s\"", func);
write_attributes (file, (GIBaseInfo*) info);
size = g_struct_info_get_size (info);
@ -1237,6 +1246,7 @@ write_union_info (const gchar *namespace,
const gchar *name;
const gchar *type_name;
const gchar *type_init;
const gchar *func;
gboolean deprecated;
gint i;
gint size;
@ -1260,6 +1270,14 @@ write_union_info (const gchar *namespace,
if (file->show_all && size >= 0)
xml_printf (file, " size=\"%d\"", size);
func = g_union_info_get_copy_function (info);
if (func)
xml_printf (file, " copy-function=\"%s\"", func);
func = g_union_info_get_free_function (info);
if (func)
xml_printf (file, " free-function=\"%s\"", func);
write_attributes (file, (GIBaseInfo*) info);
if (g_union_info_is_discriminated (info))

View File

@ -281,3 +281,57 @@ g_struct_info_is_gtype_struct (GIStructInfo *info)
return blob->is_gtype_struct;
}
/**
* g_struct_info_get_copy_function:
* @info: a struct information blob
*
* Retrieves the name of the copy function for @info, if any is set.
*
* Returns: (transfer none) (nullable): the name of the copy function
*
* Since: 1.76
*/
const char *
g_struct_info_get_copy_function (GIStructInfo *info)
{
GIRealInfo *rinfo = (GIRealInfo *)info;
StructBlob *blob;
g_return_val_if_fail (info != NULL, NULL);
g_return_val_if_fail (GI_IS_STRUCT_INFO (info), NULL);
blob = (StructBlob *)&rinfo->typelib->data[rinfo->offset];
if (blob->copy_func)
return g_typelib_get_string (rinfo->typelib, blob->copy_func);
return NULL;
}
/**
* g_struct_info_get_free_function:
* @info: a struct information blob
*
* Retrieves the name of the free function for @info, if any is set.
*
* Returns: (transfer none) (nullable): the name of the free function
*
* Since: 1.76
*/
const char *
g_struct_info_get_free_function (GIStructInfo *info)
{
GIRealInfo *rinfo = (GIRealInfo *)info;
StructBlob *blob;
g_return_val_if_fail (info != NULL, NULL);
g_return_val_if_fail (GI_IS_STRUCT_INFO (info), NULL);
blob = (StructBlob *)&rinfo->typelib->data[rinfo->offset];
if (blob->free_func)
return g_typelib_get_string (rinfo->typelib, blob->free_func);
return NULL;
}

View File

@ -75,7 +75,12 @@ gboolean g_struct_info_is_gtype_struct (GIStructInfo *info);
GI_AVAILABLE_IN_ALL
gboolean g_struct_info_is_foreign (GIStructInfo *info);
GI_AVAILABLE_IN_1_76
const char * g_struct_info_get_copy_function (GIStructInfo *info);
GI_AVAILABLE_IN_1_76
const char * g_struct_info_get_free_function (GIStructInfo *info);
G_END_DECLS
#endif /* __GISTRUCTINFO_H__ */

View File

@ -792,8 +792,10 @@ typedef struct {
* @size: The size of the struct in bytes.
* @n_fields: TODO
* @n_methods: TODO
* @reserved2: Reserved for future use.
* @reserved3: Reserved for future use.
* @copy_func: String pointing to a function which can be called to copy
* the contents of this struct type
* @free_func: String pointing to a function which can be called to free
* the contents of this struct type
*
* TODO
*/
@ -817,8 +819,8 @@ typedef struct {
guint16 n_fields;
guint16 n_methods;
guint32 reserved2;
guint32 reserved3;
guint32 copy_func;
guint32 free_func;
} StructBlob;
/**
@ -835,8 +837,10 @@ typedef struct {
* @size: TODO
* @n_fields: Length of the arrays
* @n_functions: TODO
* @reserved2: Reserved for future use.
* @reserved3: Reserved for future use.
* @copy_func: String pointing to a function which can be called to copy
* the contents of this union type
* @free_func: String pointing to a function which can be called to free
* the contents of this union type
* @discriminator_offset: Offset from the beginning of the union where the
* discriminator of a discriminated union is located. The value 0xFFFF
* indicates that the discriminator offset is unknown.
@ -861,8 +865,8 @@ typedef struct {
guint16 n_fields;
guint16 n_functions;
guint32 reserved2;
guint32 reserved3;
guint32 copy_func;
guint32 free_func;
gint32 discriminator_offset;
SimpleTypeBlob discriminator_type;

View File

@ -267,3 +267,57 @@ g_union_info_get_alignment (GIUnionInfo *info)
return blob->alignment;
}
/**
* g_union_info_get_copy_function:
* @info: a union information blob
*
* Retrieves the name of the copy function for @info, if any is set.
*
* Returns: (transfer none) (nullable): the name of the copy function
*
* Since: 1.76
*/
const char *
g_union_info_get_copy_function (GIUnionInfo *info)
{
GIRealInfo *rinfo = (GIRealInfo *)info;
UnionBlob *blob;
g_return_val_if_fail (info != NULL, NULL);
g_return_val_if_fail (GI_IS_UNION_INFO (info), NULL);
blob = (UnionBlob *)&rinfo->typelib->data[rinfo->offset];
if (blob->copy_func)
return g_typelib_get_string (rinfo->typelib, blob->copy_func);
return NULL;
}
/**
* g_union_info_get_free_function:
* @info: a union information blob
*
* Retrieves the name of the free function for @info, if any is set.
*
* Returns: (transfer none) (nullable): the name of the free function
*
* Since: 1.76
*/
const char *
g_union_info_get_free_function (GIUnionInfo *info)
{
GIRealInfo *rinfo = (GIRealInfo *)info;
UnionBlob *blob;
g_return_val_if_fail (info != NULL, NULL);
g_return_val_if_fail (GI_IS_UNION_INFO (info), NULL);
blob = (UnionBlob *)&rinfo->typelib->data[rinfo->offset];
if (blob->free_func)
return g_typelib_get_string (rinfo->typelib, blob->free_func);
return NULL;
}

View File

@ -77,6 +77,12 @@ gsize g_union_info_get_size (GIUnionInfo *info);
GI_AVAILABLE_IN_ALL
gsize g_union_info_get_alignment (GIUnionInfo *info);
GI_AVAILABLE_IN_1_76
const char * g_union_info_get_copy_function (GIUnionInfo *info);
GI_AVAILABLE_IN_1_76
const char * g_union_info_get_free_function (GIUnionInfo *info);
G_END_DECLS