[pygobject/gsoc2009: 67/160] Add basic ownership transfer for arrays and strings
- From: Simon van der Linden <svdlinden src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [pygobject/gsoc2009: 67/160] Add basic ownership transfer for arrays and strings
- Date: Fri, 14 Aug 2009 21:27:43 +0000 (UTC)
commit 124007502294681002bdac3ff3a6361e5784a89b
Author: Simon van der Linden <svdlinden src gnome org>
Date: Sat Jul 25 17:17:21 2009 +0200
Add basic ownership transfer for arrays and strings
Add input and output (not both input and output!) argument freeing
capability.
Note: because we might lose pointers to items in a container when the
transfer mode is 'container', we need to keep references in another
structure during the call.
gi/Makefile.am | 1 +
gi/pygargument.c | 190 +++++++++++++++++++++++++++++++++-----------
gi/pygargument.h | 10 ++-
gi/pygi-private.c | 24 ++++++
gi/pygi-private.h | 16 ++++
gi/pygiinfo.c | 178 ++++++++++++++++++++++++++---------------
tests/test_girepository.py | 18 ++++-
7 files changed, 319 insertions(+), 118 deletions(-)
---
diff --git a/gi/Makefile.am b/gi/Makefile.am
index d4e1e11..0943118 100644
--- a/gi/Makefile.am
+++ b/gi/Makefile.am
@@ -48,6 +48,7 @@ _gi_la_SOURCES = \
pygargument.c \
pygargument.h \
pygi.h \
+ pygi-private.c \
pygi-private.h \
gimodule.c
diff --git a/gi/pygargument.c b/gi/pygargument.c
index d8fb268..ad9924d 100644
--- a/gi/pygargument.c
+++ b/gi/pygargument.c
@@ -572,7 +572,7 @@ pygi_gi_type_tag_get_size(GITypeTag type_tag)
}
GArgument
-pygi_g_argument_from_py_object(PyObject *object, GITypeInfo *type_info)
+pygi_g_argument_from_py_object(PyObject *object, GITypeInfo *type_info, GITransfer transfer)
{
GArgument arg;
GITypeTag type_tag;
@@ -656,12 +656,20 @@ pygi_g_argument_from_py_object(PyObject *object, GITypeInfo *type_info)
break;
}
case GI_TYPE_TAG_UTF8:
+ {
+ const gchar *string;
+
if (object == Py_None) {
arg.v_string = NULL;
break;
}
- arg.v_string = g_strdup(PyString_AsString(object));
+
+ string = PyString_AsString(object);
+
+ /* Don't need to check for errors, since g_strdup is NULL-proof. */
+ arg.v_string = g_strdup(string);
break;
+ }
case GI_TYPE_TAG_INTERFACE:
{
GIBaseInfo *info;
@@ -796,7 +804,8 @@ pygi_g_argument_from_py_object(PyObject *object, GITypeInfo *type_info)
break;
}
- item = pygi_g_argument_from_py_object(py_item, item_type_info);
+ item = pygi_g_argument_from_py_object(py_item, item_type_info,
+ transfer == GI_TRANSFER_EVERYTHING ? GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING);
Py_DECREF(py_item);
@@ -839,7 +848,8 @@ pygi_g_argument_from_py_object(PyObject *object, GITypeInfo *type_info)
break;
}
- item = pygi_g_argument_from_py_object(py_item, item_type_info);
+ item = pygi_g_argument_from_py_object(py_item, item_type_info,
+ transfer == GI_TRANSFER_EVERYTHING ? GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING);
Py_DECREF(py_item);
@@ -936,13 +946,15 @@ pygi_g_argument_from_py_object(PyObject *object, GITypeInfo *type_info)
py_key = PyList_GET_ITEM(keys, i);
py_value = PyList_GET_ITEM(values, i);
- key = pygi_g_argument_from_py_object(py_key, key_type_info);
+ key = pygi_g_argument_from_py_object(py_key, key_type_info,
+ transfer == GI_TRANSFER_EVERYTHING ? GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING);
if (PyErr_Occurred()) {
/* TODO: free the previous items */
break;
}
- value = pygi_g_argument_from_py_object(py_value, value_type_info);
+ value = pygi_g_argument_from_py_object(py_value, value_type_info,
+ transfer == GI_TRANSFER_EVERYTHING ? GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING);
if (PyErr_Occurred()) {
/* TODO: free the previous items */
break;
@@ -989,7 +1001,7 @@ pygi_g_argument_from_py_object(PyObject *object, GITypeInfo *type_info)
}
PyObject *
-pygi_g_argument_to_py_object(GArgument arg, GITypeInfo *type_info)
+pygi_g_argument_to_py_object(GArgument *arg, GITypeInfo *type_info)
{
GITypeTag type_tag;
PyObject *object;
@@ -1004,69 +1016,69 @@ pygi_g_argument_to_py_object(GArgument arg, GITypeInfo *type_info)
object = Py_None;
break;
case GI_TYPE_TAG_BOOLEAN:
- object = PyBool_FromLong(arg.v_boolean);
+ object = PyBool_FromLong(arg->v_boolean);
break;
case GI_TYPE_TAG_UINT8:
- object = PyInt_FromLong(arg.v_uint8);
+ object = PyInt_FromLong(arg->v_uint8);
break;
case GI_TYPE_TAG_UINT16:
- object = PyInt_FromLong(arg.v_uint16);
+ object = PyInt_FromLong(arg->v_uint16);
break;
case GI_TYPE_TAG_UINT32:
- object = PyLong_FromLongLong(arg.v_uint32);
+ object = PyLong_FromLongLong(arg->v_uint32);
break;
case GI_TYPE_TAG_UINT64:
- object = PyLong_FromUnsignedLongLong(arg.v_uint64);
+ object = PyLong_FromUnsignedLongLong(arg->v_uint64);
break;
case GI_TYPE_TAG_USHORT:
- object = PyInt_FromLong(arg.v_ushort);
+ object = PyInt_FromLong(arg->v_ushort);
break;
case GI_TYPE_TAG_UINT:
- object = PyLong_FromLongLong(arg.v_uint);
+ object = PyLong_FromLongLong(arg->v_uint);
break;
case GI_TYPE_TAG_ULONG:
- object = PyLong_FromUnsignedLongLong(arg.v_ulong);
+ object = PyLong_FromUnsignedLongLong(arg->v_ulong);
break;
case GI_TYPE_TAG_SIZE:
- object = PyLong_FromUnsignedLongLong(arg.v_size);
+ object = PyLong_FromUnsignedLongLong(arg->v_size);
break;
case GI_TYPE_TAG_INT8:
- object = PyInt_FromLong(arg.v_int8);
+ object = PyInt_FromLong(arg->v_int8);
break;
case GI_TYPE_TAG_INT16:
- object = PyInt_FromLong(arg.v_int16);
+ object = PyInt_FromLong(arg->v_int16);
break;
case GI_TYPE_TAG_INT32:
- object = PyInt_FromLong(arg.v_int32);
+ object = PyInt_FromLong(arg->v_int32);
break;
case GI_TYPE_TAG_INT64:
- object = PyLong_FromLongLong(arg.v_int64);
+ object = PyLong_FromLongLong(arg->v_int64);
break;
case GI_TYPE_TAG_SHORT:
- object = PyInt_FromLong(arg.v_short);
+ object = PyInt_FromLong(arg->v_short);
break;
case GI_TYPE_TAG_INT:
- object = PyInt_FromLong(arg.v_int);
+ object = PyInt_FromLong(arg->v_int);
break;
case GI_TYPE_TAG_SSIZE:
- object = PyInt_FromLong(arg.v_ssize);
+ object = PyInt_FromLong(arg->v_ssize);
break;
case GI_TYPE_TAG_LONG:
- object = PyInt_FromLong(arg.v_long);
+ object = PyInt_FromLong(arg->v_long);
break;
case GI_TYPE_TAG_FLOAT:
- object = PyFloat_FromDouble(arg.v_float);
+ object = PyFloat_FromDouble(arg->v_float);
break;
case GI_TYPE_TAG_DOUBLE:
- object = PyFloat_FromDouble(arg.v_double);
+ object = PyFloat_FromDouble(arg->v_double);
break;
case GI_TYPE_TAG_UTF8:
- if (arg.v_string == NULL) {
+ if (arg->v_string == NULL) {
object = Py_None;
Py_INCREF(object);
break;
}
- object = PyString_FromString(arg.v_string);
+ object = PyString_FromString(arg->v_string);
break;
case GI_TYPE_TAG_INTERFACE:
{
@@ -1078,7 +1090,7 @@ pygi_g_argument_to_py_object(GArgument arg, GITypeInfo *type_info)
switch (info_type) {
case GI_INFO_TYPE_ENUM:
- object = PyInt_FromLong(arg.v_int);
+ object = PyInt_FromLong(arg->v_int);
break;
case GI_INFO_TYPE_STRUCT:
{
@@ -1090,14 +1102,14 @@ pygi_g_argument_to_py_object(GArgument arg, GITypeInfo *type_info)
/* Handle special cases first. */
type = g_registered_type_info_get_g_type((GIRegisteredTypeInfo *)info);
if (g_type_is_a(type, G_TYPE_VALUE)) {
- object = pyg_value_as_pyobject(arg.v_pointer, FALSE);
- g_value_unset(arg.v_pointer);
+ object = pyg_value_as_pyobject(arg->v_pointer, FALSE);
+ g_value_unset(arg->v_pointer);
break;
}
/* Create a Python buffer. */
size = g_struct_info_get_size((GIStructInfo *)info);
- buffer = PyBuffer_FromReadWriteMemory(arg.v_pointer, size);
+ buffer = PyBuffer_FromReadWriteMemory(arg->v_pointer, size);
if (buffer == NULL) {
goto struct_error_clean;
}
@@ -1135,7 +1147,7 @@ struct_error_clean:
break;
}
- object = pygobject_new(arg.v_pointer);
+ object = pygobject_new(arg->v_pointer);
Py_DECREF(py_type);
@@ -1155,7 +1167,7 @@ struct_error_clean:
GError *error = NULL;
gchar *string;
- string = g_filename_to_utf8(arg.v_string, -1, NULL, NULL, &error);
+ string = g_filename_to_utf8(arg->v_string, -1, NULL, NULL, &error);
if (string == NULL) {
PyErr_SetString(PyExc_Exception, error->message);
/* TODO: Convert the error to an exception. */
@@ -1172,11 +1184,9 @@ struct_error_clean:
{
GArray *array;
GITypeInfo *item_type_info;
- GITypeTag item_type_tag;
- gsize item_size;
gsize i;
- array = arg.v_pointer;
+ array = arg->v_pointer;
object = PyTuple_New(array->len);
if (object == NULL) {
@@ -1184,15 +1194,13 @@ struct_error_clean:
}
item_type_info = g_type_info_get_param_type(type_info, 0);
- item_type_tag = g_type_info_get_tag(item_type_info);
- item_size = pygi_gi_type_tag_get_size(item_type_tag);
for(i = 0; i < array->len; i++) {
GArgument item;
PyObject *py_item;
- item = *(GArgument *)(array->data + item_size * i);
- py_item = pygi_g_argument_to_py_object(item, item_type_info);
+ item = _g_array_index(array, GArgument, i);
+ py_item = pygi_g_argument_to_py_object(&item, item_type_info);
if (py_item == NULL) {
Py_CLEAR(object);
PyErr_PREFIX_FROM_FORMAT("Item %zu: ", i);
@@ -1213,7 +1221,7 @@ struct_error_clean:
GITypeInfo *item_type_info;
gsize i;
- list = arg.v_pointer;
+ list = arg->v_pointer;
length = g_slist_length(list);
object = PyList_New(length);
@@ -1229,7 +1237,7 @@ struct_error_clean:
item.v_pointer = list->data;
- py_item = pygi_g_argument_to_py_object(item, item_type_info);
+ py_item = pygi_g_argument_to_py_object(&item, item_type_info);
if (py_item == NULL) {
Py_CLEAR(object);
PyErr_PREFIX_FROM_FORMAT("Item %zu: ", i);
@@ -1258,18 +1266,18 @@ struct_error_clean:
key_type_info = g_type_info_get_param_type(type_info, 0);
value_type_info = g_type_info_get_param_type(type_info, 1);
- g_hash_table_iter_init(&hash_table_iter, (GHashTable *)arg.v_pointer);
+ g_hash_table_iter_init(&hash_table_iter, (GHashTable *)arg->v_pointer);
while (g_hash_table_iter_next(&hash_table_iter, &key.v_pointer, &value.v_pointer)) {
PyObject *py_key;
PyObject *py_value;
int retval;
- py_key = pygi_g_argument_to_py_object(key, key_type_info);
+ py_key = pygi_g_argument_to_py_object(&key, key_type_info);
if (py_key == NULL) {
break;
}
- py_value = pygi_g_argument_to_py_object(value, value_type_info);
+ py_value = pygi_g_argument_to_py_object(&value, value_type_info);
if (py_value == NULL) {
Py_DECREF(py_key);
break;
@@ -1292,7 +1300,7 @@ struct_error_clean:
}
case GI_TYPE_TAG_GTYPE:
{
- object = pyg_type_wrapper_new(arg.v_long);
+ object = pyg_type_wrapper_new(arg->v_long);
break;
}
default:
@@ -1303,3 +1311,91 @@ struct_error_clean:
return object;
}
+void
+pygi_g_argument_clean(GArgument *arg, GITypeInfo *type_info, GITransfer transfer, GIDirection direction)
+{
+ GITypeTag type_tag;
+
+ type_tag = g_type_info_get_tag(type_info);
+
+ switch(type_tag) {
+ case GI_TYPE_TAG_VOID:
+ case GI_TYPE_TAG_BOOLEAN:
+ case GI_TYPE_TAG_INT8:
+ case GI_TYPE_TAG_UINT8:
+ case GI_TYPE_TAG_INT16:
+ case GI_TYPE_TAG_UINT16:
+ case GI_TYPE_TAG_INT32:
+ case GI_TYPE_TAG_UINT32:
+ case GI_TYPE_TAG_INT64:
+ case GI_TYPE_TAG_UINT64:
+ case GI_TYPE_TAG_SHORT:
+ case GI_TYPE_TAG_USHORT:
+ case GI_TYPE_TAG_INT:
+ case GI_TYPE_TAG_UINT:
+ case GI_TYPE_TAG_LONG:
+ case GI_TYPE_TAG_ULONG:
+ case GI_TYPE_TAG_SSIZE:
+ case GI_TYPE_TAG_SIZE:
+ case GI_TYPE_TAG_FLOAT:
+ case GI_TYPE_TAG_DOUBLE:
+ case GI_TYPE_TAG_TIME_T:
+ case GI_TYPE_TAG_GTYPE:
+ /* Values, nothing to free. */
+ break;
+ case GI_TYPE_TAG_FILENAME:
+ case GI_TYPE_TAG_UTF8:
+ if (transfer == GI_TRANSFER_CONTAINER) {
+ PyErr_WarnEx(NULL, "Invalid 'container' transfer for string", 1);
+ break;
+ }
+ if ((direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING)
+ || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) {
+ g_free(arg->v_string);
+ }
+ break;
+ case GI_TYPE_TAG_ARRAY:
+ {
+ GArray *array;
+ GITypeInfo *item_type_info;
+ gsize i;
+
+ array = arg->v_pointer;
+
+ item_type_info = g_type_info_get_param_type(type_info, 0);
+
+ if ((direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING)
+ || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) {
+ GITransfer item_transfer;
+
+ if (direction == GI_DIRECTION_IN) {
+ item_transfer = GI_TRANSFER_NOTHING;
+ } else {
+ item_transfer = GI_TRANSFER_EVERYTHING;
+ }
+
+ /* Free the items */
+ for (i = 0; i < array->len; i++) {
+ GArgument item;
+ item = _g_array_index(array, GArgument, i);
+ pygi_g_argument_clean(&item, item_type_info, item_transfer, direction);
+ }
+ }
+
+ if ((direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING)
+ || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) {
+ g_array_free(array, TRUE);
+ }
+
+ g_base_info_unref((GIBaseInfo *)item_type_info);
+ break;
+ }
+ case GI_TYPE_TAG_INTERFACE:
+ case GI_TYPE_TAG_GLIST:
+ case GI_TYPE_TAG_GSLIST:
+ case GI_TYPE_TAG_GHASH:
+ case GI_TYPE_TAG_ERROR:
+ break;
+ }
+}
+
diff --git a/gi/pygargument.h b/gi/pygargument.h
index ab60456..570f9be 100644
--- a/gi/pygargument.h
+++ b/gi/pygargument.h
@@ -35,10 +35,16 @@ gint pygi_gi_type_info_check_py_object(GITypeInfo *type_info,
PyObject *object);
GArgument pygi_g_argument_from_py_object(PyObject *object,
- GITypeInfo *type_info);
-PyObject * pygi_g_argument_to_py_object(GArgument arg,
+ GITypeInfo *type_info,
+ GITransfer transfer);
+PyObject * pygi_g_argument_to_py_object(GArgument *arg,
GITypeInfo *type_info);
+void pygi_g_argument_clean(GArgument *arg,
+ GITypeInfo *type_info,
+ GITransfer transfer,
+ GIDirection direction);
+
G_END_DECLS
#endif /* __PYG_ARGUMENT_H__ */
diff --git a/gi/pygi-private.c b/gi/pygi-private.c
new file mode 100644
index 0000000..ef8be42
--- /dev/null
+++ b/gi/pygi-private.c
@@ -0,0 +1,24 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ */
+
+#include "pygi-private.h"
+
+GArray *
+_g_array_values(GArray *array)
+{
+ GArray *values;
+ gsize element_size;
+
+ element_size = g_array_get_element_size(array);
+
+ values = g_array_sized_new(FALSE, FALSE, element_size, array->len);
+
+ if (values == NULL) {
+ return NULL;
+ }
+
+ g_array_insert_vals(values, 0, array->data, array->len);
+
+ return values;
+}
diff --git a/gi/pygi-private.h b/gi/pygi-private.h
index af32488..05775f0 100644
--- a/gi/pygi-private.h
+++ b/gi/pygi-private.h
@@ -63,4 +63,20 @@ PyObject * pygi_py_type_find_by_name(const char *namespace_,
gpointer pygi_py_object_get_buffer(PyObject *object, gsize *size);
+#if GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 22
+#define g_array_get_element_size(a) \
+ *(guint *)((gpointer)(a) + sizeof(guint8 *) + sizeof(guint) * 2)
+#endif
+
+
+/* GArray */
+
+/* Redefine g_array_index because we want it to return the i-th element, casted
+ * to the type t, of the array a, and not the i-th element of the array a casted to the type t. */
+#define _g_array_index(a,t,i) \
+ *(t *)((a)->data + g_array_get_element_size(a) * (i))
+
+GArray * _g_array_values(GArray *array);
+
+
#endif /* __PYGI_PRIVATE_H__ */
diff --git a/gi/pygiinfo.c b/gi/pygiinfo.c
index d0de7ac..fefe1f5 100644
--- a/gi/pygiinfo.c
+++ b/gi/pygiinfo.c
@@ -392,6 +392,7 @@ _wrap_g_function_info_invoke(PyGIBaseInfo *self, PyObject *args)
guint n_args;
guint n_in_args;
guint n_out_args;
+ gsize n_in_containers;
Py_ssize_t n_py_args;
gsize n_aux_in_args;
gsize n_aux_out_args;
@@ -403,6 +404,7 @@ _wrap_g_function_info_invoke(PyGIBaseInfo *self, PyObject *args)
GArgument *in_args;
GArgument *out_args;
+ GArray **in_containers;
GArgument **aux_args;
GArgument *out_values;
GArgument return_arg;
@@ -425,6 +427,7 @@ _wrap_g_function_info_invoke(PyGIBaseInfo *self, PyObject *args)
n_py_args = PyTuple_Size(args);
n_in_args = is_method ? 1 : 0; /* The first argument is the instance. */
n_out_args = 0;
+ n_in_containers = 0;
n_aux_in_args = 0;
n_aux_out_args = 0;
aux_args = g_newa(GArgument *, n_args);
@@ -434,11 +437,13 @@ _wrap_g_function_info_invoke(PyGIBaseInfo *self, PyObject *args)
GIArgInfo *arg_info;
GITypeInfo *arg_type_info;
GITypeTag arg_type_tag;
+ GITransfer transfer;
arg_info = g_callable_info_get_arg(callable_info, i);
arg_type_info = g_arg_info_get_type(arg_info);
direction = g_arg_info_get_direction(arg_info);
+ transfer = g_arg_info_get_ownership_transfer(arg_info);
arg_type_tag = g_type_info_get_tag(arg_type_info);
@@ -449,6 +454,10 @@ _wrap_g_function_info_invoke(PyGIBaseInfo *self, PyObject *args)
n_out_args += 1;
}
+ if (transfer == GI_TRANSFER_CONTAINER && direction == GI_DIRECTION_IN) {
+ n_in_containers += 1;
+ }
+
aux_args[i] = NULL;
if (arg_type_tag == GI_TYPE_TAG_ARRAY) {
gint length_arg_pos;
@@ -670,6 +679,7 @@ _wrap_g_function_info_invoke(PyGIBaseInfo *self, PyObject *args)
}
in_args = g_newa(GArgument, n_in_args);
+ in_containers = g_newa(GArray *, n_in_containers);
out_args = g_newa(GArgument, n_out_args);
/* each out arg is a pointer, they point to these values */
/* FIXME: This will break for caller-allocates funcs:
@@ -719,6 +729,7 @@ _wrap_g_function_info_invoke(PyGIBaseInfo *self, PyObject *args)
{
guint in_args_pos = 0;
guint out_args_pos = 0;
+ gsize in_containers_pos = 0;
Py_ssize_t py_args_pos = 0;
if (is_method && !is_constructor) {
@@ -779,6 +790,7 @@ _wrap_g_function_info_invoke(PyGIBaseInfo *self, PyObject *args)
PyObject *py_arg;
GITypeInfo *arg_type_info;
GITypeTag arg_type_tag;
+ GITransfer transfer;
g_assert(in_args_pos < n_in_args);
if (direction == GI_DIRECTION_INOUT) {
@@ -793,13 +805,15 @@ _wrap_g_function_info_invoke(PyGIBaseInfo *self, PyObject *args)
}
arg_type_info = g_arg_info_get_type(arg_info);
+ transfer = g_arg_info_get_ownership_transfer(arg_info);
+
arg_type_tag = g_type_info_get_tag(arg_type_info);
g_assert(py_args_pos < n_py_args);
py_arg = PyTuple_GetItem(args, py_args_pos);
g_assert(py_arg != NULL);
- GArgument in_value = pygi_g_argument_from_py_object(py_arg, g_arg_info_get_type(arg_info));
+ GArgument in_value = pygi_g_argument_from_py_object(py_arg, arg_type_info, transfer);
if (PyErr_Occurred()) {
/* TODO: Release ressources allocated for previous arguments. */
@@ -809,6 +823,27 @@ _wrap_g_function_info_invoke(PyGIBaseInfo *self, PyObject *args)
return NULL;
}
+ if (transfer == GI_TRANSFER_CONTAINER && direction == GI_DIRECTION_IN) {
+ /* keep the items in another container. */
+ GArray *items;
+
+ switch (arg_type_tag) {
+ case GI_TYPE_TAG_ARRAY:
+ items = _g_array_values((GArray *)in_value.v_pointer);
+ break;
+ default:
+ items = NULL;
+ /* TODO */
+ break;
+ }
+
+ /* TODO: look for errors */
+
+ g_assert(in_containers_pos < n_in_containers);
+ in_containers[in_containers_pos] = items;
+ in_containers_pos += 1;
+ }
+
if (arg_type_tag == GI_TYPE_TAG_ARRAY) {
GArray *array;
gint length_arg_pos;
@@ -919,7 +954,7 @@ _wrap_g_function_info_invoke(PyGIBaseInfo *self, PyObject *args)
g_base_info_unref((GIBaseInfo *)item_type_info);
}
- return_value = pygi_g_argument_to_py_object(return_arg, return_info);
+ return_value = pygi_g_argument_to_py_object(&return_arg, return_info);
if (return_tag == GI_TYPE_TAG_ARRAY) {
return_arg.v_pointer = g_array_free((GArray *)return_arg.v_pointer, FALSE);
@@ -963,6 +998,7 @@ _wrap_g_function_info_invoke(PyGIBaseInfo *self, PyObject *args)
guint in_args_pos;
guint out_args_pos;
guint return_values_pos;
+ gsize in_containers_pos;
return_values_pos = 0;
@@ -989,97 +1025,109 @@ _wrap_g_function_info_invoke(PyGIBaseInfo *self, PyObject *args)
}
in_args_pos = is_method ? 1 : 0;
+ in_containers_pos = 0;
out_args_pos = 0;
for (i = 0; i < n_args; i++) {
GIDirection direction;
GIArgInfo *arg_info;
GITypeInfo *arg_type_info;
+ GITypeTag type_tag;
+ GITransfer transfer;
+ GArgument *arg;
arg_info = g_callable_info_get_arg(callable_info, i);
- arg_type_info = g_arg_info_get_type(arg_info);
direction = g_arg_info_get_direction(arg_info);
+ transfer = g_arg_info_get_ownership_transfer(arg_info);
+ arg_type_info = g_arg_info_get_type(arg_info);
+
+ type_tag = g_type_info_get_tag(arg_type_info);
if (direction == GI_DIRECTION_IN) {
- g_assert(in_args_pos < n_in_args);
+ arg = NULL;
- /* TODO: Release if allocated. */
+ if (transfer == GI_TRANSFER_CONTAINER) {
+ GArray *items;
- in_args_pos += 1;
- } else {
- PyObject *obj;
- GITypeTag type_tag;
- GArgument *arg;
+ g_assert(in_containers_pos < n_in_containers);
+ items = in_containers[in_containers_pos];
+ if (items != NULL) {
+ arg = (GArgument *)&items;
+ }
- if (direction == GI_DIRECTION_INOUT) {
- g_assert(in_args_pos < n_in_args);
+ in_containers_pos += 1;
}
- g_assert(out_args_pos < n_out_args);
- if (aux_args[i] != NULL) {
- if (direction == GI_DIRECTION_INOUT) {
- in_args_pos += 1;
- }
- out_args_pos += 1;
- g_base_info_unref((GIBaseInfo *)arg_type_info);
- g_base_info_unref((GIBaseInfo *)arg_info);
- continue;
+ if (arg == NULL) {
+ g_assert(in_args_pos < n_in_args);
+ arg = &in_args[in_args_pos];
}
-
+ in_args_pos += 1;
+ } else {
+ g_assert(out_args_pos < n_out_args);
arg = (GArgument *)out_args[out_args_pos].v_pointer;
+ if (direction == GI_DIRECTION_INOUT) {
+ in_args_pos += 1;
+ }
+ out_args_pos += 1;
+ }
- type_tag = g_type_info_get_tag(arg_type_info);
+ if (aux_args[i] != NULL) {
+ g_base_info_unref((GIBaseInfo *)arg_type_info);
+ g_base_info_unref((GIBaseInfo *)arg_info);
+ continue;
+ }
- if (type_tag == GI_TYPE_TAG_ARRAY) {
- /* Create a GArray. */
- GITypeInfo *item_type_info;
- GITypeTag item_type_tag;
- gsize item_size;
- gssize length;
- gboolean is_zero_terminated;
- GArray *array;
+ if (type_tag == GI_TYPE_TAG_ARRAY &&
+ !(direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_CONTAINER)) {
+ /* Create a GArray. */
+ GITypeInfo *item_type_info;
+ GITypeTag item_type_tag;
+ gsize item_size;
+ gssize length;
+ gboolean is_zero_terminated;
+ GArray *array;
- item_type_info = g_type_info_get_param_type(arg_type_info, 0);
- item_type_tag = g_type_info_get_tag(item_type_info);
- item_size = pygi_gi_type_tag_get_size(item_type_tag);
- is_zero_terminated = g_type_info_is_zero_terminated(arg_type_info);
+ item_type_info = g_type_info_get_param_type(arg_type_info, 0);
+ item_type_tag = g_type_info_get_tag(item_type_info);
+ item_size = pygi_gi_type_tag_get_size(item_type_tag);
+ is_zero_terminated = g_type_info_is_zero_terminated(arg_type_info);
- if (is_zero_terminated) {
- length = g_strv_length(arg->v_pointer);
- } else {
- length = g_type_info_get_array_fixed_size(arg_type_info);
- if (length < 0) {
- gint length_arg_pos;
- GArgument *length_arg;
+ if (is_zero_terminated) {
+ length = g_strv_length(arg->v_pointer);
+ } else {
+ length = g_type_info_get_array_fixed_size(arg_type_info);
+ if (length < 0) {
+ gint length_arg_pos;
+ GArgument *length_arg;
- length_arg_pos = g_type_info_get_array_length(arg_type_info);
- g_assert(length_arg_pos >= 0);
+ length_arg_pos = g_type_info_get_array_length(arg_type_info);
+ g_assert(length_arg_pos >= 0 && length_arg_pos < n_args);
- length_arg = aux_args[length_arg_pos];
- g_assert(length_arg != NULL);
+ length_arg = aux_args[length_arg_pos];
+ g_assert(length_arg != NULL);
- /* FIXME: Take into account the type of the argument. */
- length = length_arg->v_int;
- }
+ /* FIXME: Take into account the type of the argument. */
+ length = length_arg->v_int;
}
+ }
- array = g_array_new(is_zero_terminated, FALSE, item_size);
- array->data = arg->v_pointer;
- array->len = length;
-
- arg->v_pointer = array;
+ array = g_array_new(is_zero_terminated, FALSE, item_size);
+ array->data = arg->v_pointer;
+ array->len = length;
- g_base_info_unref((GIBaseInfo *)item_type_info);
- }
+ arg->v_pointer = array;
- obj = pygi_g_argument_to_py_object(*arg, arg_type_info);
+ g_base_info_unref((GIBaseInfo *)item_type_info);
+ }
- if (type_tag == GI_TYPE_TAG_ARRAY) {
- arg->v_pointer = g_array_free((GArray *)arg->v_pointer, FALSE);
- }
+ if (direction == GI_DIRECTION_INOUT || direction == GI_DIRECTION_OUT) {
+ PyObject *obj;
+ obj = pygi_g_argument_to_py_object(arg, arg_type_info);
g_assert(obj != NULL);
+
g_assert(return_values_pos < n_return_values);
if (n_return_values > 1) {
@@ -1093,13 +1141,11 @@ _wrap_g_function_info_invoke(PyGIBaseInfo *self, PyObject *args)
return_value = obj;
}
- if (direction == GI_DIRECTION_INOUT) {
- in_args_pos += 1;
- }
- out_args_pos += 1;
return_values_pos += 1;
}
+ pygi_g_argument_clean(arg, arg_type_info, transfer, direction);
+
g_base_info_unref((GIBaseInfo *)arg_type_info);
g_base_info_unref((GIBaseInfo *)arg_info);
}
@@ -1591,7 +1637,7 @@ _wrap_g_field_info_get_value(PyGIBaseInfo *self, PyObject *args)
}
g_argument_to_py_object:
- retval = pygi_g_argument_to_py_object(value, field_type_info);
+ retval = pygi_g_argument_to_py_object(&value, field_type_info);
return_:
g_base_info_unref((GIBaseInfo *)field_type_info);
@@ -1648,7 +1694,7 @@ _wrap_g_field_info_set_value(PyGIBaseInfo *self, PyObject *args)
goto return_;
}
- value = pygi_g_argument_from_py_object(py_value, field_type_info);
+ value = pygi_g_argument_from_py_object(py_value, field_type_info, GI_TRANSFER_NOTHING);
/* A few types are not handled by g_field_info_set_field, so do it here. */
if (!g_type_info_is_pointer(field_type_info)
diff --git a/tests/test_girepository.py b/tests/test_girepository.py
index e8f13ec..b5ca881 100644
--- a/tests/test_girepository.py
+++ b/tests/test_girepository.py
@@ -312,9 +312,6 @@ class TestGIEverything(unittest.TestCase):
def testArrayIntOut(self):
self.assertEquals((0, 1, 2, 3, 4), Everything.test_array_int_out())
- def testArrayIntReturn(self):
- self.assertEquals((0, 1, 2, 3, 4), Everything.test_array_int_full_out())
-
def testArrayInt8In(self):
self.assertEquals(5, Everything.test_array_gint8_in((1, 2, 3, -1)))
self.assertEquals(-1, Everything.test_array_gint8_in((INT8_MAX, INT8_MIN)))
@@ -397,6 +394,21 @@ class TestGIEverything(unittest.TestCase):
self.assertEquals((0, 1, 2, 3, 4), Everything.test_array_fixed_size_int_return())
+# Transfer tests
+
+ def testArrayIntInTake(self):
+ self.assertEquals(5, Everything.test_array_int_in_take((1, 2, 3, -1)))
+
+ def testStrvInContainer(self):
+ self.assertTrue(Everything.test_strv_in_container(test_sequence))
+
+ def testArrayIntFullOut(self):
+ self.assertEquals((0, 1, 2, 3, 4), Everything.test_array_int_full_out())
+
+ def testArrayIntNoneOut(self):
+ self.assertEquals((1, 2, 3, 4, 5), Everything.test_array_int_none_out())
+
+
# Interface
# GList
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]