[pygobject/gsoc2009: 72/160] Too large commit to be descripted



commit 62b2d5b662dfed5e69181755f62d52563d116615
Author: Simon van der Linden <svdlinden src gnome org>
Date:   Mon Jul 27 14:38:37 2009 +0200

    Too large commit to be descripted
    
    Notably, the argument release code gained support for inout arguments.

 gi/pygargument.c |   23 +-
 gi/pygargument.h |   13 +-
 gi/pygiinfo.c    |  844 +++++++++++++++++++++++-------------------------------
 3 files changed, 372 insertions(+), 508 deletions(-)
---
diff --git a/gi/pygargument.c b/gi/pygargument.c
index 9b9be44..253147e 100644
--- a/gi/pygargument.c
+++ b/gi/pygargument.c
@@ -31,6 +31,7 @@ pygi_gi_registered_type_info_check_py_object(GIRegisteredTypeInfo *info,
         PyObject *object, gboolean is_instance)
 {
     gint retval;
+
     PyObject *type;
     gchar *type_name_expected;
 
@@ -214,7 +215,7 @@ pygi_gi_type_info_check_py_object(GITypeInfo *type_info, gboolean may_be_null, P
             pygi_gi_type_tag_get_py_bounds(type_tag, &lower, &upper);
             if (lower == NULL || upper == NULL) {
                 retval = -1;
-                goto check_number_clean;
+                goto check_number_release;
             }
 
             /* Check bounds */
@@ -224,14 +225,14 @@ pygi_gi_type_info_check_py_object(GITypeInfo *type_info, gboolean may_be_null, P
 
                 if (PyErr_Occurred()) {
                     retval = -1;
-                    goto check_number_error_clean;
+                    goto check_number_error_release;
                 }
 
                 lower_str = PyObject_Str(lower);
                 upper_str = PyObject_Str(upper);
                 if (lower_str == NULL || upper_str == NULL) {
                     retval = -1;
-                    goto check_number_error_clean;
+                    goto check_number_error_release;
                 }
 
                 PyErr_Format(PyExc_ValueError, "Must range from %s to %s",
@@ -240,12 +241,12 @@ pygi_gi_type_info_check_py_object(GITypeInfo *type_info, gboolean may_be_null, P
 
                 retval = 0;
 
-check_number_error_clean:
+check_number_error_release:
                 Py_XDECREF(lower_str);
                 Py_XDECREF(upper_str);
             }
 
-check_number_clean:
+check_number_release:
             Py_XDECREF(lower);
             Py_XDECREF(upper);
             break;
@@ -782,7 +783,7 @@ pygi_g_argument_from_py_object(PyObject *object, GITypeInfo *type_info, GITransf
 
 array_item_error:
                 /* Free everything we have converted so far. */
-                pygi_g_argument_clean((GArgument *)array, type_info,
+                pygi_g_argument_release((GArgument *)array, type_info,
                         GI_TRANSFER_NOTHING, GI_DIRECTION_IN);
                 array = NULL;
 
@@ -918,7 +919,7 @@ array_item_error:
 
 list_item_error:
                 /* Free everything we have converted so far. */
-                pygi_g_argument_clean((GArgument *)list, type_info,
+                pygi_g_argument_release((GArgument *)list, type_info,
                         GI_TRANSFER_NOTHING, GI_DIRECTION_IN);
                 list = NULL;
 
@@ -1026,7 +1027,7 @@ list_item_error:
 
 hash_table_item_error:
                 /* Free everything we have converted so far. */
-                pygi_g_argument_clean((GArgument *)hash_table, type_info,
+                pygi_g_argument_release((GArgument *)hash_table, type_info,
                         GI_TRANSFER_NOTHING, GI_DIRECTION_IN);
                 hash_table = NULL;
 
@@ -1369,7 +1370,7 @@ 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)
+pygi_g_argument_release(GArgument *arg, GITypeInfo *type_info, GITransfer transfer, GIDirection direction)
 {
     GITypeTag type_tag;
 
@@ -1436,12 +1437,12 @@ pygi_g_argument_clean(GArgument *arg, GITypeInfo *type_info, GITransfer transfer
                 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);
+                    pygi_g_argument_release(&item, item_type_info, item_transfer, direction);
                 }
             }
 
             if ((direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING)
-                    || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) {
+                    || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) {
                 g_array_free(array, TRUE);
             }
 
diff --git a/gi/pygargument.h b/gi/pygargument.h
index 570f9be..1c42861 100644
--- a/gi/pygargument.h
+++ b/gi/pygargument.h
@@ -30,6 +30,10 @@ G_BEGIN_DECLS
 
 gsize pygi_gi_type_tag_get_size(GITypeTag type_tag);
 
+gint pygi_gi_registered_type_info_check_py_object(GIRegisteredTypeInfo *info,
+                                                  PyObject *object,
+                                                  gboolean is_instance);
+
 gint pygi_gi_type_info_check_py_object(GITypeInfo *type_info,
                                        gboolean may_be_null,
                                        PyObject *object);
@@ -37,13 +41,14 @@ gint pygi_gi_type_info_check_py_object(GITypeInfo *type_info,
 GArgument pygi_g_argument_from_py_object(PyObject *object,
                                          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);
+void pygi_g_argument_release(GArgument *arg,
+                             GITypeInfo *type_info,
+                             GITransfer transfer,
+                             GIDirection direction);
 
 G_END_DECLS
 
diff --git a/gi/pygiinfo.c b/gi/pygiinfo.c
index 5c982f0..f81aceb 100644
--- a/gi/pygiinfo.c
+++ b/gi/pygiinfo.c
@@ -326,7 +326,7 @@ pygi_gi_base_info_get_fullname(GIBaseInfo *info) {
     }
 
     if (fullname == NULL) {
-        PyErr_SetString(PyExc_MemoryError, "Out of memory");
+        PyErr_NoMemory();
     }
 
     return fullname;
@@ -383,91 +383,147 @@ _wrap_g_function_info_is_method(PyGIBaseInfo *self)
                           GI_FUNCTION_IS_METHOD);
 }
 
+static
+GArray *
+pygi_g_array_from_array(gpointer array, GITypeInfo *type_info, GArgument *args[])
+{
+    /* Create a GArray. */
+    GITypeInfo *item_type_info;
+    gboolean is_zero_terminated;
+    GITypeTag item_type_tag;
+    gsize item_size;
+    gssize length;
+    GArray *g_array;
+
+    is_zero_terminated = g_type_info_is_zero_terminated(type_info);
+    item_type_info = g_type_info_get_param_type(type_info, 0);
+    g_assert(item_type_info != NULL);
+
+    item_type_tag = g_type_info_get_tag(item_type_info);
+    item_size = pygi_gi_type_tag_get_size(item_type_tag);
+
+    g_base_info_unref((GIBaseInfo *)item_type_info);
+
+    if (is_zero_terminated) {
+        length = g_strv_length(array);
+    } else {
+        length = g_type_info_get_array_fixed_size(type_info);
+        if (length < 0) {
+            gint length_arg_pos;
+
+            length_arg_pos = g_type_info_get_array_length(type_info);
+            g_assert(length_arg_pos >= 0);
+
+            /* FIXME: Take into account the type of the argument. */
+            length = args[length_arg_pos]->v_int;
+        }
+    }
+
+    g_array = g_array_new(is_zero_terminated, FALSE, item_size);
+    if (g_array == NULL) {
+        PyErr_NoMemory();
+        return NULL;
+    }
+
+    g_array->data = array;
+    g_array->len = length;
+
+    return g_array;
+}
+
 static PyObject *
-_wrap_g_function_info_invoke(PyGIBaseInfo *self, PyObject *args)
+_wrap_g_function_info_invoke(PyGIBaseInfo *self, PyObject *py_args)
 {
     gboolean is_method;
     gboolean is_constructor;
 
-    guint n_args;
-    guint n_in_args;
-    guint n_out_args;
-    gsize n_in_containers;
+    gsize n_args;
+    gsize n_in_args;
+    gsize n_out_args;
+    gsize n_containers;
     Py_ssize_t n_py_args;
     gsize n_aux_in_args;
     gsize n_aux_out_args;
-    guint n_return_values;
+    gsize n_return_values;
+
+    GIArgInfo **arg_infos;
+    GITypeInfo **arg_type_infos;
+    GITypeInfo *return_type_info;
+    GITypeTag return_type_tag;
 
-    GICallableInfo *callable_info;
-    GITypeInfo *return_info;
-    GITypeTag return_tag;
+    GArgument **args;
+    gboolean *args_is_auxiliary;
 
     GArgument *in_args;
     GArgument *out_args;
-    GArray **in_containers;
-    GArgument **aux_args;
     GArgument *out_values;
+    GArgument *containers;
     GArgument return_arg;
-    PyObject *return_value;
 
-    guint i;
+    PyObject *return_value = NULL;
 
-    callable_info = (GICallableInfo *)self->info;
+    gsize i;
 
     {
         GIFunctionInfoFlags flags;
 
-        flags = g_function_info_get_flags((GIFunctionInfo *)callable_info);
+        flags = g_function_info_get_flags((GIFunctionInfo *)self->info);
         is_method = (flags & GI_FUNCTION_IS_METHOD) != 0;
         is_constructor = (flags & GI_FUNCTION_IS_CONSTRUCTOR) != 0;
     }
 
     /* Count arguments. */
-    n_args = g_callable_info_get_n_args(callable_info);
-    n_py_args = PyTuple_Size(args);
-    n_in_args = is_method ? 1 : 0;  /* The first argument is the instance. */
+    n_args = g_callable_info_get_n_args((GICallableInfo *)self->info);
+    n_in_args = 0;
     n_out_args = 0;
-    n_in_containers = 0;
+    n_containers = 0;
     n_aux_in_args = 0;
     n_aux_out_args = 0;
-    aux_args = g_newa(GArgument *, n_args);
+
+    arg_infos = g_newa(GIArgInfo *, n_args);
+    arg_type_infos = g_newa(GITypeInfo *, n_args);
+
+    args_is_auxiliary = g_newa(gboolean, n_args);
+    memset(args_is_auxiliary, 0, sizeof(args_is_auxiliary));
+
+    if (is_method) {
+        /* The first argument is the instance. */
+        n_in_args += 1;
+    }
 
     for (i = 0; i < n_args; i++) {
         GIDirection direction;
-        GIArgInfo *arg_info;
-        GITypeInfo *arg_type_info;
-        GITypeTag arg_type_tag;
         GITransfer transfer;
+        GITypeTag arg_type_tag;
 
-        arg_info = g_callable_info_get_arg(callable_info, i);
+        arg_infos[i] = g_callable_info_get_arg((GICallableInfo *)self->info, i);
+        g_assert(arg_infos[i] != NULL);
 
-        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_infos[i] = g_arg_info_get_type(arg_infos[i]);
+        g_assert(arg_type_infos[i] != NULL);
 
-        arg_type_tag = g_type_info_get_tag(arg_type_info);
+        direction = g_arg_info_get_direction(arg_infos[i]);
+        transfer = g_arg_info_get_ownership_transfer(arg_infos[i]);
+        arg_type_tag = g_type_info_get_tag(arg_type_infos[i]);
 
         if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) {
             n_in_args += 1;
+            if (arg_type_tag == GI_TYPE_TAG_ARRAY
+                    && transfer == GI_TRANSFER_CONTAINER) {
+                n_containers += 1;
+            }
         }
         if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) {
             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;
 
-            length_arg_pos = g_type_info_get_array_length(arg_type_info);
-            if (length_arg_pos != -1) {
-                /* Tag the argument as auxiliary. Later, it'll be changed into a pointer to (in|out)_args[(in|out)_args_pos].
-                 * We cannot do it now since we don't know how much space to allocate (n_(in|out)_args) yet.
-                 */
-                aux_args[length_arg_pos] = (GArgument *)!NULL;
+            length_arg_pos = g_type_info_get_array_length(arg_type_infos[i]);
+            if (length_arg_pos >= 0) {
+                g_assert(length_arg_pos < n_args);
+                args_is_auxiliary[length_arg_pos] = TRUE;
 
                 if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) {
                     n_aux_in_args += 1;
@@ -477,199 +533,115 @@ _wrap_g_function_info_invoke(PyGIBaseInfo *self, PyObject *args)
                 }
             }
         }
-
-        g_base_info_unref((GIBaseInfo *)arg_type_info);
-        g_base_info_unref((GIBaseInfo *)arg_info);
     }
 
-    return_info = g_callable_info_get_return_type((GICallableInfo *)self->info);
-    return_tag = g_type_info_get_tag(return_info);
+    return_type_info = g_callable_info_get_return_type((GICallableInfo *)self->info);
+    g_assert(return_type_info != NULL);
+
+    return_type_tag = g_type_info_get_tag(return_type_info);
 
-    /* Tag the return value's auxiliary argument too, if applicable. */
-    if (return_tag == GI_TYPE_TAG_ARRAY) {
+    if (return_type_tag == GI_TYPE_TAG_ARRAY) {
         gint length_arg_pos;
-        length_arg_pos = g_type_info_get_array_length(return_info);
-        if (length_arg_pos != -1) {
-            aux_args[length_arg_pos] = (GArgument *)!NULL;
+        length_arg_pos = g_type_info_get_array_length(return_type_info);
+        if (length_arg_pos >= 0) {
+            g_assert(length_arg_pos < n_args);
+            args_is_auxiliary[length_arg_pos] = TRUE;
             n_aux_out_args += 1;
         }
     }
 
+    n_return_values = n_out_args - n_aux_out_args;
+    if (return_type_tag != GI_TYPE_TAG_VOID) {
+        n_return_values += 1;
+    }
+
     {
+        gsize n_py_args_expected;
         Py_ssize_t py_args_pos;
 
         /* Check the argument count. */
-        if (n_py_args != n_in_args + (is_constructor ? 1 : 0) - n_aux_in_args) {
-            g_base_info_unref((GIBaseInfo *)return_info);
-            PyErr_Format(PyExc_TypeError, "%s() takes exactly %zd argument(s) (%zd given)",
-                    pygi_gi_base_info_get_fullname(self->info),
-                    n_in_args + (is_constructor ? 1 : 0) - n_aux_in_args, n_py_args);
-            return NULL;
+        n_py_args = PyTuple_Size(py_args);
+        g_assert(n_py_args >= 0);
+
+        n_py_args_expected = n_in_args + (is_constructor ? 1 : 0) - n_aux_in_args;
+
+        if (n_py_args != n_py_args_expected) {
+            gchar *fullname;
+            fullname = pygi_gi_base_info_get_fullname(self->info);
+            if (fullname != NULL) {
+                PyErr_Format(PyExc_TypeError,
+                    "%s() takes exactly %zd argument(s) (%zd given)",
+                    fullname, n_py_args_expected, n_py_args);
+                g_free(fullname);
+            }
+            goto return_;
         }
 
         /* Check argument types. */
         py_args_pos = 0;
-        if (is_constructor) {
-            PyObject *py_arg;
-
-            g_assert(n_py_args > 0);
-            py_arg = PyTuple_GetItem(args, py_args_pos);
-            g_assert(py_arg != NULL);
-
-            if (!PyType_Check(py_arg)) {
-                PyErr_Format(PyExc_TypeError, "%s() argument %zd: Must be type, not %s",
-                    pygi_gi_base_info_get_fullname(self->info), py_args_pos,
-                    ((PyTypeObject *)py_arg)->tp_name);
-            } else if (!PyType_IsSubtype((PyTypeObject *)py_arg, &PyGObject_Type)) {
-                PyErr_Format(PyExc_TypeError, "%s() argument %zd: Must be a non-strict subclass of %s",
-                    pygi_gi_base_info_get_fullname(self->info), py_args_pos,
-                    PyGObject_Type.tp_name);
-            } else {
-                GIBaseInfo *interface_info;
-                GType interface_g_type;
-                GType arg_g_type;
-
-                interface_info = g_type_info_get_interface(return_info);
-
-                interface_g_type = g_registered_type_info_get_g_type((GIRegisteredTypeInfo *)interface_info);
-                arg_g_type = pyg_type_from_object(py_arg);
-
-                if (!g_type_is_a(arg_g_type, interface_g_type)) {
-                    PyErr_Format(PyExc_TypeError, "%s() argument %zd: Must be a non-strict subclass of %s",
-                        pygi_gi_base_info_get_fullname(self->info), py_args_pos,
-                        g_type_name(interface_g_type));
-                }
-
-                g_base_info_unref(interface_info);
-            }
-
-            if (PyErr_Occurred()) {
-                g_base_info_unref((GIBaseInfo *)return_info);
-                return NULL;
-            }
-
-            py_args_pos += 1;
-        } else if (is_method) {
-            PyObject *py_arg;
+        if (is_constructor || is_method) {
             GIBaseInfo *container_info;
-            GIInfoType container_info_type;
-
-            g_assert(n_py_args > 0);
-            py_arg = PyTuple_GetItem(args, py_args_pos);
-            g_assert(py_arg != NULL);
+            PyObject *py_arg;
+            gint retval;
 
             container_info = g_base_info_get_container(self->info);
-            container_info_type = g_base_info_get_type(container_info);
+            g_assert(container_info != NULL);
 
-            /* FIXME: this could take place in pygi_g_argument_from_py_object, but we need to create an
-               independant function because it needs a GITypeInfo to be passed. */
-
-            switch(container_info_type) {
-                case GI_INFO_TYPE_OBJECT:
-                {
-                    PyObject *py_type;
-                    GType container_g_type;
-                    GType arg_g_type;
-
-                    py_type = PyObject_Type(py_arg);
-                    g_assert(py_type != NULL);
-
-                    container_g_type = g_registered_type_info_get_g_type((GIRegisteredTypeInfo *)container_info);
-                    arg_g_type = pyg_type_from_object(py_arg);
-
-                    /* Note: If the first argument is not an instance, its type hasn't got a gtype. */
-                    if (!g_type_is_a(arg_g_type, container_g_type)) {
-                        PyErr_Format(PyExc_TypeError, "%s() argument %zd: Must be %s, not %s",
-                            pygi_gi_base_info_get_fullname(self->info), py_args_pos,
-                            g_base_info_get_name(container_info), ((PyTypeObject *)py_type)->tp_name);
-                    }
-
-                    Py_DECREF(py_type);
-
-                    break;
-                }
-                case GI_INFO_TYPE_BOXED:
-                case GI_INFO_TYPE_STRUCT:
-                {
-                    GIBaseInfo *info;
-
-                    info = pyg_base_info_from_object(py_arg);
-                    if (info == NULL || !g_base_info_equals(info, container_info)) {
-                        PyObject *py_type;
-
-                        py_type = PyObject_Type(py_arg);
-                        g_assert(py_type != NULL);
-
-                        PyErr_Format(PyExc_TypeError, "%s() argument %zd: Must be %s, not %s",
-                            pygi_gi_base_info_get_fullname(self->info), py_args_pos,
-                            g_base_info_get_name(container_info), ((PyTypeObject *)py_type)->tp_name);
-
-                        Py_DECREF(py_type);
-                    }
+            g_assert(py_args_pos < n_py_args);
+            py_arg = PyTuple_GET_ITEM(py_args, py_args_pos);
 
-                    if (info != NULL) {
-                        g_base_info_unref(info);
-                    }
+            /* AFAIK, only registered types can have constructors or methods,
+             * so the cast should be safe. */
+            retval = pygi_gi_registered_type_info_check_py_object(
+                    (GIRegisteredTypeInfo *)container_info, py_arg, is_method);
 
-                    break;
+            if (retval < 0) {
+                goto return_;
+            } else if (!retval) {
+                gchar *fullname;
+                fullname = pygi_gi_base_info_get_fullname(self->info);
+                if (fullname != NULL) {
+                    PyErr_PREFIX_FROM_FORMAT("%s() argument %zd: ", fullname, py_args_pos);
+                    g_free(fullname);
                 }
-                case GI_INFO_TYPE_UNION:
-                    /* TODO */
-                default:
-                    /* The other info types haven't got methods. */
-                    g_assert_not_reached();
-            }
-
-            if (PyErr_Occurred()) {
-                return NULL;
+                goto return_;
             }
 
             py_args_pos += 1;
         }
+
         for (i = 0; i < n_args; i++) {
-            GIArgInfo *arg_info;
-            GITypeInfo *type_info;
             GIDirection direction;
             gboolean may_be_null;
             PyObject *py_arg;
             gint retval;
 
-            if (aux_args[i] != NULL) {
-                /* No check needed for auxiliary arguments. */
-                continue;
-            }
+            direction = g_arg_info_get_direction(arg_infos[i]);
 
-            arg_info = g_callable_info_get_arg(callable_info, i);
-            direction = g_arg_info_get_direction(arg_info);
-            if (!(direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)) {
-                g_base_info_unref((GIBaseInfo *)arg_info);
+            if (direction == GI_DIRECTION_OUT || args_is_auxiliary[i]) {
                 continue;
             }
 
             g_assert(py_args_pos < n_py_args);
+            py_arg = PyTuple_GET_ITEM(py_args, py_args_pos);
 
-            py_arg = PyTuple_GetItem(args, py_args_pos);
-            g_assert(py_arg != NULL);
-
-            type_info = g_arg_info_get_type(arg_info);
-            may_be_null = g_arg_info_may_be_null(arg_info);
-
-            retval = pygi_gi_type_info_check_py_object(type_info, may_be_null, py_arg);
+            may_be_null = g_arg_info_may_be_null(arg_infos[i]);
 
-            g_base_info_unref((GIBaseInfo *)type_info);
-            g_base_info_unref((GIBaseInfo *)arg_info);
+            retval = pygi_gi_type_info_check_py_object(arg_type_infos[i],
+                    may_be_null, py_arg);
 
             if (retval < 0) {
-                g_base_info_unref((GIBaseInfo *)return_info);
-                return NULL;
-            }
-
-            if (!retval) {
-                g_base_info_unref((GIBaseInfo *)return_info);
-                PyErr_PREFIX_FROM_FORMAT("%s() argument %zd: ",
+                goto return_;
+            } else if (!retval) {
+                gchar *fullname;
+                fullname = pygi_gi_base_info_get_fullname(self->info);
+                if (fullname != NULL) {
+                    PyErr_PREFIX_FROM_FORMAT("%s() argument %zd: ",
                         pygi_gi_base_info_get_fullname(self->info),
                         py_args_pos);
-                return NULL;
+                    g_free(fullname);
+                }
+                goto return_;
             }
 
             py_args_pos += 1;
@@ -678,15 +650,13 @@ _wrap_g_function_info_invoke(PyGIBaseInfo *self, PyObject *args)
         g_assert(py_args_pos == n_py_args);
     }
 
+    args = g_newa(GArgument *, n_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:
-       http://bugzilla.gnome.org/show_bug.cgi?id=573314 */
     out_values = g_newa(GArgument, n_out_args);
+    containers = g_newa(GArgument, n_containers);
 
-    /* Link aux_args to in_args. */
+    /* Bind args so we can use an unique index. */
     {
         gsize in_args_pos;
         gsize out_args_pos;
@@ -695,291 +665,221 @@ _wrap_g_function_info_invoke(PyGIBaseInfo *self, PyObject *args)
         out_args_pos = 0;
 
         for (i = 0; i < n_args; i++) {
-            GIArgInfo *arg_info;
             GIDirection direction;
 
-            arg_info = g_callable_info_get_arg((GICallableInfo *)self->info, i);
-            direction = g_arg_info_get_direction(arg_info);
+            direction = g_arg_info_get_direction(arg_infos[i]);
 
-            if (direction == GI_DIRECTION_IN) {
-                if (aux_args[i] != NULL) {
+            switch (direction) {
+                case GI_DIRECTION_IN:
+                    g_assert(in_args_pos < n_in_args);
+                    args[i] = &in_args[in_args_pos];
+                    in_args_pos += 1;
+                    break;
+                case GI_DIRECTION_INOUT:
                     g_assert(in_args_pos < n_in_args);
-                    aux_args[i] = &in_args[in_args_pos];
-                }
-                in_args_pos += 1;
-            } else {
-                if (aux_args[i] != NULL) {
                     g_assert(out_args_pos < n_out_args);
-                    aux_args[i] = &out_values[out_args_pos];
-                }
-                out_args_pos += 1;
-                if (direction == GI_DIRECTION_INOUT) {
+                    in_args[in_args_pos].v_pointer = &out_values[out_args_pos];
                     in_args_pos += 1;
-                }
+                case GI_DIRECTION_OUT:
+                    g_assert(out_args_pos < n_out_args);
+                    out_args[out_args_pos].v_pointer = &out_values[out_args_pos];
+                    args[i] = &out_values[out_args_pos];
+                    out_args_pos += 1;
             }
-
-            g_base_info_unref((GIBaseInfo *)arg_info);
         }
 
         g_assert(in_args_pos == n_in_args);
         g_assert(out_args_pos == n_out_args);
     }
 
-    /* Get the arguments. */
+    /* Convert the input arguments. */
     {
-        guint in_args_pos = 0;
-        guint out_args_pos = 0;
-        gsize in_containers_pos = 0;
-        Py_ssize_t py_args_pos = 0;
+        Py_ssize_t py_args_pos;
+        gsize containers_pos;
 
-        if (is_method && !is_constructor) {
+        py_args_pos = 0;
+        containers_pos = 0;
+
+        if (is_constructor) {
+            /* Skip the first argument. */
+            py_args_pos += 1;
+        } else if (is_method) {
             /* Get the instance. */
-            GIBaseInfo *container;
+            GIBaseInfo *container_info;
             GIInfoType container_info_type;
             PyObject *py_arg;
 
-            container = g_base_info_get_container((GIBaseInfo *)callable_info);
-            container_info_type = g_base_info_get_type(container);
-
-            py_arg = PyTuple_GetItem(args, py_args_pos);
-            g_assert(py_arg != NULL);
-
-            if (py_arg == Py_None) {
-                in_args[in_args_pos].v_pointer = NULL;
-            } else if (container_info_type == GI_INFO_TYPE_STRUCT || container_info_type == GI_INFO_TYPE_BOXED) {
-                PyObject *py_buffer;
-                PyBufferProcs *py_buffer_procs;
-                py_buffer = PyObject_GetAttrString((PyObject *)py_arg, "__buffer__");
-                if (py_buffer == NULL) {
-                    g_base_info_unref(container);
-                    g_base_info_unref((GIBaseInfo *)return_info);
-                    return NULL;
+            container_info = g_base_info_get_container(self->info);
+            container_info_type = g_base_info_get_type(container_info);
+
+            g_assert(py_args_pos < n_py_args);
+            py_arg = PyTuple_GET_ITEM(py_args, py_args_pos);
+
+            g_assert(n_in_args > 0);
+            switch(container_info_type) {
+                case GI_INFO_TYPE_UNION:
+                    /* TODO */
+                    g_assert_not_reached();
+                    break;
+                case GI_INFO_TYPE_STRUCT:
+                {
+                    gsize size;
+                    in_args[0].v_pointer = pygi_py_object_get_buffer(py_arg, &size);
+                    break;
                 }
-                py_buffer_procs = py_buffer->ob_type->tp_as_buffer;
-                (*py_buffer_procs->bf_getreadbuffer)(py_buffer, 0, &in_args[in_args_pos].v_pointer);
-            } else { /* by fallback is always object */
-                in_args[in_args_pos].v_pointer = pygobject_get(py_arg);
+                case GI_INFO_TYPE_OBJECT:
+                    in_args[0].v_pointer = pygobject_get(py_arg);
+                    break;
+                default:
+                    /* Other types don't have methods. */
+                    g_assert_not_reached();
             }
 
-            g_base_info_unref(container);
-
-            in_args_pos += 1;
-            py_args_pos += 1;
-        } else if (is_constructor) {
-            /* Skip the first argument. */
             py_args_pos += 1;
         }
 
         for (i = 0; i < n_args; i++) {
             GIDirection direction;
-            GIArgInfo *arg_info;
-            GArgument *out_value = NULL;
-
-            arg_info = g_callable_info_get_arg(callable_info, i);
-            direction = g_arg_info_get_direction(arg_info);
-
-            if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) {
-                g_assert(out_args_pos < n_out_args);
 
-                out_value = &out_values[out_args_pos];
-                out_args[out_args_pos].v_pointer = out_value;
-                out_args_pos += 1;
+            if (args_is_auxiliary[i]) {
+                continue;
             }
 
+            direction = g_arg_info_get_direction(arg_infos[i]);
+
             if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) {
                 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) {
-                    in_args[in_args_pos].v_pointer = out_value;
-                }
-
-                if (aux_args[i] != NULL) {
-                    /* Auxiliary argument has already been set or will be set later. */
-                    in_args_pos += 1;
-                    g_base_info_unref((GIBaseInfo *)arg_info);
-                    continue;
-                }
-
-                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);
+                transfer = g_arg_info_get_ownership_transfer(arg_infos[i]);
 
                 g_assert(py_args_pos < n_py_args);
-                py_arg = PyTuple_GetItem(args, py_args_pos);
-                g_assert(py_arg != NULL);
+                py_arg = PyTuple_GET_ITEM(py_args, py_args_pos);
 
-                GArgument in_value = pygi_g_argument_from_py_object(py_arg, arg_type_info, transfer);
+                *args[i] = pygi_g_argument_from_py_object(py_arg, arg_type_infos[i],
+                        transfer);
 
                 if (PyErr_Occurred()) {
                     /* TODO: Release ressources allocated for previous arguments. */
-                    g_base_info_unref((GIBaseInfo *)arg_type_info);
-                    g_base_info_unref((GIBaseInfo *)arg_info);
-                    g_base_info_unref((GIBaseInfo *)return_info);
                     return NULL;
                 }
 
-                if (transfer == GI_TRANSFER_CONTAINER && direction == GI_DIRECTION_IN) {
-                    /* keep the items in another container. */
-                    GArray *items;
-
-                    switch (arg_type_tag) {
+                arg_type_tag = g_type_info_get_tag(arg_type_infos[i]);
+
+                if ((direction == GI_DIRECTION_INOUT && transfer != GI_TRANSFER_EVERYTHING)
+                        || (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_CONTAINER)) {
+                    /* We need to keep a copy of the container to be able to
+                     * release the items after the call. */
+                    g_assert(containers_pos < n_containers);
+                    switch(arg_type_tag) {
+                        case GI_TYPE_TAG_FILENAME:
+                        case GI_TYPE_TAG_UTF8:
+                            containers[containers_pos].v_string = args[i]->v_pointer;
                         case GI_TYPE_TAG_ARRAY:
-                            items = _g_array_values((GArray *)in_value.v_pointer);
-                            break;
+                            containers[containers_pos].v_pointer = g_array_copy(args[i]->v_pointer);
                         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;
+                    containers_pos += 1;
                 }
 
                 if (arg_type_tag == GI_TYPE_TAG_ARRAY) {
                     GArray *array;
-                    gint length_arg_pos;
-
-                    array = in_value.v_pointer;
+                    gssize length_arg_pos;
 
-                    length_arg_pos = g_type_info_get_array_length(arg_type_info);
-                    if (length_arg_pos != -1) {
-                        GArgument *length_arg;
+                    array = args[i]->v_pointer;
 
-                        length_arg = aux_args[length_arg_pos];
-                        g_assert(length_arg != NULL);
-                        length_arg->v_size = array->len;
+                    length_arg_pos = g_type_info_get_array_length(arg_type_infos[i]);
+                    if (length_arg_pos >= 0) {
+                        /* Set the auxiliary argument holding the length. */
+                        args[length_arg_pos]->v_size = array->len;
                     }
 
                     /* Get rid of the GArray. */
-                    in_value.v_pointer = g_array_free(array, FALSE);
+                    args[i]->v_pointer = g_array_free(array, FALSE);
                 }
 
-                if (direction == GI_DIRECTION_IN) {
-                    /* Pass the value. */
-                    in_args[in_args_pos] = in_value;
-                } else {
-                    /* Pass a pointer to the value. */
-                    g_assert(out_value != NULL);
-                    *out_value = in_value;
-                }
-
-                g_base_info_unref((GIBaseInfo *)arg_type_info);
-
-                in_args_pos += 1;
                 py_args_pos += 1;
             }
-
-            g_base_info_unref((GIBaseInfo *)arg_info);
         }
 
-        g_assert(in_args_pos == n_in_args);
-        g_assert(out_args_pos == n_out_args);
         g_assert(py_args_pos == n_py_args);
     }
 
     /* Invoke the callable. */
     {
         GError *error;
+        gint retval;
 
         error = NULL;
 
-        if (!g_function_info_invoke((GIFunctionInfo *)callable_info,
-                    in_args, n_in_args,
-                    out_args, n_out_args,
-                    &return_arg,
-                    &error)) {
-            g_base_info_unref((GIBaseInfo *)return_info);
-            PyErr_Format(PyExc_RuntimeError, "Error invoking %s.%s(): %s",
-                    g_base_info_get_namespace((GIBaseInfo *)callable_info),
-                    g_base_info_get_name((GIBaseInfo *)callable_info),
-                    error->message);
+        retval = g_function_info_invoke((GIFunctionInfo *)self->info,
+                in_args, n_in_args, out_args, n_out_args, &return_arg, &error);
+        if (!retval) {
+            gchar *fullname;
+
+            g_assert(error != NULL);
+
+            fullname = pygi_gi_base_info_get_fullname(self->info);
+            if (fullname != NULL) {
+                PyErr_Format(PyExc_RuntimeError, "Error invoking %s(): %s",
+                    fullname, error->message);
+            }
+
             g_error_free(error);
-            return NULL;
+            /* TODO */
+            goto return_;
         }
     }
 
-    n_return_values = n_out_args - n_aux_out_args;
-    if (return_tag != GI_TYPE_TAG_VOID) {
-        n_return_values += 1;
+    /* Convert the return value. */
+    if (is_constructor) {
+        PyTypeObject *type;
 
-        if (!is_constructor) {
-            if (return_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;
-
-                item_type_info = g_type_info_get_param_type(return_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(return_info);
-
-                if (is_zero_terminated) {
-                    length = g_strv_length(return_arg.v_pointer);
-                } else {
-                    length = g_type_info_get_array_fixed_size(return_info);
-                    if (length < 0) {
-                        gint length_arg_pos;
-                        GArgument *length_arg;
+        g_assert(n_py_args > 0);
+        type = (PyTypeObject *)PyTuple_GET_ITEM(py_args, 0);
 
-                        length_arg_pos = g_type_info_get_array_length(return_info);
-                        g_assert(length_arg_pos >= 0);
+        return_value = pygobject_new_from_type(return_arg.v_pointer, TRUE, type);
+    } else {
+        GITransfer transfer;
 
-                        length_arg = aux_args[length_arg_pos];
-                        g_assert(length_arg != NULL);
+        if (return_type_tag == GI_TYPE_TAG_ARRAY) {
+            GArray *array;
 
-                        /* 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 = return_arg.v_pointer;
-                array->len = length;
-                
-                return_arg.v_pointer = array;
-
-                g_base_info_unref((GIBaseInfo *)item_type_info);
+            array = pygi_g_array_from_array(return_arg.v_pointer, return_type_info, args);
+            if (array == NULL) {
+                /* TODO */
+                goto return_;
             }
 
-            return_value = pygi_g_argument_to_py_object(&return_arg, return_info);
+            return_arg.v_pointer = array;
+        }
 
-            if (return_tag == GI_TYPE_TAG_ARRAY) {
-                return_arg.v_pointer = g_array_free((GArray *)return_arg.v_pointer, FALSE);
-            }
+        return_value = pygi_g_argument_to_py_object(&return_arg, return_type_info);
+        if (return_value == NULL) {
+            /* TODO */
+            goto return_;
+        }
 
-            g_assert(return_value != NULL);
-        } else {
-            PyTypeObject *type;
+        transfer = g_callable_info_get_caller_owns((GICallableInfo *)self->info);
 
-            g_assert(n_py_args > 0);
-            type = (PyTypeObject *)PyTuple_GET_ITEM(args, 0);
+        pygi_g_argument_release(&return_arg, return_type_info, transfer,
+            GI_DIRECTION_OUT);
 
-            return_value = pygobject_new_from_type(return_arg.v_pointer, TRUE, type);
+        if (return_type_tag == GI_TYPE_TAG_ARRAY
+                && transfer == GI_TRANSFER_NOTHING) {
+            /* We created a #GArray, so free it. */
+            return_arg.v_pointer = g_array_free(return_arg.v_pointer, FALSE);
         }
-    } else {
-        return_value = NULL;
     }
 
-    /* Get output arguments and release input arguments. */
+    /* Convert output arguments and release arguments. */
     {
-        guint in_args_pos;
-        guint out_args_pos;
-        guint return_values_pos;
-        gsize in_containers_pos;
+        gsize containers_pos;
+        gsize return_values_pos;
 
+        containers_pos = 0;
         return_values_pos = 0;
 
         if (n_return_values > 1) {
@@ -988,11 +888,14 @@ _wrap_g_function_info_invoke(PyGIBaseInfo *self, PyObject *args)
 
             return_values = PyTuple_New(n_return_values);
             if (return_values == NULL) {
-                g_base_info_unref((GIBaseInfo *)return_info);
+                /* TODO */
                 return NULL;
             }
 
-            if (return_tag != GI_TYPE_TAG_VOID) {
+            if (return_type_tag == GI_TYPE_TAG_VOID) {
+                /* The current return value is None. */
+                Py_DECREF(return_value);
+            } else {
                 /* Put the return value first. */
                 int retval;
                 g_assert(return_value != NULL);
@@ -1004,144 +907,99 @@ _wrap_g_function_info_invoke(PyGIBaseInfo *self, PyObject *args)
             return_value = return_values;
         }
 
-        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);
-
-            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) {
-                arg = NULL;
-
-                if (transfer == GI_TRANSFER_CONTAINER) {
-                    GArray *items;
-
-                    g_assert(in_containers_pos < n_in_containers);
-                    items = in_containers[in_containers_pos];
-                    if (items != NULL) {
-                        arg = (GArgument *)&items;
-                    }
-
-                    in_containers_pos += 1;
-                }
-
-                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;
-            }
 
-            if (aux_args[i] != NULL) {
-                g_base_info_unref((GIBaseInfo *)arg_type_info);
-                g_base_info_unref((GIBaseInfo *)arg_info);
+            if (args_is_auxiliary[i]) {
+                /* Auxiliary arguments are handled at the same time as their
+                 * relatives. */
                 continue;
             }
 
-            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);
-
-                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;
+            direction = g_arg_info_get_direction(arg_infos[i]);
+            transfer = g_arg_info_get_ownership_transfer(arg_infos[i]);
 
-                        length_arg_pos = g_type_info_get_array_length(arg_type_info);
-                        g_assert(length_arg_pos >= 0 && length_arg_pos < n_args);
+            type_tag = g_type_info_get_tag(arg_type_infos[i]);
 
-                        length_arg = aux_args[length_arg_pos];
-                        g_assert(length_arg != NULL);
+            if (type_tag == GI_TYPE_TAG_ARRAY
+                    && (direction != GI_DIRECTION_IN || transfer == GI_TRANSFER_NOTHING)) {
+                GArray *array;
 
-                        /* FIXME: Take into account the type of the argument. */
-                        length = length_arg->v_int;
-                    }
+                array = pygi_g_array_from_array(args[i]->v_pointer, arg_type_infos[i], args);
+                if (array == NULL) {
+                    /* TODO */
+                    goto return_;
                 }
 
-                array = g_array_new(is_zero_terminated, FALSE, item_size);
-                array->data = arg->v_pointer;
-                array->len = length;
-
-                arg->v_pointer = array;
-
-                g_base_info_unref((GIBaseInfo *)item_type_info);
+                args[i]->v_pointer = array;
             }
 
             if (direction == GI_DIRECTION_INOUT || direction == GI_DIRECTION_OUT) {
+                /* Convert the argument. */
                 PyObject *obj;
 
-                obj = pygi_g_argument_to_py_object(arg, arg_type_info);
-                g_assert(obj != NULL);
+                obj = pygi_g_argument_to_py_object(args[i], arg_type_infos[i]);
+                if (obj == NULL) {
+                    /* TODO */
+                    goto return_;
+                }
 
                 g_assert(return_values_pos < n_return_values);
 
                 if (n_return_values > 1) {
-                    int retval;
-                    g_assert(return_value != NULL);
-
-                    retval = PyTuple_SetItem(return_value, return_values_pos, obj);
-                    g_assert(retval == 0);
+                    PyTuple_SET_ITEM(return_value, return_values_pos, obj);
                 } else {
-                    g_assert(return_value == NULL);
+                    /* The current return value is None. */
+                    Py_DECREF(return_value);
                     return_value = obj;
                 }
 
                 return_values_pos += 1;
             }
 
-            pygi_g_argument_clean(arg, arg_type_info, transfer, direction);
+            /* Release the argument. */
+            if (direction == GI_DIRECTION_INOUT) {
+                if (transfer != GI_TRANSFER_EVERYTHING) {
+                    g_assert(containers_pos < n_containers);
+                    pygi_g_argument_release(&containers[containers_pos], arg_type_infos[i],
+                        transfer, GI_DIRECTION_IN);
+                    containers_pos += 1;
+                }
+                if (transfer != GI_TRANSFER_NOTHING) {
+                    pygi_g_argument_release(args[i], arg_type_infos[i], transfer,
+                        GI_DIRECTION_OUT);
+                }
+            } else if (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_CONTAINER) {
+                g_assert(containers_pos < n_containers);
+                pygi_g_argument_release(&containers[containers_pos], arg_type_infos[i],
+                    transfer, direction);
+                containers_pos += 1;
+            } else {
+                pygi_g_argument_release(args[i], arg_type_infos[i], transfer, direction);
+            }
 
-            g_base_info_unref((GIBaseInfo *)arg_type_info);
-            g_base_info_unref((GIBaseInfo *)arg_info);
+            if (type_tag == GI_TYPE_TAG_ARRAY
+                    && (direction != GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING)) {
+                /* We created a #GArray and it has not been released above, so free it. */
+                args[i]->v_pointer = g_array_free(args[i]->v_pointer, FALSE);
+            }
         }
 
-        if (n_return_values > 1) {
-            g_assert(return_values_pos == n_return_values);
-        }
-        g_assert(out_args_pos == n_out_args);
-        g_assert(in_args_pos == n_in_args);
+        g_assert(n_return_values <= 1 || return_values_pos == n_return_values);
     }
 
-    g_base_info_unref((GIBaseInfo *)return_info);
+return_:
+    g_base_info_unref((GIBaseInfo *)return_type_info);
+
+    for (i = 0; i < n_args; i++) {
+        g_base_info_unref((GIBaseInfo *)arg_type_infos[i]);
+        g_base_info_unref((GIBaseInfo *)arg_infos[i]);
+    }
 
-    if (return_value == NULL) {
-        Py_INCREF(Py_None);
-        return_value = Py_None;
+    if (PyErr_Occurred()) {
+        Py_CLEAR(return_value);
     }
 
     return return_value;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]