summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmmanuele Bassi <ebassi@gnome.org>2022-10-29 18:09:23 +0100
committerEmmanuele Bassi <ebassi@gnome.org>2023-01-08 14:50:28 +0000
commite9e3866133275cedcec6b9953adaf88fefcabbf8 (patch)
tree813abc2433ad2d50c23303a6cc0c7b09a8646a92
parent221b006625f2185b5a4d81d544bd0a2acf70ef60 (diff)
downloadgobject-introspection-e9e3866133275cedcec6b9953adaf88fefcabbf8.tar.gz
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
-rw-r--r--girepository/girnode.c22
-rw-r--r--girepository/girnode.h6
-rw-r--r--girepository/girparser.c17
-rw-r--r--girepository/girwriter.c18
-rw-r--r--girepository/gistructinfo.c54
-rw-r--r--girepository/gistructinfo.h7
-rw-r--r--girepository/gitypelib-internal.h20
-rw-r--r--girepository/giunioninfo.c54
-rw-r--r--girepository/giunioninfo.h6
-rw-r--r--giscanner/annotationparser.py63
-rw-r--r--giscanner/ast.py12
-rw-r--r--giscanner/girparser.py6
-rw-r--r--giscanner/girwriter.py8
-rw-r--r--giscanner/maintransformer.py9
14 files changed, 287 insertions, 15 deletions
diff --git a/girepository/girnode.c b/girepository/girnode.c
index 34b7dea8..4a8d78b9 100644
--- a/girepository/girnode.c
+++ b/girepository/girnode.c
@@ -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)
diff --git a/girepository/girnode.h b/girepository/girnode.h
index 7b8c97f6..45a81477 100644
--- a/girepository/girnode.h
+++ b/girepository/girnode.h
@@ -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;
diff --git a/girepository/girparser.c b/girepository/girparser.c
index e5878b43..5ac4aefe 100644
--- a/girepository/girparser.c
+++ b/girepository/girparser.c
@@ -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
diff --git a/girepository/girwriter.c b/girepository/girwriter.c
index ea148f32..276bb676 100644
--- a/girepository/girwriter.c
+++ b/girepository/girwriter.c
@@ -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))
diff --git a/girepository/gistructinfo.c b/girepository/gistructinfo.c
index a9ad73f6..c13cb716 100644
--- a/girepository/gistructinfo.c
+++ b/girepository/gistructinfo.c
@@ -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;
+}
diff --git a/girepository/gistructinfo.h b/girepository/gistructinfo.h
index 6e70fea7..8ff10d3c 100644
--- a/girepository/gistructinfo.h
+++ b/girepository/gistructinfo.h
@@ -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);
-G_END_DECLS
+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__ */
diff --git a/girepository/gitypelib-internal.h b/girepository/gitypelib-internal.h
index 77c4d6f3..494ab2b3 100644
--- a/girepository/gitypelib-internal.h
+++ b/girepository/gitypelib-internal.h
@@ -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;
diff --git a/girepository/giunioninfo.c b/girepository/giunioninfo.c
index 0089f11c..32a2e307 100644
--- a/girepository/giunioninfo.c
+++ b/girepository/giunioninfo.c
@@ -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;
+}
diff --git a/girepository/giunioninfo.h b/girepository/giunioninfo.h
index 62951b85..4087ed4d 100644
--- a/girepository/giunioninfo.h
+++ b/girepository/giunioninfo.h
@@ -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
diff --git a/giscanner/annotationparser.py b/giscanner/annotationparser.py
index 3952b24b..e567115a 100644
--- a/giscanner/annotationparser.py
+++ b/giscanner/annotationparser.py
@@ -193,11 +193,13 @@ ANN_ARRAY = 'array'
ANN_ATTRIBUTES = 'attributes'
ANN_CLOSURE = 'closure'
ANN_CONSTRUCTOR = 'constructor'
+ANN_COPY_FUNC = 'copy-func'
ANN_DEFAULT_VALUE = 'default-value'
ANN_DESTROY = 'destroy'
ANN_ELEMENT_TYPE = 'element-type'
ANN_EMITTER = 'emitter'
ANN_FOREIGN = 'foreign'
+ANN_FREE_FUNC = 'free-func'
ANN_GET_PROPERTY = 'get-property'
ANN_GET_VALUE_FUNC = 'get-value-func'
ANN_GETTER = 'getter'
@@ -790,6 +792,18 @@ class GtkDocAnnotatable(object):
self._validate_annotation(position, ann_name, options, exact_n_options=0)
+ def _do_validate_copy_func(self, position, ann_name, options):
+ '''
+ Validate the ``(copy-func)`` annotation.
+
+ :param position: :class:`giscanner.message.Position` of the line in the source file
+ containing the annotation to be validated
+ :param ann_name: name of the annotation holding the options to validate
+ :param options: annotation options to validate
+ '''
+
+ self._validate_annotation(position, ann_name, options, exact_n_options=1)
+
def _do_validate_default_value(self, position, ann_name, options):
'''
Validate the ``(default-value)`` annotation.
@@ -851,6 +865,18 @@ class GtkDocAnnotatable(object):
self._validate_annotation(position, ann_name, options, exact_n_options=0)
+ def _do_validate_free_func(self, position, ann_name, options):
+ '''
+ Validate the ``(free-func)`` annotation.
+
+ :param position: :class:`giscanner.message.Position` of the line in the source file
+ containing the annotation to be validated
+ :param ann_name: name of the annotation holding the options to validate
+ :param options: annotation options to validate
+ '''
+
+ self._validate_annotation(position, ann_name, options, exact_n_options=1)
+
def _do_validate_get_property(self, position, ann_name, options):
'''
Validate the ``(get-property)`` annotation.
@@ -1127,9 +1153,24 @@ class GtkDocParameter(GtkDocAnnotatable):
__slots__ = ('name', 'description')
- valid_annotations = (ANN_ALLOW_NONE, ANN_ARRAY, ANN_ATTRIBUTES, ANN_CLOSURE, ANN_DESTROY,
- ANN_ELEMENT_TYPE, ANN_IN, ANN_INOUT, ANN_OUT, ANN_SCOPE, ANN_SKIP,
- ANN_TRANSFER, ANN_TYPE, ANN_OPTIONAL, ANN_NULLABLE, ANN_NOT)
+ valid_annotations = (
+ ANN_ALLOW_NONE,
+ ANN_ARRAY,
+ ANN_ATTRIBUTES,
+ ANN_CLOSURE,
+ ANN_DESTROY,
+ ANN_ELEMENT_TYPE,
+ ANN_IN,
+ ANN_INOUT,
+ ANN_OUT,
+ ANN_SCOPE,
+ ANN_SKIP,
+ ANN_TRANSFER,
+ ANN_TYPE,
+ ANN_OPTIONAL,
+ ANN_NULLABLE,
+ ANN_NOT,
+ )
def __init__(self, name, position=None):
GtkDocAnnotatable.__init__(self, position)
@@ -1151,8 +1192,18 @@ class GtkDocTag(GtkDocAnnotatable):
__slots__ = ('name', 'value', 'description')
- valid_annotations = (ANN_ALLOW_NONE, ANN_ARRAY, ANN_ATTRIBUTES, ANN_ELEMENT_TYPE, ANN_SKIP,
- ANN_TRANSFER, ANN_TYPE, ANN_NULLABLE, ANN_OPTIONAL, ANN_NOT)
+ valid_annotations = (
+ ANN_ALLOW_NONE,
+ ANN_ARRAY,
+ ANN_ATTRIBUTES,
+ ANN_ELEMENT_TYPE,
+ ANN_SKIP,
+ ANN_TRANSFER,
+ ANN_TYPE,
+ ANN_NULLABLE,
+ ANN_OPTIONAL,
+ ANN_NOT,
+ )
def __init__(self, name, position=None):
GtkDocAnnotatable.__init__(self, position)
@@ -1182,9 +1233,11 @@ class GtkDocCommentBlock(GtkDocAnnotatable):
valid_annotations = (
ANN_ATTRIBUTES,
ANN_CONSTRUCTOR,
+ ANN_COPY_FUNC,
ANN_DEFAULT_VALUE,
ANN_EMITTER,
ANN_FOREIGN,
+ ANN_FREE_FUNC,
ANN_GET_PROPERTY,
ANN_GET_VALUE_FUNC,
ANN_GETTER,
diff --git a/giscanner/ast.py b/giscanner/ast.py
index dac326cb..bbfbe267 100644
--- a/giscanner/ast.py
+++ b/giscanner/ast.py
@@ -1127,6 +1127,12 @@ class Record(Compound):
# If non-None, this record defines the FooClass C structure
# for some Foo GObject (or similar for GInterface)
self.is_gtype_struct_for = None
+ # If non-None, this record has a copy function for heap
+ # allocated instances
+ self.copy_func = None
+ # If non-None, this record has a free function for heap
+ # allocated instances
+ self.free_func = None
class Union(Compound):
@@ -1145,6 +1151,12 @@ class Union(Compound):
c_symbol_prefix=c_symbol_prefix,
disguised=disguised,
tag_name=tag_name)
+ # If non-None, this union has a copy function for heap
+ # allocated instances
+ self.copy_func = None
+ # If non-None, this union has a free function for heap
+ # allocated instances
+ self.free_func = None
class Boxed(Node, Registered):
diff --git a/giscanner/girparser.py b/giscanner/girparser.py
index 5fc22899..2f8c5f66 100644
--- a/giscanner/girparser.py
+++ b/giscanner/girparser.py
@@ -462,14 +462,20 @@ class GIRParser(object):
def _parse_record(self, node, anonymous=False):
struct = self._parse_compound(ast.Record, node)
is_gtype_struct_for = node.attrib.get(_glibns('is-gtype-struct-for'))
+ copy_func = node.attrib.get('copy-function')
+ free_func = node.attrib.get('free-function')
if is_gtype_struct_for is not None:
struct.is_gtype_struct_for = self._namespace.type_from_name(is_gtype_struct_for)
+ struct.copy_func = copy_func
+ struct.free_func = free_func
if not anonymous:
self._namespace.append(struct)
return struct
def _parse_union(self, node, anonymous=False):
union = self._parse_compound(ast.Union, node)
+ union.copy_func = node.attrib.get('copy-function')
+ union.free_func = node.attrib.get('free-function')
if not anonymous:
self._namespace.append(union)
return union
diff --git a/giscanner/girwriter.py b/giscanner/girwriter.py
index a3b3bc3e..810acad6 100644
--- a/giscanner/girwriter.py
+++ b/giscanner/girwriter.py
@@ -593,6 +593,10 @@ class GIRWriter(XMLWriter):
is_gtype_struct = True
attrs.append(('glib:is-gtype-struct-for',
self._type_to_name(record.is_gtype_struct_for)))
+ if record.copy_func:
+ attrs.append(('copy-function', record.copy_func))
+ if record.free_func:
+ attrs.append(('free-function', record.free_func))
self._append_version(record, attrs)
self._append_node_generic(record, attrs)
self._append_registered(record, attrs)
@@ -621,6 +625,10 @@ class GIRWriter(XMLWriter):
self._append_registered(union, attrs)
if union.c_symbol_prefix:
attrs.append(('c:symbol-prefix', union.c_symbol_prefix))
+ if union.copy_func:
+ attrs.append(('copy-function', union.copy_func))
+ if union.free_func:
+ attrs.append(('free-function', union.free_func))
with self.tagcontext('union', attrs):
self._write_generic(union)
if union.fields:
diff --git a/giscanner/maintransformer.py b/giscanner/maintransformer.py
index 285712c7..4393e160 100644
--- a/giscanner/maintransformer.py
+++ b/giscanner/maintransformer.py
@@ -28,11 +28,13 @@ from .annotationparser import (
ANN_ATTRIBUTES,
ANN_CLOSURE,
ANN_CONSTRUCTOR,
+ ANN_COPY_FUNC,
ANN_DEFAULT_VALUE,
ANN_DESTROY,
ANN_ELEMENT_TYPE,
ANN_EMITTER,
ANN_FOREIGN,
+ ANN_FREE_FUNC,
ANN_GET_PROPERTY,
ANN_GET_VALUE_FUNC,
ANN_GETTER,
@@ -310,6 +312,13 @@ class MainTransformer(object):
node.get_value_func = annotation[0] if annotation else None
if isinstance(node, ast.Constant):
self._apply_annotations_constant(node)
+ if isinstance(node, (ast.Record, ast.Union)):
+ block = self._get_block(node)
+ if block:
+ annotation = block.annotations.get(ANN_COPY_FUNC)
+ node.copy_func = annotation[0] if annotation else None
+ annotation = block.annotations.get(ANN_FREE_FUNC)
+ node.free_func = annotation[0] if annotation else None
return True
def _adjust_container_type(self, parent, node, annotations):