[pygobject/gsoc2009: 67/160] Add basic ownership transfer for arrays and strings



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]