[pygobject] cache refactoring: Move GArray arg setup and marshaling into new file



commit c45cafd07fc62ad545f3e58f2b7350ee4b2bb9b7
Author: Simon Feltman <sfeltman src gnome org>
Date:   Sat Oct 12 03:07:53 2013 -0700

    cache refactoring: Move GArray arg setup and marshaling into new file
    
    Move GArray argument caching and marshaling fragments into an
    isolated file: pygi-array.c.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=709700

 gi/Makefile.am            |    2 +
 gi/pygi-array.c           |  906 +++++++++++++++++++++++++++++++++++++++++++++
 gi/pygi-array.h           |   42 ++
 gi/pygi-cache.c           |  236 +-----------
 gi/pygi-marshal-cleanup.c |  150 --------
 gi/pygi-marshal-cleanup.h |   10 -
 gi/pygi-marshal-from-py.c |  354 ------------------
 gi/pygi-marshal-from-py.h |    6 -
 gi/pygi-marshal-to-py.c   |  210 -----------
 gi/pygi-marshal-to-py.h   |    4 -
 10 files changed, 963 insertions(+), 957 deletions(-)
---
diff --git a/gi/Makefile.am b/gi/Makefile.am
index bd884cc..df4e803 100644
--- a/gi/Makefile.am
+++ b/gi/Makefile.am
@@ -107,6 +107,8 @@ _gi_la_SOURCES = \
        pygi-basictype.h \
        pygi-list.c \
        pygi-list.h \
+       pygi-array.c \
+       pygi-array.h \
        pygi-hashtable.c \
        pygi-hashtable.h
 _gi_la_CFLAGS = \
diff --git a/gi/pygi-array.c b/gi/pygi-array.c
new file mode 100644
index 0000000..7b51584
--- /dev/null
+++ b/gi/pygi-array.c
@@ -0,0 +1,906 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2011 John (J5) Palmieri <johnp redhat com>
+ * Copyright (C) 2014 Simon Feltman <sfeltman gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <Python.h>
+#include <pyglib-python-compat.h>
+
+#include "pygi-array.h"
+#include "pygi-private.h"
+#include "pygi-marshal-cleanup.h"
+
+/*
+ * GArray to Python
+ */
+
+static gboolean
+gi_argument_from_py_ssize_t (GIArgument   *arg_out,
+                             Py_ssize_t    size_in,
+                             GITypeTag     type_tag)
+{
+    switch (type_tag) {
+    case GI_TYPE_TAG_VOID:
+    case GI_TYPE_TAG_BOOLEAN:
+        goto unhandled_type;
+
+    case GI_TYPE_TAG_INT8:
+        if (size_in >= G_MININT8 && size_in <= G_MAXINT8) {
+            arg_out->v_int8 = size_in;
+            return TRUE;
+        } else {
+            goto overflow;
+        }
+
+    case GI_TYPE_TAG_UINT8:
+        if (size_in >= 0 && size_in <= G_MAXUINT8) {
+            arg_out->v_uint8 = size_in;
+            return TRUE;
+        } else {
+            goto overflow;
+        }
+
+    case GI_TYPE_TAG_INT16:
+        if (size_in >= G_MININT16 && size_in <= G_MAXINT16) {
+            arg_out->v_int16 = size_in;
+            return TRUE;
+        } else {
+            goto overflow;
+        }
+
+    case GI_TYPE_TAG_UINT16:
+        if (size_in >= 0 && size_in <= G_MAXUINT16) {
+            arg_out->v_uint16 = size_in;
+            return TRUE;
+        } else {
+            goto overflow;
+        }
+
+        /* Ranges assume two's complement */
+    case GI_TYPE_TAG_INT32:
+        if (size_in >= G_MININT32 && size_in <= G_MAXINT32) {
+            arg_out->v_int32 = size_in;
+            return TRUE;
+        } else {
+            goto overflow;
+        }
+
+    case GI_TYPE_TAG_UINT32:
+        if (size_in >= 0 && size_in <= G_MAXUINT32) {
+            arg_out->v_uint32 = size_in;
+            return TRUE;
+        } else {
+            goto overflow;
+        }
+
+    case GI_TYPE_TAG_INT64:
+        arg_out->v_int64 = size_in;
+        return TRUE;
+
+    case GI_TYPE_TAG_UINT64:
+        if (size_in >= 0) {
+            arg_out->v_uint64 = size_in;
+            return TRUE;
+        } else {
+            goto overflow;
+        }
+
+    case GI_TYPE_TAG_FLOAT:
+    case GI_TYPE_TAG_DOUBLE:
+    case GI_TYPE_TAG_GTYPE:
+    case GI_TYPE_TAG_UTF8:
+    case GI_TYPE_TAG_FILENAME:
+    case GI_TYPE_TAG_ARRAY:
+    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:
+    case GI_TYPE_TAG_UNICHAR:
+    default:
+        goto unhandled_type;
+    }
+
+ overflow:
+    PyErr_Format (PyExc_OverflowError,
+                  "Unable to marshal C Py_ssize_t %zd to %s",
+                  size_in,
+                  g_type_tag_to_string (type_tag));
+    return FALSE;
+
+ unhandled_type:
+    PyErr_Format (PyExc_TypeError,
+                  "Unable to marshal C Py_ssize_t %zd to %s",
+                  size_in,
+                  g_type_tag_to_string (type_tag));
+    return FALSE;
+}
+
+static gboolean
+gi_argument_to_gsize (GIArgument *arg_in,
+                      gsize      *gsize_out,
+                      GITypeTag   type_tag)
+{
+    switch (type_tag) {
+      case GI_TYPE_TAG_INT8:
+          *gsize_out = arg_in->v_int8;
+          return TRUE;
+      case GI_TYPE_TAG_UINT8:
+          *gsize_out = arg_in->v_uint8;
+          return TRUE;
+      case GI_TYPE_TAG_INT16:
+          *gsize_out = arg_in->v_int16;
+          return TRUE;
+      case GI_TYPE_TAG_UINT16:
+          *gsize_out = arg_in->v_uint16;
+          return TRUE;
+      case GI_TYPE_TAG_INT32:
+          *gsize_out = arg_in->v_int32;
+          return TRUE;
+      case GI_TYPE_TAG_UINT32:
+          *gsize_out = arg_in->v_uint32;
+          return TRUE;
+      case GI_TYPE_TAG_INT64:
+          *gsize_out = arg_in->v_int64;
+          return TRUE;
+      case GI_TYPE_TAG_UINT64:
+          *gsize_out = arg_in->v_uint64;
+          return TRUE;
+      default:
+          PyErr_Format (PyExc_TypeError,
+                        "Unable to marshal %s to gsize",
+                        g_type_tag_to_string (type_tag));
+          return FALSE;
+    }
+}
+
+static gboolean
+_pygi_marshal_from_py_array (PyGIInvokeState   *state,
+                             PyGICallableCache *callable_cache,
+                             PyGIArgCache      *arg_cache,
+                             PyObject          *py_arg,
+                             GIArgument        *arg,
+                             gpointer          *cleanup_data)
+{
+    PyGIMarshalFromPyFunc from_py_marshaller;
+    int i = 0;
+    int success_count = 0;
+    Py_ssize_t length;
+    gssize item_size;
+    gboolean is_ptr_array;
+    GArray *array_ = NULL;
+    PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
+    PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache;
+
+
+    if (py_arg == Py_None) {
+        arg->v_pointer = NULL;
+        return TRUE;
+    }
+
+    if (!PySequence_Check (py_arg)) {
+        PyErr_Format (PyExc_TypeError, "Must be sequence, not %s",
+                      py_arg->ob_type->tp_name);
+        return FALSE;
+    }
+
+    length = PySequence_Length (py_arg);
+    if (length < 0)
+        return FALSE;
+
+    if (array_cache->fixed_size >= 0 &&
+            array_cache->fixed_size != length) {
+        PyErr_Format (PyExc_ValueError, "Must contain %zd items, not %zd",
+                      array_cache->fixed_size, length);
+
+        return FALSE;
+    }
+
+    item_size = array_cache->item_size;
+    is_ptr_array = (array_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY);
+    if (is_ptr_array) {
+        array_ = (GArray *)g_ptr_array_sized_new (length);
+    } else {
+        array_ = g_array_sized_new (array_cache->is_zero_terminated,
+                                    TRUE,
+                                    item_size,
+                                    length);
+    }
+
+    if (array_ == NULL) {
+        PyErr_NoMemory ();
+        return FALSE;
+    }
+
+    if (sequence_cache->item_cache->type_tag == GI_TYPE_TAG_UINT8 &&
+        PYGLIB_PyBytes_Check (py_arg)) {
+        memcpy(array_->data, PYGLIB_PyBytes_AsString (py_arg), length);
+        array_->len = length;
+        if (array_cache->is_zero_terminated) {
+            /* If array_ has been created with zero_termination, space for the
+             * terminator is properly allocated, so we're not off-by-one here. */
+            array_->data[length] = '\0';
+        }
+        goto array_success;
+    }
+
+    from_py_marshaller = sequence_cache->item_cache->from_py_marshaller;
+    for (i = 0, success_count = 0; i < length; i++) {
+        GIArgument item = {0};
+        gpointer item_cleanup_data = NULL;
+        PyObject *py_item = PySequence_GetItem (py_arg, i);
+        if (py_item == NULL)
+            goto err;
+
+        if (!from_py_marshaller ( state,
+                                  callable_cache,
+                                  sequence_cache->item_cache,
+                                  py_item,
+                                 &item,
+                                 &item_cleanup_data)) {
+            Py_DECREF (py_item);
+            goto err;
+        }
+        Py_DECREF (py_item);
+
+        if (item_cleanup_data != NULL && item_cleanup_data != item.v_pointer) {
+            /* We only support one level of data discrepancy between an items
+             * data and its cleanup data. This is because we only track a single
+             * extra cleanup data pointer per-argument and cannot track the entire
+             * array of items differing data and cleanup_data.
+             * For example, this would fail if trying to marshal an array of
+             * callback closures marked with SCOPE call type where the cleanup data
+             * is different from the items v_pointer, likewise an array of arrays.
+             */
+            PyErr_SetString(PyExc_RuntimeError, "Cannot cleanup item data for array due to "
+                                                "the items data its cleanup data being different.");
+            goto err;
+        }
+
+        /* FIXME: it is much more efficent to have seperate marshaller
+         *        for ptr arrays than doing the evaluation
+         *        and casting each loop iteration
+         */
+        if (is_ptr_array) {
+            g_ptr_array_add((GPtrArray *)array_, item.v_pointer);
+        } else if (sequence_cache->item_cache->is_pointer) {
+            /* if the item is a pointer, simply copy the pointer */
+            g_assert (item_size == sizeof (item.v_pointer));
+            g_array_insert_val (array_, i, item);
+        } else if (sequence_cache->item_cache->type_tag == GI_TYPE_TAG_INTERFACE) {
+            /* Special case handling of flat arrays of gvalue/boxed/struct */
+            PyGIInterfaceCache *item_iface_cache = (PyGIInterfaceCache *) sequence_cache->item_cache;
+            GIBaseInfo *base_info = (GIBaseInfo *) item_iface_cache->interface_info;
+            GIInfoType info_type = g_base_info_get_type (base_info);
+
+            switch (info_type) {
+                case GI_INFO_TYPE_UNION:
+                case GI_INFO_TYPE_STRUCT:
+                {
+                    PyGIArgCache *item_arg_cache = (PyGIArgCache *)item_iface_cache;
+                    PyGIMarshalCleanupFunc from_py_cleanup = item_arg_cache->from_py_cleanup;
+
+                    if (g_type_is_a (item_iface_cache->g_type, G_TYPE_VALUE)) {
+                        /* Special case GValue flat arrays to properly init and copy the contents. */
+                        GValue* dest = (GValue*) (array_->data + (i * item_size));
+                        if (item.v_pointer != NULL) {
+                            memset (dest, 0, item_size);
+                            g_value_init (dest, G_VALUE_TYPE ((GValue*) item.v_pointer));
+                            g_value_copy ((GValue*) item.v_pointer, dest);
+                        }
+                        /* Manually increment the length because we are manually setting the memory. */
+                        array_->len++;
+
+                    } else {
+                        /* Handles flat arrays of boxed or struct types. */
+                        g_array_insert_vals (array_, i, item.v_pointer, 1);
+                    }
+
+                    /* Cleanup any memory left by the per-item marshaler because
+                     * _pygi_marshal_cleanup_from_py_array will not know about this
+                     * due to "item" being a temporarily marshaled value done on the stack.
+                     */
+                    if (from_py_cleanup)
+                        from_py_cleanup (state, item_arg_cache, py_item, item_cleanup_data, TRUE);
+
+                    break;
+                }
+                default:
+                    g_array_insert_val (array_, i, item);
+            }
+        } else {
+            /* default value copy of a simple type */
+            g_array_insert_val (array_, i, item);
+        }
+
+        success_count++;
+        continue;
+err:
+        if (sequence_cache->item_cache->from_py_cleanup != NULL) {
+            gsize j;
+            PyGIMarshalCleanupFunc cleanup_func =
+                sequence_cache->item_cache->from_py_cleanup;
+
+            /* Only attempt per item cleanup on pointer items */
+            if (sequence_cache->item_cache->is_pointer) {
+                for(j = 0; j < success_count; j++) {
+                    PyObject *py_item = PySequence_GetItem (py_arg, j);
+                    cleanup_func (state,
+                                  sequence_cache->item_cache,
+                                  py_item,
+                                  is_ptr_array ?
+                                          g_ptr_array_index ((GPtrArray *)array_, j) :
+                                          g_array_index (array_, gpointer, j),
+                                  TRUE);
+                    Py_DECREF (py_item);
+                }
+            }
+        }
+
+        if (is_ptr_array)
+            g_ptr_array_free ( ( GPtrArray *)array_, TRUE);
+        else
+            g_array_free (array_, TRUE);
+        _PyGI_ERROR_PREFIX ("Item %i: ", i);
+        return FALSE;
+    }
+
+array_success:
+    if (array_cache->len_arg_index >= 0) {
+        /* we have an child arg to handle */
+        PyGIArgCache *child_cache =
+            _pygi_callable_cache_get_arg (callable_cache, array_cache->len_arg_index);
+
+        if (child_cache->direction == PYGI_DIRECTION_BIDIRECTIONAL) {
+            gint *len_arg = (gint *)state->in_args[child_cache->c_arg_index].v_pointer;
+            /* if we are not setup yet just set the in arg */
+            if (len_arg == NULL) {
+                if (!gi_argument_from_py_ssize_t (&state->in_args[child_cache->c_arg_index],
+                                                  length,
+                                                  child_cache->type_tag)) {
+                    goto err;
+                }
+            } else {
+                *len_arg = length;
+            }
+        } else {
+            if (!gi_argument_from_py_ssize_t (&state->in_args[child_cache->c_arg_index],
+                                              length,
+                                              child_cache->type_tag)) {
+                goto err;
+            }
+        }
+    }
+
+    if (array_cache->array_type == GI_ARRAY_TYPE_C) {
+        /* In the case of GI_ARRAY_C, we give the data directly as the argument
+         * but keep the array_ wrapper as cleanup data so we don't have to find
+         * it's length again.
+         */
+        arg->v_pointer = array_->data;
+
+        if (arg_cache->transfer == GI_TRANSFER_EVERYTHING) {
+            g_array_free (array_, FALSE);
+            *cleanup_data = NULL;
+        } else {
+            *cleanup_data = array_;
+        }
+    } else {
+        arg->v_pointer = array_;
+
+        if (arg_cache->transfer == GI_TRANSFER_NOTHING) {
+            /* Free everything in cleanup. */
+            *cleanup_data = array_;
+        } else if (arg_cache->transfer == GI_TRANSFER_CONTAINER) {
+            /* Make a shallow copy so we can free the elements later in cleanup
+             * because it is possible invoke will free the list before our cleanup. */
+            *cleanup_data = is_ptr_array ?
+                    (gpointer)g_ptr_array_ref ((GPtrArray *)array_) :
+                    (gpointer)g_array_ref (array_);
+        } else { /* GI_TRANSFER_EVERYTHING */
+            /* No cleanup, everything is given to the callee. */
+            *cleanup_data = NULL;
+        }
+    }
+
+    return TRUE;
+}
+
+static void
+_pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state,
+                                     PyGIArgCache    *arg_cache,
+                                     PyObject        *py_arg,
+                                     gpointer         data,
+                                     gboolean         was_processed)
+{
+    if (was_processed) {
+        GArray *array_ = NULL;
+        GPtrArray *ptr_array_ = NULL;
+        PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
+        PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache;
+
+        if (array_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
+            ptr_array_ = (GPtrArray *) data;
+        } else {
+            array_ = (GArray *) data;
+        }
+
+        /* clean up items first */
+        if (sequence_cache->item_cache->from_py_cleanup != NULL) {
+            gsize i;
+            guint len = (array_ != NULL) ? array_->len : ptr_array_->len;
+            PyGIMarshalCleanupFunc cleanup_func =
+                sequence_cache->item_cache->from_py_cleanup;
+
+            for (i = 0; i < len; i++) {
+                gpointer item;
+                PyObject *py_item = NULL;
+
+                /* case 1: GPtrArray */
+                if (ptr_array_ != NULL)
+                    item = g_ptr_array_index (ptr_array_, i);
+                /* case 2: C array or GArray with object pointers */
+                else if (sequence_cache->item_cache->is_pointer)
+                    item = g_array_index (array_, gpointer, i);
+                /* case 3: C array or GArray with simple types or structs */
+                else {
+                    item = array_->data + i * array_cache->item_size;
+                    /* special-case hack: GValue array items do not get slice
+                     * allocated in _pygi_marshal_from_py_array(), so we must
+                     * not try to deallocate it as a slice and thus
+                     * short-circuit cleanup_func. */
+                    if (cleanup_func == _pygi_marshal_cleanup_from_py_interface_struct_gvalue) {
+                        g_value_unset ((GValue*) item);
+                        continue;
+                    }
+                }
+
+                py_item = PySequence_GetItem (py_arg, i);
+                cleanup_func (state, sequence_cache->item_cache, py_item, item, TRUE);
+                Py_XDECREF (py_item);
+            }
+        }
+
+        /* Only free the array when we didn't transfer ownership */
+        if (array_cache->array_type == GI_ARRAY_TYPE_C) {
+            /* always free the GArray wrapper created in from_py marshaling and
+             * passed back as cleanup_data
+             */
+            g_array_free (array_, arg_cache->transfer == GI_TRANSFER_NOTHING);
+        } else {
+            if (array_ != NULL)
+                g_array_unref (array_);
+            else
+                g_ptr_array_unref (ptr_array_);
+        }
+    }
+}
+
+/*
+ * GArray from Python
+ */
+static PyObject *
+_pygi_marshal_to_py_array (PyGIInvokeState   *state,
+                           PyGICallableCache *callable_cache,
+                           PyGIArgCache      *arg_cache,
+                           GIArgument        *arg)
+{
+    GArray *array_;
+    PyObject *py_obj = NULL;
+    PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
+    PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache;
+    gsize processed_items = 0;
+
+     /* GArrays make it easier to iterate over arrays
+      * with different element sizes but requires that
+      * we allocate a GArray if the argument was a C array
+      */
+    if (array_cache->array_type == GI_ARRAY_TYPE_C) {
+        gsize len;
+        if (array_cache->fixed_size >= 0) {
+            g_assert(arg->v_pointer != NULL);
+            len = array_cache->fixed_size;
+        } else if (array_cache->is_zero_terminated) {
+            if (arg->v_pointer == NULL) {
+                len = 0;
+            } else if (seq_cache->item_cache->type_tag == GI_TYPE_TAG_UINT8) {
+                len = strlen (arg->v_pointer);
+            } else {
+                len = g_strv_length ((gchar **)arg->v_pointer);
+            }
+        } else {
+            GIArgument *len_arg = state->args[array_cache->len_arg_index];
+            PyGIArgCache *arg_cache = _pygi_callable_cache_get_arg (callable_cache,
+                                                                    array_cache->len_arg_index);
+
+            if (!gi_argument_to_gsize (len_arg, &len, arg_cache->type_tag)) {
+                return NULL;
+            }
+        }
+
+        array_ = g_array_new (FALSE,
+                              FALSE,
+                              array_cache->item_size);
+        if (array_ == NULL) {
+            PyErr_NoMemory ();
+
+            if (arg_cache->transfer == GI_TRANSFER_EVERYTHING && arg->v_pointer != NULL)
+                g_free (arg->v_pointer);
+
+            return NULL;
+        }
+
+        if (array_->data != NULL)
+            g_free (array_->data);
+        array_->data = arg->v_pointer;
+        array_->len = len;
+    } else {
+        array_ = arg->v_pointer;
+    }
+
+    if (seq_cache->item_cache->type_tag == GI_TYPE_TAG_UINT8) {
+        if (arg->v_pointer == NULL) {
+            py_obj = PYGLIB_PyBytes_FromString ("");
+        } else {
+            py_obj = PYGLIB_PyBytes_FromStringAndSize (array_->data, array_->len);
+        }
+    } else {
+        if (arg->v_pointer == NULL) {
+            py_obj = PyList_New (0);
+        } else {
+            int i;
+
+            gsize item_size;
+            PyGIMarshalToPyFunc item_to_py_marshaller;
+            PyGIArgCache *item_arg_cache;
+
+            py_obj = PyList_New (array_->len);
+            if (py_obj == NULL)
+                goto err;
+
+
+            item_arg_cache = seq_cache->item_cache;
+            item_to_py_marshaller = item_arg_cache->to_py_marshaller;
+
+            item_size = g_array_get_element_size (array_);
+
+            for (i = 0; i < array_->len; i++) {
+                GIArgument item_arg = {0};
+                PyObject *py_item;
+
+                /* If we are receiving an array of pointers, simply assign the pointer
+                 * and move on, letting the per-item marshaler deal with the
+                 * various transfer modes and ref counts (e.g. g_variant_ref_sink).
+                 */
+                if (array_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
+                    item_arg.v_pointer = g_ptr_array_index ( ( GPtrArray *)array_, i);
+
+                } else if (item_arg_cache->is_pointer) {
+                    item_arg.v_pointer = g_array_index (array_, gpointer, i);
+
+                } else if (item_arg_cache->type_tag == GI_TYPE_TAG_INTERFACE) {
+                    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *) item_arg_cache;
+
+                    // FIXME: This probably doesn't work with boxed types or gvalues. See fx. 
_pygi_marshal_from_py_array()
+                    switch (g_base_info_get_type (iface_cache->interface_info)) {
+                        case GI_INFO_TYPE_STRUCT:
+                            if (arg_cache->transfer == GI_TRANSFER_EVERYTHING &&
+                                       !g_type_is_a (iface_cache->g_type, G_TYPE_BOXED)) {
+                                /* array elements are structs */
+                                gpointer *_struct = g_malloc (item_size);
+                                memcpy (_struct, array_->data + i * item_size,
+                                        item_size);
+                                item_arg.v_pointer = _struct;
+                            } else {
+                                item_arg.v_pointer = array_->data + i * item_size;
+                            }
+                            break;
+                        default:
+                            item_arg.v_pointer = g_array_index (array_, gpointer, i);
+                            break;
+                    }
+                } else {
+                    memcpy (&item_arg, array_->data + i * item_size, item_size);
+                }
+
+                py_item = item_to_py_marshaller ( state,
+                                                callable_cache,
+                                                item_arg_cache,
+                                                &item_arg);
+
+                if (py_item == NULL) {
+                    Py_CLEAR (py_obj);
+
+                    if (array_cache->array_type == GI_ARRAY_TYPE_C)
+                        g_array_unref (array_);
+
+                    goto err;
+                }
+                PyList_SET_ITEM (py_obj, i, py_item);
+                processed_items++;
+            }
+        }
+    }
+
+    if (array_cache->array_type == GI_ARRAY_TYPE_C)
+        g_array_free (array_, FALSE);
+
+    return py_obj;
+
+err:
+    if (array_cache->array_type == GI_ARRAY_TYPE_C) {
+        g_array_free (array_, arg_cache->transfer == GI_TRANSFER_EVERYTHING);
+    } else {
+        /* clean up unprocessed items */
+        if (seq_cache->item_cache->to_py_cleanup != NULL) {
+            int j;
+            PyGIMarshalCleanupFunc cleanup_func = seq_cache->item_cache->to_py_cleanup;
+            for (j = processed_items; j < array_->len; j++) {
+                cleanup_func (state,
+                              seq_cache->item_cache,
+                              NULL,
+                              g_array_index (array_, gpointer, j),
+                              FALSE);
+            }
+        }
+
+        if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
+            g_array_free (array_, TRUE);
+    }
+
+    return NULL;
+}
+
+static GArray*
+_wrap_c_array (PyGIInvokeState   *state,
+               PyGIArgGArray     *array_cache,
+               gpointer           data)
+{
+    GArray *array_;
+    gsize   len = 0;
+
+    if (array_cache->fixed_size >= 0) {
+        len = array_cache->fixed_size;
+    } else if (array_cache->is_zero_terminated) {
+        len = g_strv_length ((gchar **)data);
+    } else if (array_cache->len_arg_index >= 0) {
+        GIArgument *len_arg = state->args[array_cache->len_arg_index];
+        len = len_arg->v_long;
+    }
+
+    array_ = g_array_new (FALSE,
+                          FALSE,
+                          array_cache->item_size);
+
+    if (array_ == NULL)
+        return NULL;
+
+    g_free (array_->data);
+    array_->data = data;
+    array_->len = len;
+
+    return array_;
+}
+
+static void
+_pygi_marshal_cleanup_to_py_array (PyGIInvokeState *state,
+                                   PyGIArgCache    *arg_cache,
+                                   PyObject        *dummy,
+                                   gpointer         data,
+                                   gboolean         was_processed)
+{
+    if (arg_cache->transfer == GI_TRANSFER_EVERYTHING ||
+        arg_cache->transfer == GI_TRANSFER_CONTAINER) {
+        GArray *array_ = NULL;
+        GPtrArray *ptr_array_ = NULL;
+        PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
+        PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache;
+
+        /* If this isn't a garray create one to help process variable sized
+           array elements */
+        if (array_cache->array_type == GI_ARRAY_TYPE_C) {
+            array_ = _wrap_c_array (state, array_cache, data);
+
+            if (array_ == NULL)
+                return;
+
+        } else if (array_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
+            ptr_array_ = (GPtrArray *) data;
+        } else {
+            array_ = (GArray *) data;
+        }
+
+        if (sequence_cache->item_cache->to_py_cleanup != NULL) {
+            gsize i;
+            guint len = (array_ != NULL) ? array_->len : ptr_array_->len;
+
+            PyGIMarshalCleanupFunc cleanup_func = sequence_cache->item_cache->to_py_cleanup;
+            for (i = 0; i < len; i++) {
+                cleanup_func (state,
+                              sequence_cache->item_cache,
+                              NULL,
+                              (array_ != NULL) ? g_array_index (array_, gpointer, i) : g_ptr_array_index 
(ptr_array_, i),
+                              was_processed);
+            }
+        }
+
+        if (array_ != NULL)
+            g_array_free (array_, TRUE);
+        else
+            g_ptr_array_free (ptr_array_, TRUE);
+    }
+}
+
+static void
+_array_cache_free_func (PyGIArgGArray *cache)
+{
+    if (cache != NULL) {
+        _pygi_arg_cache_free (((PyGISequenceCache *)cache)->item_cache);
+        g_slice_free (PyGIArgGArray, cache);
+    }
+}
+
+PyGIArgCache*
+pygi_arg_garray_len_arg_setup (PyGIArgCache *arg_cache,
+                               GITypeInfo *type_info,
+                               PyGICallableCache *callable_cache,
+                               PyGIDirection direction,
+                               gssize arg_index,
+                               gssize *py_arg_index)
+{
+    PyGIArgGArray *seq_cache = (PyGIArgGArray *)arg_cache;
+
+    /* attempt len_arg_index setup for the first time */
+    if (seq_cache->len_arg_index < 0) {
+        seq_cache->len_arg_index = g_type_info_get_array_length (type_info);
+
+        /* offset by self arg for methods and vfuncs */
+        if (seq_cache->len_arg_index >= 0 && callable_cache != NULL &&
+                (callable_cache->function_type == PYGI_FUNCTION_TYPE_METHOD ||
+                 callable_cache->function_type == PYGI_FUNCTION_TYPE_VFUNC)) {
+            seq_cache->len_arg_index += 1;
+        }
+    }
+
+    if (seq_cache->len_arg_index >= 0) {
+        PyGIArgCache *child_cache = NULL;
+
+        child_cache = _pygi_callable_cache_get_arg (callable_cache,
+                                                    seq_cache->len_arg_index);
+        if (child_cache == NULL) {
+            child_cache = _arg_cache_alloc ();
+        } else {
+            /* If the "length" arg cache already exists (the length comes before
+             * the array in the argument list), remove it from the to_py_args list
+             * because it does not belong in "to python" return tuple. The length
+             * will implicitly be a part of the returned Python list.
+             */
+            if (direction & PYGI_DIRECTION_TO_PYTHON) {
+                callable_cache->to_py_args =
+                    g_slist_remove (callable_cache->to_py_args, child_cache);
+            }
+
+            /* This is a case where the arg cache already exists and has been
+             * setup by another array argument sharing the same length argument.
+             * See: gi_marshalling_tests_multi_array_key_value_in
+             */
+            if (child_cache->meta_type == PYGI_META_ARG_TYPE_CHILD)
+                return child_cache;
+        }
+
+        /* There is a length argument for this array, so increment the number
+         * of "to python" child arguments when applicable.
+         */
+        if (direction & PYGI_DIRECTION_TO_PYTHON)
+             callable_cache->n_to_py_child_args++;
+
+        child_cache->meta_type = PYGI_META_ARG_TYPE_CHILD;
+        child_cache->direction = direction;
+        child_cache->to_py_marshaller = NULL;
+        child_cache->from_py_marshaller = NULL;
+
+        /* ugly edge case code:
+         *
+         * When the length comes before the array parameter we need to update
+         * indexes of arguments after the index argument.
+         */
+        if (seq_cache->len_arg_index < arg_index && direction & PYGI_DIRECTION_FROM_PYTHON) {
+            gssize i;
+            (*py_arg_index) -= 1;
+            callable_cache->n_py_args -= 1;
+
+            for (i = seq_cache->len_arg_index + 1;
+                   i < _pygi_callable_cache_args_len (callable_cache); i++) {
+                PyGIArgCache *update_cache = _pygi_callable_cache_get_arg (callable_cache, i);
+                if (update_cache == NULL)
+                    break;
+
+                update_cache->py_arg_index -= 1;
+            }
+        }
+
+        _pygi_callable_cache_set_arg (callable_cache, seq_cache->len_arg_index, child_cache);
+        return child_cache;
+    }
+
+    return NULL;
+}
+
+static gboolean
+pygi_arg_garray_setup (PyGIArgGArray      *sc,
+                       GITypeInfo         *type_info,
+                       GIArgInfo          *arg_info,    /* may be NULL for return arguments */
+                       GITransfer          transfer,
+                       PyGIDirection       direction)
+{
+    GITypeInfo *item_type_info;
+    PyGIArgCache *arg_cache = (PyGIArgCache *)sc;
+
+    if (!pygi_arg_sequence_setup ((PyGISequenceCache *)sc,
+                                  type_info,
+                                  arg_info,
+                                  transfer,
+                                  direction)) {
+        return FALSE;
+    }
+
+    ((PyGIArgCache *)sc)->destroy_notify = (GDestroyNotify)_array_cache_free_func;
+    sc->array_type = g_type_info_get_array_type (type_info);
+    sc->is_zero_terminated = g_type_info_is_zero_terminated (type_info);
+    sc->fixed_size = g_type_info_get_array_fixed_size (type_info);
+    sc->len_arg_index = -1;  /* setup by pygi_arg_garray_len_arg_setup */
+
+    item_type_info = g_type_info_get_param_type (type_info, 0);
+    sc->item_size = _pygi_g_type_info_size (item_type_info);
+    g_base_info_unref ( (GIBaseInfo *)item_type_info);
+
+    if (direction & PYGI_DIRECTION_FROM_PYTHON) {
+        arg_cache->from_py_marshaller = _pygi_marshal_from_py_array;
+        arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_array;
+    }
+
+    if (direction & PYGI_DIRECTION_TO_PYTHON) {
+        arg_cache->to_py_marshaller = _pygi_marshal_to_py_array;
+        arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_array;
+    }
+
+    return TRUE;
+}
+
+PyGIArgCache *
+pygi_arg_garray_new_from_info (GITypeInfo *type_info,
+                               GIArgInfo *arg_info,
+                               GITransfer transfer,
+                               PyGIDirection direction)
+{
+    PyGIArgGArray *array_cache = g_slice_new0 (PyGIArgGArray);
+    if (array_cache == NULL)
+        return NULL;
+
+    if (!pygi_arg_garray_setup (array_cache,
+                                type_info,
+                                arg_info,
+                                transfer,
+                                direction)) {
+        _pygi_arg_cache_free ( (PyGIArgCache *)array_cache);
+        return NULL;
+    }
+
+    return (PyGIArgCache *)array_cache;
+}
diff --git a/gi/pygi-array.h b/gi/pygi-array.h
new file mode 100644
index 0000000..4792ca1
--- /dev/null
+++ b/gi/pygi-array.h
@@ -0,0 +1,42 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2014 Simon Feltman <sfeltman gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __PYGI_ARRAY_H__
+#define __PYGI_ARRAY_H__
+
+#include <girepository.h>
+#include "pygi-cache.h"
+
+G_BEGIN_DECLS
+
+PyGIArgCache *pygi_arg_garray_new_from_info  (GITypeInfo    *type_info,
+                                              GIArgInfo     *arg_info,   /* may be null */
+                                              GITransfer     transfer,
+                                              PyGIDirection  direction);
+
+PyGIArgCache *pygi_arg_garray_len_arg_setup  (PyGIArgCache      *arg_cache,
+                                              GITypeInfo        *type_info,
+                                              PyGICallableCache *callable_cache,
+                                              PyGIDirection      direction,
+                                              gssize             arg_index,
+                                              gssize            *py_arg_index);
+
+G_END_DECLS
+
+#endif /*__PYGI_ARRAY_H__*/
diff --git a/gi/pygi-cache.c b/gi/pygi-cache.c
index ecd1eae..8158c37 100644
--- a/gi/pygi-cache.c
+++ b/gi/pygi-cache.c
@@ -30,6 +30,7 @@
 #include "pygi-hashtable.h"
 #include "pygi-basictype.h"
 #include "pygi-list.h"
+#include "pygi-array.h"
 
 
 PyGIArgCache * _arg_cache_new_for_interface (GIInterfaceInfo *iface_info,
@@ -161,15 +162,6 @@ _sequence_cache_free_func (PyGISequenceCache *cache)
 }
 
 static void
-_array_cache_free_func (PyGIArgGArray *cache)
-{
-    if (cache != NULL) {
-        _pygi_arg_cache_free (((PyGISequenceCache *)cache)->item_cache);
-        g_slice_free (PyGIArgGArray, cache);
-    }
-}
-
-static void
 _callback_cache_free_func (PyGICallbackCache *cache)
 {
     if (cache != NULL) {
@@ -255,80 +247,6 @@ pygi_arg_sequence_setup (PyGISequenceCache  *sc,
     return TRUE;
 }
 
-static gboolean
-pygi_arg_garray_setup (PyGIArgGArray      *sc,
-                       GITypeInfo         *type_info,
-                       GIArgInfo          *arg_info,    /* may be NULL for return arguments */
-                       GITransfer          transfer,
-                       PyGIDirection       direction,
-                       gssize              child_offset)
-{
-    GITypeInfo *item_type_info;
-
-    if (!pygi_arg_sequence_setup ((PyGISequenceCache *)sc,
-                                  type_info,
-                                  arg_info,
-                                  transfer,
-                                  direction)) {
-        return FALSE;
-    }
-
-    ((PyGIArgCache *)sc)->destroy_notify = (GDestroyNotify)_array_cache_free_func;
-    sc->is_zero_terminated = g_type_info_is_zero_terminated (type_info);
-    sc->fixed_size = g_type_info_get_array_fixed_size (type_info);
-    sc->len_arg_index = g_type_info_get_array_length (type_info);
-    if (sc->len_arg_index >= 0)
-        sc->len_arg_index += child_offset;
-
-    item_type_info = g_type_info_get_param_type (type_info, 0);
-    sc->item_size = _pygi_g_type_info_size (item_type_info);
-    g_base_info_unref ( (GIBaseInfo *)item_type_info);
-
-    return TRUE;
-}
-
-static PyGISequenceCache *
-pygi_arg_sequence_new (GITypeInfo *type_info,
-                       GIArgInfo *arg_info,
-                       GITransfer transfer,
-                       PyGIDirection direction)
-{
-    PyGISequenceCache *sc = g_slice_new0 (PyGISequenceCache);
-    if (sc == NULL)
-        return NULL;
-
-    if (!pygi_arg_sequence_setup (sc, type_info, arg_info, transfer, direction)) {
-        _pygi_arg_cache_free ( (PyGIArgCache *)sc);
-        return NULL;
-    }
-
-    return sc;
-}
-
-static PyGIArgGArray *
-_arg_array_cache_new (GITypeInfo *type_info,
-                      GIArgInfo *arg_info,
-                      GITransfer transfer,
-                      PyGIDirection direction,
-                      gssize child_offset)
-{
-    PyGIArgGArray *array_cache = g_slice_new0 (PyGIArgGArray);
-    if (array_cache == NULL)
-        return NULL;
-
-    if (!pygi_arg_garray_setup (array_cache,
-                                type_info,
-                                arg_info,
-                                transfer,
-                                direction,
-                                child_offset)) {
-        _pygi_arg_cache_free ( (PyGIArgCache *)array_cache);
-        return NULL;
-    }
-
-    return array_cache;
-}
-
 static PyGICallbackCache *
 _callback_cache_new (GIArgInfo *arg_info,
                      GIInterfaceInfo *iface_info,
@@ -357,109 +275,6 @@ _arg_cache_alloc (void)
     return g_slice_new0 (PyGIArgCache);
 }
 
-
-static PyGIArgCache*
-_arg_cache_array_len_arg_setup (PyGIArgCache *arg_cache,
-                                PyGICallableCache *callable_cache,
-                                PyGIDirection direction,
-                                gssize arg_index,
-                                gssize *py_arg_index)
-{
-    PyGIArgGArray *seq_cache = (PyGIArgGArray *)arg_cache;
-    if (seq_cache->len_arg_index >= 0) {
-        PyGIArgCache *child_cache = NULL;
-
-        child_cache = _pygi_callable_cache_get_arg (callable_cache,
-                                                    seq_cache->len_arg_index);
-        if (child_cache == NULL) {
-            child_cache = _arg_cache_alloc ();
-        } else {
-            /* If the "length" arg cache already exists (the length comes before
-             * the array in the argument list), remove it from the to_py_args list
-             * because it does not belong in "to python" return tuple. The length
-             * will implicitly be a part of the returned Python list.
-             */
-            if (direction & PYGI_DIRECTION_TO_PYTHON) {
-                callable_cache->to_py_args =
-                    g_slist_remove (callable_cache->to_py_args, child_cache);
-            }
-
-            /* This is a case where the arg cache already exists and has been
-             * setup by another array argument sharing the same length argument.
-             * See: gi_marshalling_tests_multi_array_key_value_in
-             */
-            if (child_cache->meta_type == PYGI_META_ARG_TYPE_CHILD)
-                return child_cache;
-        }
-
-        /* There is a length argument for this array, so increment the number
-         * of "to python" child arguments when applicable.
-         */
-        if (direction & PYGI_DIRECTION_TO_PYTHON)
-             callable_cache->n_to_py_child_args++;
-
-        child_cache->meta_type = PYGI_META_ARG_TYPE_CHILD;
-        child_cache->direction = direction;
-        child_cache->to_py_marshaller = NULL;
-        child_cache->from_py_marshaller = NULL;
-
-        /* ugly edge case code:
-         *
-         * When the length comes before the array parameter we need to update
-         * indexes of arguments after the index argument.
-         */
-        if (seq_cache->len_arg_index < arg_index && direction & PYGI_DIRECTION_FROM_PYTHON) {
-            gssize i;
-            (*py_arg_index) -= 1;
-            callable_cache->n_py_args -= 1;
-
-            for (i = seq_cache->len_arg_index + 1;
-                   i < _pygi_callable_cache_args_len (callable_cache); i++) {
-                PyGIArgCache *update_cache = _pygi_callable_cache_get_arg (callable_cache, i);
-                if (update_cache == NULL)
-                    break;
-
-                update_cache->py_arg_index -= 1;
-            }
-        }
-
-        _pygi_callable_cache_set_arg (callable_cache, seq_cache->len_arg_index, child_cache);
-        return child_cache;
-    }
-
-    return NULL;
-}
-
-static gboolean
-_arg_cache_from_py_array_setup (PyGIArgCache *arg_cache,
-                                PyGICallableCache *callable_cache,
-                                GITypeInfo *type_info,
-                                GITransfer transfer,
-                                PyGIDirection direction,
-                                gssize arg_index)
-{
-    PyGIArgGArray *seq_cache = (PyGIArgGArray *)arg_cache;
-    seq_cache->array_type = g_type_info_get_array_type (type_info);
-    arg_cache->from_py_marshaller = _pygi_marshal_from_py_array;
-    arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_array;
-    return TRUE;
-}
-
-static gboolean
-_arg_cache_to_py_array_setup (PyGIArgCache *arg_cache,
-                              PyGICallableCache *callable_cache,
-                              GITypeInfo *type_info,
-                              GITransfer transfer,
-                              PyGIDirection direction,
-                              gssize arg_index)
-{
-    PyGIArgGArray *seq_cache = (PyGIArgGArray *)arg_cache;
-    seq_cache->array_type = g_type_info_get_array_type (type_info);
-    arg_cache->to_py_marshaller = _pygi_marshal_to_py_array;
-    arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_array;
-    return TRUE;
-}
-
 static void
 _arg_cache_from_py_gerror_setup (PyGIArgCache *arg_cache)
 {
@@ -717,16 +532,10 @@ _arg_cache_new (GITypeInfo *type_info,
                 PyGICallableCache *callable_cache)
 {
     PyGIArgCache *arg_cache = NULL;
-    gssize child_offset = 0;
     GITypeTag type_tag;
 
     type_tag = g_type_info_get_tag (type_info);
 
-    if (callable_cache != NULL)
-        child_offset =
-            (callable_cache->function_type == PYGI_FUNCTION_TYPE_METHOD ||
-                callable_cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) ? 1: 0;
-
     switch (type_tag) {
        case GI_TYPE_TAG_VOID:
        case GI_TYPE_TAG_BOOLEAN:
@@ -755,38 +564,19 @@ _arg_cache_new (GITypeInfo *type_info,
 
        case GI_TYPE_TAG_ARRAY:
            {
-               PyGIArgGArray *seq_cache =
-                   _arg_array_cache_new (type_info,
-                                         arg_info,
-                                         transfer,
-                                         direction,
-                                         child_offset);
-
-               arg_cache = (PyGIArgCache *)seq_cache;
+               arg_cache = pygi_arg_garray_new_from_info (type_info,
+                                                          arg_info,
+                                                          transfer,
+                                                          direction);
                if (arg_cache == NULL)
-                   break;
-
-               if (direction & PYGI_DIRECTION_FROM_PYTHON)
-                   _arg_cache_from_py_array_setup (arg_cache,
-                                                   callable_cache,
-                                                   type_info,
-                                                   transfer,
-                                                   direction,
-                                                   c_arg_index);
-
-               if (direction & PYGI_DIRECTION_TO_PYTHON)
-                   _arg_cache_to_py_array_setup (arg_cache,
-                                                 callable_cache,
-                                                 type_info,
-                                                 transfer,
-                                                 direction,
-                                                 c_arg_index);
-
-               _arg_cache_array_len_arg_setup (arg_cache,
-                                               callable_cache,
-                                               direction,
-                                               c_arg_index,
-                                               &py_arg_index);
+                   return NULL;
+
+               pygi_arg_garray_len_arg_setup (arg_cache,
+                                              type_info,
+                                              callable_cache,
+                                              direction,
+                                              c_arg_index,
+                                              &py_arg_index);
 
                arg_cache->py_arg_index = py_arg_index;
                arg_cache->c_arg_index = c_arg_index;
diff --git a/gi/pygi-marshal-cleanup.c b/gi/pygi-marshal-cleanup.c
index d402f1e..a8fa3f6 100644
--- a/gi/pygi-marshal-cleanup.c
+++ b/gi/pygi-marshal-cleanup.c
@@ -294,153 +294,3 @@ _pygi_marshal_cleanup_to_py_interface_struct_foreign (PyGIInvokeState *state,
             ( (PyGIInterfaceCache *)arg_cache)->interface_info,
             data);
 }
-
-static GArray*
-_wrap_c_array (PyGIInvokeState   *state,
-               PyGIArgGArray     *array_cache,
-               gpointer           data)
-{
-    GArray *array_;
-    gsize   len = 0;
-  
-    if (array_cache->fixed_size >= 0) {
-        len = array_cache->fixed_size;
-    } else if (array_cache->is_zero_terminated) {
-        len = g_strv_length ((gchar **)data);
-    } else if (array_cache->len_arg_index >= 0) {
-        GIArgument *len_arg = state->args[array_cache->len_arg_index];
-        len = len_arg->v_long;
-    }
-
-    array_ = g_array_new (FALSE,
-                          FALSE,
-                          array_cache->item_size);
-
-    if (array_ == NULL)
-        return NULL;
-
-    g_free (array_->data);
-    array_->data = data;
-    array_->len = len;
-
-    return array_;
-}
-
-void
-_pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state,
-                                     PyGIArgCache    *arg_cache,
-                                     PyObject        *py_arg,
-                                     gpointer         data,
-                                     gboolean         was_processed)
-{
-    if (was_processed) {
-        GArray *array_ = NULL;
-        GPtrArray *ptr_array_ = NULL;
-        PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
-        PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache;
-
-        if (array_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
-            ptr_array_ = (GPtrArray *) data;
-        } else {
-            array_ = (GArray *) data;
-        }
-
-        /* clean up items first */
-        if (sequence_cache->item_cache->from_py_cleanup != NULL) {
-            gsize i;
-            guint len = (array_ != NULL) ? array_->len : ptr_array_->len;
-            PyGIMarshalCleanupFunc cleanup_func =
-                sequence_cache->item_cache->from_py_cleanup;
-
-            for (i = 0; i < len; i++) {
-                gpointer item;
-                PyObject *py_item = NULL;
-
-                /* case 1: GPtrArray */
-                if (ptr_array_ != NULL)
-                    item = g_ptr_array_index (ptr_array_, i);
-                /* case 2: C array or GArray with object pointers */
-                else if (sequence_cache->item_cache->is_pointer)
-                    item = g_array_index (array_, gpointer, i);
-                /* case 3: C array or GArray with simple types or structs */
-                else {
-                    item = array_->data + i * array_cache->item_size;
-                    /* special-case hack: GValue array items do not get slice
-                     * allocated in _pygi_marshal_from_py_array(), so we must
-                     * not try to deallocate it as a slice and thus
-                     * short-circuit cleanup_func. */
-                    if (cleanup_func == _pygi_marshal_cleanup_from_py_interface_struct_gvalue) {
-                        g_value_unset ((GValue*) item);
-                        continue;
-                    }
-                }
-
-                py_item = PySequence_GetItem (py_arg, i);
-                cleanup_func (state, sequence_cache->item_cache, py_item, item, TRUE);
-                Py_XDECREF (py_item);
-            }
-        }
-
-        /* Only free the array when we didn't transfer ownership */
-        if (array_cache->array_type == GI_ARRAY_TYPE_C) {
-            /* always free the GArray wrapper created in from_py marshaling and
-             * passed back as cleanup_data
-             */
-            g_array_free (array_, arg_cache->transfer == GI_TRANSFER_NOTHING);
-        } else {
-            if (array_ != NULL)
-                g_array_unref (array_);
-            else
-                g_ptr_array_unref (ptr_array_);
-        }
-    }
-}
-
-void
-_pygi_marshal_cleanup_to_py_array (PyGIInvokeState *state,
-                                   PyGIArgCache    *arg_cache,
-                                   PyObject        *dummy,
-                                   gpointer         data,
-                                   gboolean         was_processed)
-{
-    if (arg_cache->transfer == GI_TRANSFER_EVERYTHING ||
-        arg_cache->transfer == GI_TRANSFER_CONTAINER) {
-        GArray *array_ = NULL;
-        GPtrArray *ptr_array_ = NULL;
-        PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
-        PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache;
-
-        /* If this isn't a garray create one to help process variable sized
-           array elements */
-        if (array_cache->array_type == GI_ARRAY_TYPE_C) {
-            array_ = _wrap_c_array (state, array_cache, data);
-            
-            if (array_ == NULL)
-                return;
-
-        } else if (array_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
-            ptr_array_ = (GPtrArray *) data;
-        } else {
-            array_ = (GArray *) data;
-        }
-
-        if (sequence_cache->item_cache->to_py_cleanup != NULL) {
-            gsize i;
-            guint len = (array_ != NULL) ? array_->len : ptr_array_->len;
-
-            PyGIMarshalCleanupFunc cleanup_func = sequence_cache->item_cache->to_py_cleanup;
-            for (i = 0; i < len; i++) {
-                cleanup_func (state,
-                              sequence_cache->item_cache,
-                              NULL,
-                              (array_ != NULL) ? g_array_index (array_, gpointer, i) : g_ptr_array_index 
(ptr_array_, i),
-                              was_processed);
-            }
-        }
-
-        if (array_ != NULL)
-            g_array_free (array_, TRUE);
-        else
-            g_ptr_array_free (ptr_array_, TRUE);
-    }
-}
diff --git a/gi/pygi-marshal-cleanup.h b/gi/pygi-marshal-cleanup.h
index 815d41c..eaacb8d 100644
--- a/gi/pygi-marshal-cleanup.h
+++ b/gi/pygi-marshal-cleanup.h
@@ -70,16 +70,6 @@ void _pygi_marshal_cleanup_from_py_interface_callback     (PyGIInvokeState *stat
                                                            PyObject        *py_arg,
                                                            gpointer         data,
                                                            gboolean         was_processed);
-void _pygi_marshal_cleanup_from_py_array                  (PyGIInvokeState *state,
-                                                           PyGIArgCache    *arg_cache,
-                                                           PyObject        *py_arg,
-                                                           gpointer         data,
-                                                           gboolean         was_processed);
-void _pygi_marshal_cleanup_to_py_array                    (PyGIInvokeState *state,
-                                                           PyGIArgCache    *arg_cache,
-                                                           PyObject        *dummy,
-                                                           gpointer         data,
-                                                           gboolean         was_processed);
 G_END_DECLS
 
 #endif /* __PYGI_MARSHAL_CLEANUP_H__ */
diff --git a/gi/pygi-marshal-from-py.c b/gi/pygi-marshal-from-py.c
index acea4f3..d371432 100644
--- a/gi/pygi-marshal-from-py.c
+++ b/gi/pygi-marshal-from-py.c
@@ -49,108 +49,6 @@ static const unsigned long __nan[2] = {0xffffffff, 0x7fffffff};
 #endif
 
 static gboolean
-gi_argument_from_py_ssize_t (GIArgument   *arg_out,
-                             Py_ssize_t    size_in,
-                             GITypeTag     type_tag)                             
-{
-    switch (type_tag) {
-    case GI_TYPE_TAG_VOID:
-    case GI_TYPE_TAG_BOOLEAN:
-        goto unhandled_type;
-
-    case GI_TYPE_TAG_INT8:
-        if (size_in >= G_MININT8 && size_in <= G_MAXINT8) {
-            arg_out->v_int8 = size_in;
-            return TRUE;
-        } else {
-            goto overflow;
-        }
-
-    case GI_TYPE_TAG_UINT8:
-        if (size_in >= 0 && size_in <= G_MAXUINT8) {
-            arg_out->v_uint8 = size_in;
-            return TRUE;
-        } else {
-            goto overflow;
-        }
-
-    case GI_TYPE_TAG_INT16:
-        if (size_in >= G_MININT16 && size_in <= G_MAXINT16) {
-            arg_out->v_int16 = size_in;
-            return TRUE;
-        } else {
-            goto overflow;
-        }
-
-    case GI_TYPE_TAG_UINT16:
-        if (size_in >= 0 && size_in <= G_MAXUINT16) {
-            arg_out->v_uint16 = size_in;
-            return TRUE;
-        } else {
-            goto overflow;
-        }
-
-        /* Ranges assume two's complement */
-    case GI_TYPE_TAG_INT32:
-        if (size_in >= G_MININT32 && size_in <= G_MAXINT32) {
-            arg_out->v_int32 = size_in;
-            return TRUE;
-        } else {
-            goto overflow;
-        }
-
-    case GI_TYPE_TAG_UINT32:
-        if (size_in >= 0 && size_in <= G_MAXUINT32) {
-            arg_out->v_uint32 = size_in;
-            return TRUE;
-        } else {
-            goto overflow;
-        }
-
-    case GI_TYPE_TAG_INT64:
-        arg_out->v_int64 = size_in;
-        return TRUE;
-
-    case GI_TYPE_TAG_UINT64:
-        if (size_in >= 0) {
-            arg_out->v_uint64 = size_in;
-            return TRUE;
-        } else {
-            goto overflow;
-        }
-            
-    case GI_TYPE_TAG_FLOAT:
-    case GI_TYPE_TAG_DOUBLE:
-    case GI_TYPE_TAG_GTYPE:
-    case GI_TYPE_TAG_UTF8:
-    case GI_TYPE_TAG_FILENAME:
-    case GI_TYPE_TAG_ARRAY:
-    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:
-    case GI_TYPE_TAG_UNICHAR:
-    default:
-        goto unhandled_type;
-    }
-
- overflow:
-    PyErr_Format (PyExc_OverflowError,
-                  "Unable to marshal C Py_ssize_t %zd to %s",
-                  size_in,
-                  g_type_tag_to_string (type_tag));
-    return FALSE;
-
- unhandled_type:
-    PyErr_Format (PyExc_TypeError,
-                  "Unable to marshal C Py_ssize_t %zd to %s",
-                  size_in,
-                  g_type_tag_to_string (type_tag));
-    return FALSE;
-}
-
-static gboolean
 gi_argument_from_c_long (GIArgument *arg_out,
                          long        c_long_in,
                          GITypeTag   type_tag)
@@ -243,258 +141,6 @@ _is_union_member (GIInterfaceInfo *interface_info, PyObject *py_arg) {
 }
 
 gboolean
-_pygi_marshal_from_py_array (PyGIInvokeState   *state,
-                             PyGICallableCache *callable_cache,
-                             PyGIArgCache      *arg_cache,
-                             PyObject          *py_arg,
-                             GIArgument        *arg,
-                             gpointer          *cleanup_data)
-{
-    PyGIMarshalFromPyFunc from_py_marshaller;
-    int i = 0;
-    int success_count = 0;
-    Py_ssize_t length;
-    gssize item_size;
-    gboolean is_ptr_array;
-    GArray *array_ = NULL;
-    PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
-    PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache;
-
-
-    if (py_arg == Py_None) {
-        arg->v_pointer = NULL;
-        return TRUE;
-    }
-
-    if (!PySequence_Check (py_arg)) {
-        PyErr_Format (PyExc_TypeError, "Must be sequence, not %s",
-                      py_arg->ob_type->tp_name);
-        return FALSE;
-    }
-
-    length = PySequence_Length (py_arg);
-    if (length < 0)
-        return FALSE;
-
-    if (array_cache->fixed_size >= 0 &&
-            array_cache->fixed_size != length) {
-        PyErr_Format (PyExc_ValueError, "Must contain %zd items, not %zd",
-                      array_cache->fixed_size, length);
-
-        return FALSE;
-    }
-
-    item_size = array_cache->item_size;
-    is_ptr_array = (array_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY);
-    if (is_ptr_array) {
-        array_ = (GArray *)g_ptr_array_sized_new (length);
-    } else {
-        array_ = g_array_sized_new (array_cache->is_zero_terminated,
-                                    TRUE,
-                                    item_size,
-                                    length);
-    }
-
-    if (array_ == NULL) {
-        PyErr_NoMemory ();
-        return FALSE;
-    }
-
-    if (sequence_cache->item_cache->type_tag == GI_TYPE_TAG_UINT8 &&
-        PYGLIB_PyBytes_Check (py_arg)) {
-        memcpy(array_->data, PYGLIB_PyBytes_AsString (py_arg), length);
-        array_->len = length;
-        if (array_cache->is_zero_terminated) {
-            /* If array_ has been created with zero_termination, space for the
-             * terminator is properly allocated, so we're not off-by-one here. */
-            array_->data[length] = '\0';
-        }
-        goto array_success;
-    }
-
-    from_py_marshaller = sequence_cache->item_cache->from_py_marshaller;
-    for (i = 0, success_count = 0; i < length; i++) {
-        GIArgument item = {0};
-        gpointer item_cleanup_data = NULL;
-        PyObject *py_item = PySequence_GetItem (py_arg, i);
-        if (py_item == NULL)
-            goto err;
-
-        if (!from_py_marshaller ( state,
-                                  callable_cache,
-                                  sequence_cache->item_cache,
-                                  py_item,
-                                 &item,
-                                 &item_cleanup_data)) {
-            Py_DECREF (py_item);
-            goto err;
-        }
-        Py_DECREF (py_item);
-
-        if (item_cleanup_data != NULL && item_cleanup_data != item.v_pointer) {
-            /* We only support one level of data discrepancy between an items
-             * data and its cleanup data. This is because we only track a single
-             * extra cleanup data pointer per-argument and cannot track the entire
-             * array of items differing data and cleanup_data.
-             * For example, this would fail if trying to marshal an array of
-             * callback closures marked with SCOPE call type where the cleanup data
-             * is different from the items v_pointer, likewise an array of arrays.
-             */
-            PyErr_SetString(PyExc_RuntimeError, "Cannot cleanup item data for array due to "
-                                                "the items data its cleanup data being different.");
-            goto err;
-        }
-
-        /* FIXME: it is much more efficent to have seperate marshaller
-         *        for ptr arrays than doing the evaluation
-         *        and casting each loop iteration
-         */
-        if (is_ptr_array) {
-            g_ptr_array_add((GPtrArray *)array_, item.v_pointer);
-        } else if (sequence_cache->item_cache->is_pointer) {
-            /* if the item is a pointer, simply copy the pointer */
-            g_assert (item_size == sizeof (item.v_pointer));
-            g_array_insert_val (array_, i, item);
-        } else if (sequence_cache->item_cache->type_tag == GI_TYPE_TAG_INTERFACE) {
-            /* Special case handling of flat arrays of gvalue/boxed/struct */
-            PyGIInterfaceCache *item_iface_cache = (PyGIInterfaceCache *) sequence_cache->item_cache;
-            GIBaseInfo *base_info = (GIBaseInfo *) item_iface_cache->interface_info;
-            GIInfoType info_type = g_base_info_get_type (base_info);
-
-            switch (info_type) {
-                case GI_INFO_TYPE_UNION:
-                case GI_INFO_TYPE_STRUCT:
-                {
-                    PyGIArgCache *item_arg_cache = (PyGIArgCache *)item_iface_cache;
-                    PyGIMarshalCleanupFunc from_py_cleanup = item_arg_cache->from_py_cleanup;
-
-                    if (g_type_is_a (item_iface_cache->g_type, G_TYPE_VALUE)) {
-                        /* Special case GValue flat arrays to properly init and copy the contents. */
-                        GValue* dest = (GValue*) (array_->data + (i * item_size));
-                        if (item.v_pointer != NULL) {
-                            memset (dest, 0, item_size);
-                            g_value_init (dest, G_VALUE_TYPE ((GValue*) item.v_pointer));
-                            g_value_copy ((GValue*) item.v_pointer, dest);
-                        }
-                        /* Manually increment the length because we are manually setting the memory. */
-                        array_->len++;
-
-                    } else {
-                        /* Handles flat arrays of boxed or struct types. */
-                        g_array_insert_vals (array_, i, item.v_pointer, 1);
-                    }
-
-                    /* Cleanup any memory left by the per-item marshaler because
-                     * _pygi_marshal_cleanup_from_py_array will not know about this
-                     * due to "item" being a temporarily marshaled value done on the stack.
-                     */
-                    if (from_py_cleanup)
-                        from_py_cleanup (state, item_arg_cache, py_item, item_cleanup_data, TRUE);
-
-                    break;
-                }
-                default:
-                    g_array_insert_val (array_, i, item);
-            }
-        } else {
-            /* default value copy of a simple type */
-            g_array_insert_val (array_, i, item);
-        }
-
-        success_count++;
-        continue;
-err:
-        if (sequence_cache->item_cache->from_py_cleanup != NULL) {
-            gsize j;
-            PyGIMarshalCleanupFunc cleanup_func =
-                sequence_cache->item_cache->from_py_cleanup;
-
-            /* Only attempt per item cleanup on pointer items */
-            if (sequence_cache->item_cache->is_pointer) {
-                for(j = 0; j < success_count; j++) {
-                    PyObject *py_item = PySequence_GetItem (py_arg, j);
-                    cleanup_func (state,
-                                  sequence_cache->item_cache,
-                                  py_item,
-                                  is_ptr_array ?
-                                          g_ptr_array_index ((GPtrArray *)array_, j) :
-                                          g_array_index (array_, gpointer, j),
-                                  TRUE);
-                    Py_DECREF (py_item);
-                }
-            }
-        }
-
-        if (is_ptr_array)
-            g_ptr_array_free ( ( GPtrArray *)array_, TRUE);
-        else
-            g_array_free (array_, TRUE);
-        _PyGI_ERROR_PREFIX ("Item %i: ", i);
-        return FALSE;
-    }
-
-array_success:
-    if (array_cache->len_arg_index >= 0) {
-        /* we have an child arg to handle */
-        PyGIArgCache *child_cache =
-            _pygi_callable_cache_get_arg (callable_cache, array_cache->len_arg_index);
-
-        if (child_cache->direction == PYGI_DIRECTION_BIDIRECTIONAL) {
-            gint *len_arg = (gint *)state->in_args[child_cache->c_arg_index].v_pointer;
-            /* if we are not setup yet just set the in arg */
-            if (len_arg == NULL) {
-                if (!gi_argument_from_py_ssize_t (&state->in_args[child_cache->c_arg_index],
-                                                  length,
-                                                  child_cache->type_tag)) {
-                    goto err;
-                }
-            } else {
-                *len_arg = length;
-            }
-        } else {
-            if (!gi_argument_from_py_ssize_t (&state->in_args[child_cache->c_arg_index],
-                                              length,
-                                              child_cache->type_tag)) {
-                goto err;
-            }
-        }
-    }
-
-    if (array_cache->array_type == GI_ARRAY_TYPE_C) {
-        /* In the case of GI_ARRAY_C, we give the data directly as the argument
-         * but keep the array_ wrapper as cleanup data so we don't have to find
-         * it's length again.
-         */
-        arg->v_pointer = array_->data;
-
-        if (arg_cache->transfer == GI_TRANSFER_EVERYTHING) {
-            g_array_free (array_, FALSE);
-            *cleanup_data = NULL;
-        } else {
-            *cleanup_data = array_;
-        }
-    } else {
-        arg->v_pointer = array_;
-
-        if (arg_cache->transfer == GI_TRANSFER_NOTHING) {
-            /* Free everything in cleanup. */
-            *cleanup_data = array_;
-        } else if (arg_cache->transfer == GI_TRANSFER_CONTAINER) {
-            /* Make a shallow copy so we can free the elements later in cleanup
-             * because it is possible invoke will free the list before our cleanup. */
-            *cleanup_data = is_ptr_array ?
-                    (gpointer)g_ptr_array_ref ((GPtrArray *)array_) :
-                    (gpointer)g_array_ref (array_);
-        } else { /* GI_TRANSFER_EVERYTHING */
-            /* No cleanup, everything is given to the callee. */
-            *cleanup_data = NULL;
-        }
-    }
-
-    return TRUE;
-}
-
-gboolean
 _pygi_marshal_from_py_gerror (PyGIInvokeState   *state,
                               PyGICallableCache *callable_cache,
                               PyGIArgCache      *arg_cache,
diff --git a/gi/pygi-marshal-from-py.h b/gi/pygi-marshal-from-py.h
index 0f6ed29..89f6f91 100644
--- a/gi/pygi-marshal-from-py.h
+++ b/gi/pygi-marshal-from-py.h
@@ -33,12 +33,6 @@ G_BEGIN_DECLS
 gboolean _pygi_marshal_from_py_ssize_t     (PyGIArgCache      *arg_cache,
                                             Py_ssize_t         size,
                                             GIArgument        *arg);
-gboolean _pygi_marshal_from_py_array       (PyGIInvokeState   *state,
-                                            PyGICallableCache *callable_cache,
-                                            PyGIArgCache      *arg_cache,
-                                            PyObject          *py_arg,
-                                            GIArgument        *arg,
-                                            gpointer          *cleanup_data);
 gboolean _pygi_marshal_from_py_gerror      (PyGIInvokeState   *state,
                                             PyGICallableCache *callable_cache,
                                             PyGIArgCache      *arg_cache,
diff --git a/gi/pygi-marshal-to-py.c b/gi/pygi-marshal-to-py.c
index 5d238a3..645b248 100644
--- a/gi/pygi-marshal-to-py.c
+++ b/gi/pygi-marshal-to-py.c
@@ -74,216 +74,6 @@ gi_argument_to_c_long (GIArgument *arg_in,
     }
 }
 
-static gboolean
-gi_argument_to_gsize (GIArgument *arg_in,
-                      gsize      *gsize_out,
-                      GITypeTag   type_tag)
-{
-    switch (type_tag) {
-      case GI_TYPE_TAG_INT8:
-          *gsize_out = arg_in->v_int8;
-          return TRUE;
-      case GI_TYPE_TAG_UINT8:
-          *gsize_out = arg_in->v_uint8;
-          return TRUE;
-      case GI_TYPE_TAG_INT16:
-          *gsize_out = arg_in->v_int16;
-          return TRUE;
-      case GI_TYPE_TAG_UINT16:
-          *gsize_out = arg_in->v_uint16;
-          return TRUE;
-      case GI_TYPE_TAG_INT32:
-          *gsize_out = arg_in->v_int32;
-          return TRUE;
-      case GI_TYPE_TAG_UINT32:
-          *gsize_out = arg_in->v_uint32;
-          return TRUE;
-      case GI_TYPE_TAG_INT64:
-          *gsize_out = arg_in->v_int64;
-          return TRUE;
-      case GI_TYPE_TAG_UINT64:
-          *gsize_out = arg_in->v_uint64;
-          return TRUE;
-      default:
-          PyErr_Format (PyExc_TypeError,
-                        "Unable to marshal %s to gsize",
-                        g_type_tag_to_string (type_tag));
-          return FALSE;
-    }
-}
-
-PyObject *
-_pygi_marshal_to_py_array (PyGIInvokeState   *state,
-                           PyGICallableCache *callable_cache,
-                           PyGIArgCache      *arg_cache,
-                           GIArgument        *arg)
-{
-    GArray *array_;
-    PyObject *py_obj = NULL;
-    PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
-    PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache;
-    gsize processed_items = 0;
-
-     /* GArrays make it easier to iterate over arrays
-      * with different element sizes but requires that
-      * we allocate a GArray if the argument was a C array
-      */
-    if (array_cache->array_type == GI_ARRAY_TYPE_C) {
-        gsize len;
-        if (array_cache->fixed_size >= 0) {
-            g_assert(arg->v_pointer != NULL);
-            len = array_cache->fixed_size;
-        } else if (array_cache->is_zero_terminated) {
-            if (arg->v_pointer == NULL) {
-                len = 0;
-            } else if (seq_cache->item_cache->type_tag == GI_TYPE_TAG_UINT8) {
-                len = strlen (arg->v_pointer);
-            } else {
-                len = g_strv_length ((gchar **)arg->v_pointer);
-            }
-        } else {
-            GIArgument *len_arg = state->args[array_cache->len_arg_index];
-            PyGIArgCache *arg_cache = _pygi_callable_cache_get_arg (callable_cache,
-                                                                    array_cache->len_arg_index);
-
-            if (!gi_argument_to_gsize (len_arg, &len, arg_cache->type_tag)) {
-                return NULL;
-            }
-        }
-
-        array_ = g_array_new (FALSE,
-                              FALSE,
-                              array_cache->item_size);
-        if (array_ == NULL) {
-            PyErr_NoMemory ();
-
-            if (arg_cache->transfer == GI_TRANSFER_EVERYTHING && arg->v_pointer != NULL)
-                g_free (arg->v_pointer);
-
-            return NULL;
-        }
-
-        if (array_->data != NULL) 
-            g_free (array_->data);
-        array_->data = arg->v_pointer;
-        array_->len = len;
-    } else {
-        array_ = arg->v_pointer;
-    }
-
-    if (seq_cache->item_cache->type_tag == GI_TYPE_TAG_UINT8) {
-        if (arg->v_pointer == NULL) {
-            py_obj = PYGLIB_PyBytes_FromString ("");
-        } else {
-            py_obj = PYGLIB_PyBytes_FromStringAndSize (array_->data, array_->len);
-        }
-    } else {
-        if (arg->v_pointer == NULL) {
-            py_obj = PyList_New (0);
-        } else {
-            int i;
-
-            gsize item_size;
-            PyGIMarshalToPyFunc item_to_py_marshaller;
-            PyGIArgCache *item_arg_cache;
-
-            py_obj = PyList_New (array_->len);
-            if (py_obj == NULL)
-                goto err;
-
-
-            item_arg_cache = seq_cache->item_cache;
-            item_to_py_marshaller = item_arg_cache->to_py_marshaller;
-
-            item_size = g_array_get_element_size (array_);
-
-            for (i = 0; i < array_->len; i++) {
-                GIArgument item_arg = {0};
-                PyObject *py_item;
-
-                /* If we are receiving an array of pointers, simply assign the pointer
-                 * and move on, letting the per-item marshaler deal with the
-                 * various transfer modes and ref counts (e.g. g_variant_ref_sink).
-                 */
-                if (array_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
-                    item_arg.v_pointer = g_ptr_array_index ( ( GPtrArray *)array_, i);
-
-                } else if (item_arg_cache->is_pointer) {
-                    item_arg.v_pointer = g_array_index (array_, gpointer, i);
-
-                } else if (item_arg_cache->type_tag == GI_TYPE_TAG_INTERFACE) {
-                    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *) item_arg_cache;
-
-                    // FIXME: This probably doesn't work with boxed types or gvalues. See fx. 
_pygi_marshal_from_py_array()
-                    switch (g_base_info_get_type (iface_cache->interface_info)) {
-                        case GI_INFO_TYPE_STRUCT:
-                            if (arg_cache->transfer == GI_TRANSFER_EVERYTHING &&
-                                       !g_type_is_a (iface_cache->g_type, G_TYPE_BOXED)) {
-                                /* array elements are structs */
-                                gpointer *_struct = g_malloc (item_size);
-                                memcpy (_struct, array_->data + i * item_size,
-                                        item_size);
-                                item_arg.v_pointer = _struct;
-                            } else {
-                                item_arg.v_pointer = array_->data + i * item_size;
-                            }
-                            break;
-                        default:
-                            item_arg.v_pointer = g_array_index (array_, gpointer, i);
-                            break;
-                    }
-                } else {
-                    memcpy (&item_arg, array_->data + i * item_size, item_size);
-                }
-
-                py_item = item_to_py_marshaller ( state,
-                                                callable_cache,
-                                                item_arg_cache,
-                                                &item_arg);
-
-                if (py_item == NULL) {
-                    Py_CLEAR (py_obj);
-
-                    if (array_cache->array_type == GI_ARRAY_TYPE_C)
-                        g_array_unref (array_);
-
-                    goto err;
-                }
-                PyList_SET_ITEM (py_obj, i, py_item);
-                processed_items++;
-            }
-        }
-    }
-
-    if (array_cache->array_type == GI_ARRAY_TYPE_C)
-        g_array_free (array_, FALSE);
-
-    return py_obj;
-
-err:
-    if (array_cache->array_type == GI_ARRAY_TYPE_C) {
-        g_array_free (array_, arg_cache->transfer == GI_TRANSFER_EVERYTHING);
-    } else {
-        /* clean up unprocessed items */
-        if (seq_cache->item_cache->to_py_cleanup != NULL) {
-            int j;
-            PyGIMarshalCleanupFunc cleanup_func = seq_cache->item_cache->to_py_cleanup;
-            for (j = processed_items; j < array_->len; j++) {
-                cleanup_func (state,
-                              seq_cache->item_cache,
-                              NULL,
-                              g_array_index (array_, gpointer, j),
-                              FALSE);
-            }
-        }
-
-        if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
-            g_array_free (array_, TRUE);
-    }
-
-    return NULL;
-}
-
 PyObject *
 _pygi_marshal_to_py_gerror (PyGIInvokeState   *state,
                             PyGICallableCache *callable_cache,
diff --git a/gi/pygi-marshal-to-py.h b/gi/pygi-marshal-to-py.h
index 1afa83f..5eec183 100644
--- a/gi/pygi-marshal-to-py.h
+++ b/gi/pygi-marshal-to-py.h
@@ -22,10 +22,6 @@
 #ifndef __PYGI_MARSHAL_TO_PY_H__
 #define __PYGI_MARSHAL_TO_PY_H__
 
-PyObject *_pygi_marshal_to_py_array     (PyGIInvokeState   *state,
-                                         PyGICallableCache *callable_cache,
-                                         PyGIArgCache      *arg_cache,
-                                         GIArgument        *arg);
 PyObject *_pygi_marshal_to_py_gerror    (PyGIInvokeState   *state,
                                          PyGICallableCache *callable_cache,
                                          PyGIArgCache      *arg_cache,


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