[pygobject/invoke-rewrite] [gi] start of merge from master



commit 7332a1b99775519fdc5500cab6628b713e946a8c
Author: John (J5) Palmieri <johnp redhat com>
Date:   Mon Mar 21 19:03:29 2011 -0400

    [gi] start of merge from master
    
    * move some of the modified files that will cause merge conflicts to their
      own, nonconflicting files
    * copy the old files out of master

 gi/pygi-argument.c  | 2101 +++-------------------------
 gi/pygi-invoke-ng.c | 1179 ++++++++++++++++
 gi/pygi-invoke.c    |  421 ++----
 gi/pygi-marshal.c   | 3916 +++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 5389 insertions(+), 2228 deletions(-)
---
diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c
index fa744f3..c44307c 100644
--- a/gi/pygi-argument.c
+++ b/gi/pygi-argument.c
@@ -30,8 +30,6 @@
 #include <pygobject.h>
 #include <pyglib-python-compat.h>
 
-#include "pygi-cache.h"
-
 static void
 _pygi_g_type_tag_py_bounds (GITypeTag   type_tag,
                             PyObject  **lower,
@@ -190,6 +188,7 @@ _pygi_g_type_interface_check_object (GIBaseInfo *info,
                     for (i = 0; i < g_enum_info_get_n_values (info); i++) {
                         GIValueInfo *value_info = g_enum_info_get_value (info, i);
                         glong enum_value = g_value_info_get_value (value_info);
+                        g_base_info_unref (value_info);
                         if (value == enum_value) {
                             retval = 1;
                             break;
@@ -225,14 +224,15 @@ _pygi_g_type_interface_check_object (GIBaseInfo *info,
             /* Handle special cases. */
             type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info);
             if (g_type_is_a (type, G_TYPE_CLOSURE)) {
-                if (!PyCallable_Check (object)) {
+                if (!(PyCallable_Check (object) ||
+                      pyg_type_from_object_strict (object, FALSE) == G_TYPE_CLOSURE)) {
                     PyErr_Format (PyExc_TypeError, "Must be callable, not %s",
                                   object->ob_type->tp_name);
                     retval = 0;
                 }
                 break;
             } else if (g_type_is_a (type, G_TYPE_VALUE)) {
-                /* we can't check g_values because we don't have
+                /* we can't check g_values because we don't have 
                  * enough context so just pass them through */
                 break;
             }
@@ -242,8 +242,46 @@ _pygi_g_type_interface_check_object (GIBaseInfo *info,
         case GI_INFO_TYPE_BOXED:
         case GI_INFO_TYPE_INTERFACE:
         case GI_INFO_TYPE_OBJECT:
+            retval = _pygi_g_registered_type_info_check_object ( (GIRegisteredTypeInfo *) info, TRUE, object);
+            break;
         case GI_INFO_TYPE_UNION:
+
+
             retval = _pygi_g_registered_type_info_check_object ( (GIRegisteredTypeInfo *) info, TRUE, object);
+
+            /* If not the same type then check to see if the object's type
+             * is the same as one of the union's members
+             */
+            if (retval == 0) {
+                gint i;
+                gint n_fields;
+
+                n_fields = g_union_info_get_n_fields ( (GIUnionInfo *) info);
+
+                for (i = 0; i < n_fields; i++) {
+                    gint member_retval;
+                    GIFieldInfo *field_info;
+                    GITypeInfo *field_type_info;
+
+                    field_info =
+                        g_union_info_get_field ( (GIUnionInfo *) info, i);
+                    field_type_info = g_field_info_get_type (field_info);
+
+                    member_retval = _pygi_g_type_info_check_object(
+                        field_type_info,
+                        object,
+                        TRUE);
+
+                    g_base_info_unref ( ( GIBaseInfo *) field_type_info);
+                    g_base_info_unref ( ( GIBaseInfo *) field_info);
+
+                    if (member_retval == 1) {
+                        retval = member_retval;
+                        break;
+                    }
+                }
+            }
+
             break;
         default:
             g_assert_not_reached();
@@ -1010,25 +1048,39 @@ array_success:
                         g_warn_if_fail (transfer == GI_TRANSFER_NOTHING);
 
                         value = g_slice_new0 (GValue);
-                        g_value_init (value, object_type);
 
-                        retval = pyg_value_from_pyobject (value, object);
-                        if (retval < 0) {
-                            g_slice_free (GValue, value);
-                            PyErr_SetString (PyExc_RuntimeError, "PyObject conversion to GValue failed");
-                            break;
+                        /* if already a gvalue, copy, else marshal into gvalue */
+                        if (object_type == G_TYPE_VALUE) {
+                            /* src GValue's lifecycle is handled by Python
+                             * so we have to copy it into the destination's
+                             * GValue which is freed during the cleanup of
+                             * invoke.
+                             */
+                            GValue *src = (GValue *)((PyGObject *) object)->obj;
+                            g_value_init (value, G_VALUE_TYPE (src));
+                            g_value_copy(src, value);
+                        } else {
+                            g_value_init (value, object_type);
+                            retval = pyg_value_from_pyobject (value, object);
+                            if (retval < 0) {
+                                g_slice_free (GValue, value);
+                                PyErr_SetString (PyExc_RuntimeError, "PyObject conversion to GValue failed");
+                                break;
+                            }
                         }
 
                         arg.v_pointer = value;
                     } else if (g_type_is_a (type, G_TYPE_CLOSURE)) {
                         GClosure *closure;
 
-                        g_warn_if_fail (transfer == GI_TRANSFER_NOTHING);
-
-                        closure = pyg_closure_new (object, NULL, NULL);
-                        if (closure == NULL) {
-                            PyErr_SetString (PyExc_RuntimeError, "PyObject conversion to GClosure failed");
-                            break;
+                        if (pyg_type_from_object_strict (object, FALSE) == G_TYPE_CLOSURE) {
+                            closure = (GClosure *)pyg_boxed_get (object, void);
+                        } else {
+                            closure = pyg_closure_new (object, NULL, NULL);
+                            if (closure == NULL) {
+                                PyErr_SetString (PyExc_RuntimeError, "PyObject conversion to GClosure failed");
+                                break;
+                            }
                         }
 
                         arg.v_pointer = closure;
@@ -1511,6 +1563,8 @@ _pygi_argument_to_object (GIArgument  *arg,
                     type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info);
                     if (g_type_is_a (type, G_TYPE_VALUE)) {
                         object = pyg_value_as_pyobject (arg->v_pointer, FALSE);
+                    } else if (g_struct_info_is_foreign (info)) {
+                        object = pygi_struct_foreign_convert_from_g_argument (type_info, arg->v_pointer);
                     } else if (g_type_is_a (type, G_TYPE_BOXED)) {
                         PyObject *py_type;
 
@@ -1534,8 +1588,6 @@ _pygi_argument_to_object (GIArgument  *arg,
                         }
 
                         Py_XDECREF (py_type);
-                    } else if ( (type == G_TYPE_NONE) && (g_struct_info_is_foreign (info))) {
-                        object = pygi_struct_foreign_convert_from_g_argument (type_info, arg->v_pointer);
                     } else if (type == G_TYPE_NONE) {
                         PyObject *py_type;
 
@@ -1720,6 +1772,97 @@ _pygi_argument_to_object (GIArgument  *arg,
     return object;
 }
 
+
+GIArgument
+_pygi_argument_from_g_value(const GValue *value,
+                            GITypeInfo *type_info)
+{
+    GIArgument arg = { 0, };
+
+    GITypeTag type_tag = g_type_info_get_tag (type_info);
+    switch (type_tag) {
+        case GI_TYPE_TAG_BOOLEAN:
+            arg.v_boolean = g_value_get_boolean (value);
+            break;
+        case GI_TYPE_TAG_INT8:
+        case GI_TYPE_TAG_INT16:
+        case GI_TYPE_TAG_INT32:
+        case GI_TYPE_TAG_INT64:
+            arg.v_int = g_value_get_int (value);
+            break;
+        case GI_TYPE_TAG_UINT8:
+        case GI_TYPE_TAG_UINT16:
+        case GI_TYPE_TAG_UINT32:
+        case GI_TYPE_TAG_UINT64:
+            arg.v_uint = g_value_get_uint (value);
+            break;
+        case GI_TYPE_TAG_UNICHAR:
+            arg.v_uint32 = g_value_get_char (value);
+            break;
+        case GI_TYPE_TAG_FLOAT:
+            arg.v_float = g_value_get_float (value);
+            break;
+        case GI_TYPE_TAG_DOUBLE:
+            arg.v_double = g_value_get_double (value);
+            break;
+        case GI_TYPE_TAG_GTYPE:
+            arg.v_long = g_value_get_gtype (value);
+            break;
+        case GI_TYPE_TAG_UTF8:
+        case GI_TYPE_TAG_FILENAME:
+            arg.v_string = g_value_dup_string (value);
+            break;
+        case GI_TYPE_TAG_GLIST:
+        case GI_TYPE_TAG_GSLIST:
+            arg.v_pointer = g_value_get_pointer (value);
+            break;
+        case GI_TYPE_TAG_ARRAY:
+        case GI_TYPE_TAG_GHASH:
+            arg.v_pointer = g_value_get_boxed (value);
+            break;
+        case GI_TYPE_TAG_INTERFACE:
+        {
+            GIBaseInfo *info;
+            GIInfoType info_type;
+
+            info = g_type_info_get_interface (type_info);
+            info_type = g_base_info_get_type (info);
+
+            g_base_info_unref (info);
+
+            switch (info_type) {
+                case GI_INFO_TYPE_FLAGS:
+                case GI_INFO_TYPE_ENUM:
+                    arg.v_long = g_value_get_enum (value);
+                    break;
+                case GI_INFO_TYPE_INTERFACE:
+                case GI_INFO_TYPE_OBJECT:
+                    arg.v_pointer = g_value_get_object (value);
+                    break;
+                case GI_INFO_TYPE_BOXED:
+                case GI_INFO_TYPE_STRUCT:
+                case GI_INFO_TYPE_UNION:
+                    if (G_VALUE_HOLDS(value, G_TYPE_BOXED)) {
+                        arg.v_pointer = g_value_get_boxed (value);
+                    } else {
+                        arg.v_pointer = g_value_get_pointer (value);
+                    }
+                    break;
+                default:
+                    g_warning("Converting of type '%s' is not implemented", g_info_type_to_string(info_type));
+                    g_assert_not_reached();
+            }
+            break;
+        }
+        case GI_TYPE_TAG_ERROR:
+        case GI_TYPE_TAG_VOID:
+            g_critical("Converting of type '%s' is not implemented", g_type_tag_to_string(type_tag));
+            g_assert_not_reached();
+    }
+
+    return arg;
+}
+
 void
 _pygi_argument_release (GIArgument   *arg,
                         GITypeInfo  *type_info,
@@ -1992,1925 +2135,3 @@ _pygi_argument_init (void)
     _pygobject_import();
 }
 
-/*** argument marshaling and validating routines ***/
-
-gboolean
-_pygi_marshal_in_void (PyGIInvokeState   *state,
-                       PyGIFunctionCache *function_cache,
-                       PyGIArgCache      *arg_cache,
-                       PyObject          *py_arg,
-                       GIArgument        *arg)
-{
-    g_warn_if_fail (arg_cache->transfer == GI_TRANSFER_NOTHING);
-
-    arg->v_pointer = py_arg;
-
-    return TRUE;
-}
-
-gboolean
-_pygi_marshal_in_boolean (PyGIInvokeState   *state,
-                          PyGIFunctionCache *function_cache,
-                          PyGIArgCache      *arg_cache,
-                          PyObject          *py_arg,
-                          GIArgument        *arg)
-{
-    arg->v_boolean = PyObject_IsTrue(py_arg);
-
-    return TRUE;
-}
-
-gboolean
-_pygi_marshal_in_int8 (PyGIInvokeState   *state,
-                       PyGIFunctionCache *function_cache,
-                       PyGIArgCache      *arg_cache,
-                       PyObject          *py_arg,
-                       GIArgument        *arg)
-{
-    PyObject *py_long;
-    long long_;
-
-    if (!PyNumber_Check(py_arg)) {
-        PyErr_Format (PyExc_TypeError, "Must be number, not %s",
-                      py_arg->ob_type->tp_name);
-        return FALSE;
-    }
-
-    py_long = PYGLIB_PyNumber_Long(py_arg);
-    if (!py_long)
-        return FALSE;
-
-    long_ = PYGLIB_PyLong_AsLong(py_long);
-    Py_DECREF(py_long);
-
-    if (PyErr_Occurred())
-        return FALSE;
-
-    if (long_ < -128 || long_ > 127) {
-        PyErr_Format (PyExc_ValueError, "%ld not in range %d to %d", long_, -128, 127);
-        return FALSE;
-    }
-
-    arg->v_long = long_;
-
-    return TRUE;
-}
-
-gboolean
-_pygi_marshal_in_uint8 (PyGIInvokeState   *state,
-                        PyGIFunctionCache *function_cache,
-                        PyGIArgCache      *arg_cache,
-                        PyObject          *py_arg,
-                        GIArgument        *arg)
-{
-    unsigned long long_;
-
-    if (PYGLIB_PyBytes_Check(py_arg)) {
-
-        if (PYGLIB_PyBytes_Size(py_arg) != 1) {
-            PyErr_Format (PyExc_TypeError, "Must be a single character");
-            return FALSE;
-        }
-
-        long_ = (unsigned char)(PYGLIB_PyBytes_AsString(py_arg)[0]);
-
-    } else if (PyNumber_Check(py_arg)) {
-        PyObject *py_long;
-        py_long = PYGLIB_PyNumber_Long(py_arg);
-        if (!py_long)
-            return FALSE;
-
-        long_ = PYGLIB_PyLong_AsLong(py_long);
-        Py_DECREF(py_long);
-
-        if (PyErr_Occurred())
-            return FALSE;
-    } else {
-        PyErr_Format (PyExc_TypeError, "Must be number or single byte string, not %s",
-                      py_arg->ob_type->tp_name);
-        return FALSE;
-    }
-
-    if (long_ < 0 || long_ > 255) {
-        PyErr_Format (PyExc_ValueError, "%ld not in range %d to %d", long_, 0, 255);
-        return FALSE;
-    }
-
-    arg->v_long = long_;
-
-    return TRUE;
-}
-
-gboolean
-_pygi_marshal_in_int16 (PyGIInvokeState   *state,
-                        PyGIFunctionCache *function_cache,
-                        PyGIArgCache      *arg_cache,
-                        PyObject          *py_arg,
-                        GIArgument        *arg)
-{
-    PyObject *py_long;
-    long long_;
-
-    if (!PyNumber_Check(py_arg)) {
-        PyErr_Format (PyExc_TypeError, "Must be number, not %s",
-                      py_arg->ob_type->tp_name);
-        return FALSE;
-    }
-
-    py_long = PYGLIB_PyNumber_Long(py_arg);
-    if (!py_long)
-        return FALSE;
-
-    long_ = PYGLIB_PyLong_AsLong(py_long);
-    Py_DECREF(py_long);
-
-    if (PyErr_Occurred())
-        return FALSE;
-
-    if (long_ < -32768 || long_ > 32767) {
-        PyErr_Format (PyExc_ValueError, "%ld not in range %d to %d", long_, -32768, 32767);
-        return FALSE;
-    }
-
-    arg->v_long = long_;
-
-    return TRUE;
-}
-
-gboolean
-_pygi_marshal_in_uint16 (PyGIInvokeState   *state,
-                         PyGIFunctionCache *function_cache,
-                         PyGIArgCache      *arg_cache,
-                         PyObject          *py_arg,
-                         GIArgument        *arg)
-{
-    PyObject *py_long;
-    long long_;
-
-    if (!PyNumber_Check(py_arg)) {
-        PyErr_Format (PyExc_TypeError, "Must be number, not %s",
-                      py_arg->ob_type->tp_name);
-        return FALSE;
-    }
-
-    py_long = PYGLIB_PyNumber_Long(py_arg);
-    if (!py_long)
-        return FALSE;
-
-    long_ = PYGLIB_PyLong_AsLong(py_long);
-    Py_DECREF(py_long);
-
-    if (PyErr_Occurred())
-        return FALSE;
-
-    if (long_ < 0 || long_ > 65535) {
-        PyErr_Format (PyExc_ValueError, "%li not in range %d to %d", long_, 0, 65535);
-        return FALSE;
-    }
-
-    arg->v_long = long_;
-
-    return TRUE;
-}
-
-gboolean
-_pygi_marshal_in_int32 (PyGIInvokeState   *state,
-                        PyGIFunctionCache *function_cache,
-                        PyGIArgCache      *arg_cache,
-                        PyObject          *py_arg,
-                        GIArgument        *arg)
-{
-    PyObject *py_long;
-    long long_;
-
-    if (!PyNumber_Check(py_arg)) {
-        PyErr_Format (PyExc_TypeError, "Must be number, not %s",
-                      py_arg->ob_type->tp_name);
-        return FALSE;
-    }
-
-    py_long = PYGLIB_PyNumber_Long(py_arg);
-    if (!py_long)
-        return FALSE;
-
-    long_ = PYGLIB_PyLong_AsLong(py_long);
-    Py_DECREF(py_long);
-
-    if (PyErr_Occurred())
-        return FALSE;
-
-    if (long_ < G_MININT32 || long_ > G_MAXINT32) {
-        PyErr_Format (PyExc_ValueError, "%ld not in range %d to %d", long_, G_MININT32, G_MAXINT32);
-        return FALSE;
-    }
-
-    arg->v_long = long_;
-
-    return TRUE;
-}
-
-gboolean
-_pygi_marshal_in_uint32 (PyGIInvokeState   *state,
-                         PyGIFunctionCache *function_cache,
-                         PyGIArgCache      *arg_cache,
-                         PyObject          *py_arg,
-                         GIArgument        *arg)
-{
-    PyObject *py_long;
-    long long long_;
-
-    if (!PyNumber_Check(py_arg)) {
-        PyErr_Format (PyExc_TypeError, "Must be number, not %s",
-                      py_arg->ob_type->tp_name);
-        return FALSE;
-    }
-
-    py_long = PYGLIB_PyNumber_Long(py_arg);
-    if (!py_long)
-        return FALSE;
-
-#if PY_VERSION_HEX < 0x03000000
-    if (PyInt_Check (py_long))
-        long_ = PyInt_AsLong (py_long);
-    else
-#endif
-        long_ = PyLong_AsLongLong(py_long);
-
-    Py_DECREF(py_long);
-
-    if (PyErr_Occurred())
-        return FALSE;
-
-    if (long_ < 0 || long_ > G_MAXUINT32) {
-        PyErr_Format (PyExc_ValueError, "%lli not in range %i to %u", long_, 0, G_MAXUINT32);
-        return FALSE;
-    }
-
-    arg->v_uint64 = long_;
-
-    return TRUE;
-}
-
-gboolean
-_pygi_marshal_in_int64 (PyGIInvokeState   *state,
-                        PyGIFunctionCache *function_cache,
-                        PyGIArgCache      *arg_cache,
-                        PyObject          *py_arg,
-                        GIArgument        *arg)
-{
-    PyObject *py_long;
-    long long long_;
-
-    if (!PyNumber_Check(py_arg)) {
-        PyErr_Format (PyExc_TypeError, "Must be number, not %s",
-                      py_arg->ob_type->tp_name);
-        return FALSE;
-    }
-
-    py_long = PYGLIB_PyNumber_Long(py_arg);
-    if (!py_long)
-        return FALSE;
-
-#if PY_VERSION_HEX < 0x03000000
-    if (PyInt_Check (py_long))
-        long_ = PyInt_AS_LONG (py_long);
-    else
-#endif
-        long_ = PyLong_AsLongLong(py_long);
-
-    Py_DECREF(py_long);
-
-    if (PyErr_Occurred()) {
-        /* OverflowError occured but range errors should be returned as ValueError */
-        char *long_str;
-        PyObject *py_str = PyObject_Str(py_long);
-
-        if (PyUnicode_Check(py_str)) {
-            PyObject *py_bytes = PyUnicode_AsUTF8String(py_str);
-            if (py_bytes == NULL)
-                return FALSE;
-
-            long_str = g_strdup(PYGLIB_PyBytes_AsString(py_bytes));
-            if (long_str == NULL) {
-                PyErr_NoMemory();
-                return FALSE;
-            }
-
-            Py_DECREF(py_bytes);
-        } else {
-            long_str = g_strdup(PYGLIB_PyBytes_AsString(py_str));
-        }
-
-        Py_DECREF(py_str);
-        PyErr_Clear();
-        PyErr_Format(PyExc_ValueError, "%s not in range %ld to %ld",
-                     long_str, G_MININT64, G_MAXINT64);
-
-        g_free(long_str);
-        return FALSE;
-    }
-
-    if (long_ < G_MININT64 || long_ > G_MAXINT64) {
-        PyErr_Format (PyExc_ValueError, "%lld not in range %ld to %ld", long_, G_MININT64, G_MAXINT64);
-        return FALSE;
-    }
-
-    arg->v_int64 = long_;
-
-    return TRUE;
-}
-
-gboolean
-_pygi_marshal_in_uint64 (PyGIInvokeState   *state,
-                         PyGIFunctionCache *function_cache,
-                         PyGIArgCache      *arg_cache,
-                         PyObject          *py_arg,
-                         GIArgument        *arg)
-{
-    PyObject *py_long;
-    guint64 ulong_;
-
-    if (!PyNumber_Check(py_arg)) {
-        PyErr_Format (PyExc_TypeError, "Must be number, not %s",
-                      py_arg->ob_type->tp_name);
-        return FALSE;
-    }
-
-    py_long = PYGLIB_PyNumber_Long(py_arg);
-    if (!py_long)
-        return FALSE;
-
-#if PY_VERSION_HEX < 0x03000000
-    if (PyInt_Check (py_long)) {
-        long long_ = PyInt_AsLong(py_long);
-        if (long_ < 0) {
-            PyErr_Format (PyExc_ValueError, "%ld not in range %d to %llu",
-                          long_, 0, G_MAXUINT64);
-            return FALSE;
-        }
-        ulong_ = long_;
-    } else
-#endif
-        ulong_ = PyLong_AsUnsignedLongLong(py_long);
-
-    Py_DECREF(py_long);
-
-    if (PyErr_Occurred()) {
-        /* OverflowError occured but range errors should be returned as ValueError */
-        char *long_str;
-        PyObject *py_str = PyObject_Str(py_long);
-
-        if (PyUnicode_Check(py_str)) {
-            PyObject *py_bytes = PyUnicode_AsUTF8String(py_str);
-            if (py_bytes == NULL)
-                return FALSE;
-
-            long_str = g_strdup(PYGLIB_PyBytes_AsString(py_bytes));
-            if (long_str == NULL) {
-                PyErr_NoMemory();
-                return FALSE;
-            }
-
-            Py_DECREF(py_bytes);
-        } else {
-            long_str = g_strdup(PYGLIB_PyBytes_AsString(py_str));
-        }
-
-        Py_DECREF(py_str);
-        PyErr_Clear();
-        PyErr_Format(PyExc_ValueError, "%s not in range %d to %llu",
-                     long_str, 0, G_MAXUINT64);
-
-        g_free(long_str);
-        return FALSE;
-    }
-
-    if (ulong_ > G_MAXUINT64) {
-        PyErr_Format (PyExc_ValueError, "%llu not in range %d to %llu", ulong_, 0, G_MAXUINT64);
-        return FALSE;
-    }
-
-    arg->v_uint64 = ulong_;
-
-    return TRUE;
-}
-
-gboolean
-_pygi_marshal_in_float (PyGIInvokeState   *state,
-                        PyGIFunctionCache *function_cache,
-                        PyGIArgCache      *arg_cache,
-                        PyObject          *py_arg,
-                        GIArgument        *arg)
-{
-    PyObject *py_float;
-    double double_;
-
-    if (!PyNumber_Check(py_arg)) {
-        PyErr_Format (PyExc_TypeError, "Must be number, not %s",
-                      py_arg->ob_type->tp_name);
-        return FALSE;
-    }
-
-    py_float = PyNumber_Float(py_arg);
-    if (!py_float)
-        return FALSE;
-
-    double_ = PyFloat_AsDouble(py_float);
-    Py_DECREF(py_float);
-
-    if (PyErr_Occurred())
-        return FALSE;
-
-    if (double_ < -G_MAXFLOAT || double_ > G_MAXFLOAT) {
-        PyErr_Format (PyExc_ValueError, "%f not in range %f to %f", double_, -G_MAXFLOAT, G_MAXFLOAT);
-        return FALSE;
-    }
-
-    arg->v_float = double_;
-
-    return TRUE;
-}
-
-gboolean
-_pygi_marshal_in_double (PyGIInvokeState   *state,
-                         PyGIFunctionCache *function_cache,
-                         PyGIArgCache      *arg_cache,
-                         PyObject          *py_arg,
-                         GIArgument        *arg)
-{
-    PyObject *py_float;
-    double double_;
-
-    if (!PyNumber_Check(py_arg)) {
-        PyErr_Format (PyExc_TypeError, "Must be number, not %s",
-                      py_arg->ob_type->tp_name);
-        return FALSE;
-    }
-
-    py_float = PyNumber_Float(py_arg);
-    if (!py_float)
-        return FALSE;
-
-    double_ = PyFloat_AsDouble(py_float);
-    Py_DECREF(py_float);
-
-    if (PyErr_Occurred())
-        return FALSE;
-
-    if (double_ < -G_MAXDOUBLE || double_ > G_MAXDOUBLE) {
-        PyErr_Format (PyExc_ValueError, "%f not in range %f to %f", double_, -G_MAXDOUBLE, G_MAXDOUBLE);
-        return FALSE;
-    }
-
-    arg->v_double = double_;
-
-    return TRUE;
-}
-
-gboolean
-_pygi_marshal_in_unichar (PyGIInvokeState   *state,
-                          PyGIFunctionCache *function_cache,
-                          PyGIArgCache      *arg_cache,
-                          PyObject          *py_arg,
-                          GIArgument        *arg)
-{
-    Py_ssize_t size;
-    gchar *string_;
-
-    if (PyUnicode_Check (py_arg)) {
-       PyObject *py_bytes;
-
-       size = PyUnicode_GET_SIZE (py_arg);
-       py_bytes = PyUnicode_AsUTF8String(py_arg);
-       string_ = strdup(PYGLIB_PyBytes_AsString(py_bytes));
-       Py_DECREF(py_bytes);
-
-#if PY_VERSION_HEX < 0x03000000
-    } else if (PyString_Check (py_arg)) {
-       PyObject *pyuni = PyUnicode_FromEncodedObject (py_arg, "UTF-8", "strict");
-       if (!pyuni)
-           return FALSE;
-
-       size = PyUnicode_GET_SIZE (pyuni);
-       string_ = g_strdup(PyString_AsString(py_arg));
-       Py_DECREF(pyuni);
-#endif
-    } else {
-       PyErr_Format (PyExc_TypeError, "Must be string, not %s",
-                     py_arg->ob_type->tp_name);
-       return FALSE;
-    }
-
-    if (size != 1) {
-       PyErr_Format (PyExc_TypeError, "Must be a one character string, not %ld characters",
-                     size);
-       g_free(string_);
-       return FALSE;
-    }
-
-    arg->v_uint32 = g_utf8_get_char(string_);
-    g_free(string_);
-
-    return TRUE;
-}
-gboolean
-_pygi_marshal_in_gtype (PyGIInvokeState   *state,
-                        PyGIFunctionCache *function_cache,
-                        PyGIArgCache      *arg_cache,
-                        PyObject          *py_arg,
-                        GIArgument        *arg)
-{
-    long type_ = pyg_type_from_object (py_arg);
-
-    if (type_ == 0) {
-        PyErr_Format (PyExc_TypeError, "Must be gobject.GType, not %s",
-                      py_arg->ob_type->tp_name);
-        return FALSE;
-    }
-
-    arg->v_long = type_;
-    return TRUE;
-}
-gboolean
-_pygi_marshal_in_utf8 (PyGIInvokeState   *state,
-                       PyGIFunctionCache *function_cache,
-                       PyGIArgCache      *arg_cache,
-                       PyObject          *py_arg,
-                       GIArgument        *arg)
-{
-    gchar *string_;
-
-    if (py_arg == Py_None) {
-        arg->v_pointer = NULL;
-        return TRUE;
-    }
-
-    if (PyUnicode_Check(py_arg)) {
-        PyObject *pystr_obj = PyUnicode_AsUTF8String (py_arg);
-        if (!pystr_obj)
-            return FALSE;
-
-        string_ = g_strdup(PYGLIB_PyBytes_AsString (pystr_obj));
-        Py_DECREF(pystr_obj);
-    }
-#if PY_VERSION_HEX < 0x03000000
-    else if (PyString_Check(py_arg)) {
-        string_ = g_strdup(PyString_AsString (py_arg));
-    }
-#endif
-    else {
-        PyErr_Format (PyExc_TypeError, "Must be string, not %s",
-                      py_arg->ob_type->tp_name);
-        return FALSE;
-    }
-
-    arg->v_string = string_;
-    return TRUE;
-}
-
-gboolean
-_pygi_marshal_in_filename (PyGIInvokeState   *state,
-                           PyGIFunctionCache *function_cache,
-                           PyGIArgCache      *arg_cache,
-                           PyObject          *py_arg,
-                           GIArgument        *arg)
-{
-    gchar *string_;
-    GError *error = NULL;
-
-    if (PyUnicode_Check(py_arg)) {
-        PyObject *pystr_obj = PyUnicode_AsUTF8String (py_arg);
-        if (!pystr_obj)
-            return FALSE;
-
-        string_ = g_strdup(PYGLIB_PyBytes_AsString (pystr_obj));
-        Py_DECREF(pystr_obj);
-    }
-#if PY_VERSION_HEX < 0x03000000
-    else if (PyString_Check(py_arg)) {
-        string_ = g_strdup(PyString_AsString (py_arg));
-    }
-#endif
-    else {
-        PyErr_Format (PyExc_TypeError, "Must be string, not %s",
-                      py_arg->ob_type->tp_name);
-        return FALSE;
-    }
-
-    arg->v_string = g_filename_from_utf8 (string_, -1, NULL, NULL, &error);
-    g_free(string_);
-
-    if (arg->v_string == NULL) {
-        PyErr_SetString (PyExc_Exception, error->message);
-        g_error_free(error);
-        /* TODO: Convert the error to an exception. */
-        return FALSE;
-    }
-
-    return TRUE;
-}
-
-gboolean
-_pygi_marshal_in_array (PyGIInvokeState   *state,
-                        PyGIFunctionCache *function_cache,
-                        PyGIArgCache      *arg_cache,
-                        PyObject          *py_arg,
-                        GIArgument        *arg)
-{
-    PyGIMarshalInFunc in_marshaller;
-    int i;
-    Py_ssize_t length;
-    GArray *array_ = NULL;
-    PyGISequenceCache *sequence_cache = (PyGISequenceCache *)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 (sequence_cache->fixed_size >= 0 &&
-        sequence_cache->fixed_size != length) {
-        PyErr_Format (PyExc_ValueError, "Must contain %zd items, not %zd",
-                      sequence_cache->fixed_size, length);
-
-        return FALSE;
-    }
-
-    array_ = g_array_sized_new (sequence_cache->is_zero_terminated,
-                                FALSE,
-                                sequence_cache->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);
-
-        goto array_success;
-    }
-
-    in_marshaller = sequence_cache->item_cache->in_marshaller;
-    for (i = 0; i < length; i++) {
-        GIArgument item;
-        PyObject *py_item = PySequence_GetItem (py_arg, i);
-        if (py_item == NULL)
-            goto err;
-
-        if (!in_marshaller(state,
-                           function_cache,
-                           sequence_cache->item_cache,
-                           py_item,
-                           &item))
-            goto err;
-
-        g_array_insert_val(array_, i, item);
-        continue;
-err:
-        if (sequence_cache->item_cache->cleanup != NULL) {
-            GDestroyNotify cleanup = sequence_cache->item_cache->cleanup;
-            /*for(j = 0; j < i; j++)
-                cleanup((gpointer)(array_->data[j]));*/
-        }
-
-        g_array_free(array_, TRUE);
-        _PyGI_ERROR_PREFIX ("Item %i: ", i);
-        return FALSE;
-    }
-
-array_success:
-    if (sequence_cache->len_arg_index >= 0) {
-        /* we have an aux arg to handle */
-        PyGIArgCache *aux_cache =
-            function_cache->args_cache[sequence_cache->len_arg_index];
-
-        if (aux_cache->direction == GI_DIRECTION_INOUT) {
-            gint *len_arg = (gint *)state->in_args[aux_cache->c_arg_index].v_pointer;
-            /* if we are not setup yet just set the in arg */
-            if (len_arg == NULL)
-                state->in_args[aux_cache->c_arg_index].v_long = length;
-            else
-                *len_arg = length;
-        } else {              
-            state->in_args[aux_cache->c_arg_index].v_long = length;
-        }
-    }
-
-    if (sequence_cache->array_type == GI_ARRAY_TYPE_C) {
-        arg->v_pointer = array_->data;
-        g_array_free(array_, FALSE);
-    } else {
-        arg->v_pointer = array_;
-    }
-
-    return TRUE;
-}
-
-gboolean
-_pygi_marshal_in_glist (PyGIInvokeState   *state,
-                        PyGIFunctionCache *function_cache,
-                        PyGIArgCache      *arg_cache,
-                        PyObject          *py_arg,
-                        GIArgument        *arg)
-{
-    PyGIMarshalInFunc in_marshaller;
-    int i;
-    Py_ssize_t length;
-    GList *list_ = NULL;
-    PyGISequenceCache *sequence_cache = (PyGISequenceCache *)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 (sequence_cache->fixed_size >= 0 &&
-        sequence_cache->fixed_size != length) {
-        PyErr_Format (PyExc_ValueError, "Must contain %zd items, not %zd",
-                      sequence_cache->fixed_size, length);
-
-        return FALSE;
-    }
-
-    in_marshaller = sequence_cache->item_cache->in_marshaller;
-    for (i = 0; i < length; i++) {
-        GIArgument item;
-        PyObject *py_item = PySequence_GetItem (py_arg, i);
-        if (py_item == NULL)
-            goto err;
-
-        if (!in_marshaller(state,
-                           function_cache,
-                           sequence_cache->item_cache,
-                           py_item,
-                           &item))
-            goto err;
-
-        list_ = g_list_append(list_, item.v_pointer);
-        continue;
-err:
-        if (sequence_cache->item_cache->cleanup != NULL) {
-            GDestroyNotify cleanup = sequence_cache->item_cache->cleanup;
-        }
-
-        g_list_free(list_);
-        _PyGI_ERROR_PREFIX ("Item %i: ", i);
-        return FALSE;
-    }
-
-    arg->v_pointer = list_;
-    return TRUE;
-}
-
-gboolean
-_pygi_marshal_in_gslist (PyGIInvokeState   *state,
-                         PyGIFunctionCache *function_cache,
-                         PyGIArgCache      *arg_cache,
-                         PyObject          *py_arg,
-                         GIArgument        *arg)
-{
-    PyGIMarshalInFunc in_marshaller;
-    int i;
-    Py_ssize_t length;
-    GSList *list_ = NULL;
-    PyGISequenceCache *sequence_cache = (PyGISequenceCache *)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 (sequence_cache->fixed_size >= 0 &&
-        sequence_cache->fixed_size != length) {
-        PyErr_Format (PyExc_ValueError, "Must contain %zd items, not %zd",
-                      sequence_cache->fixed_size, length);
-
-        return FALSE;
-    }
-
-    in_marshaller = sequence_cache->item_cache->in_marshaller;
-    for (i = 0; i < length; i++) {
-        GIArgument item;
-        PyObject *py_item = PySequence_GetItem (py_arg, i);
-        if (py_item == NULL)
-            goto err;
-
-        if (!in_marshaller(state,
-                           function_cache,
-                           sequence_cache->item_cache,
-                           py_item,
-                           &item))
-            goto err;
-
-        list_ = g_slist_append(list_, item.v_pointer);
-        continue;
-err:
-        if (sequence_cache->item_cache->cleanup != NULL) {
-            GDestroyNotify cleanup = sequence_cache->item_cache->cleanup;
-        }
-
-        g_slist_free(list_);
-        _PyGI_ERROR_PREFIX ("Item %i: ", i);
-        return FALSE;
-    }
-
-    arg->v_pointer = list_;
-    return TRUE;
-}
-
-gboolean
-_pygi_marshal_in_ghash (PyGIInvokeState   *state,
-                        PyGIFunctionCache *function_cache,
-                        PyGIArgCache      *arg_cache,
-                        PyObject          *py_arg,
-                        GIArgument        *arg)
-{
-    PyGIMarshalInFunc key_in_marshaller;
-    PyGIMarshalInFunc value_in_marshaller;
-
-    int i;
-    Py_ssize_t length;
-    PyObject *py_keys, *py_values;
-
-    GHashFunc hash_func;
-    GEqualFunc equal_func;
-
-    GHashTable *hash_ = NULL;
-    PyGIHashCache *hash_cache = (PyGIHashCache *)arg_cache;
-
-    if (py_arg == Py_None) {
-        arg->v_pointer = NULL;
-        return TRUE;
-    }
-
-    py_keys = PyMapping_Keys(py_arg);
-    if (py_keys == NULL) {
-        PyErr_Format (PyExc_TypeError, "Must be mapping, not %s",
-                      py_arg->ob_type->tp_name);
-        return FALSE;
-    }
-
-    length = PyMapping_Length(py_arg);
-    if (length < 0) {
-        Py_DECREF(py_keys);
-        return FALSE;
-    }
-
-    py_values = PyMapping_Values(py_arg);
-    if (py_values == NULL) {
-        Py_DECREF(py_keys);
-        return FALSE;
-    }
-
-    key_in_marshaller = hash_cache->key_cache->in_marshaller;
-    value_in_marshaller = hash_cache->value_cache->in_marshaller;
-
-    switch (hash_cache->key_cache->type_tag) {
-        case GI_TYPE_TAG_UTF8:
-        case GI_TYPE_TAG_FILENAME:
-            hash_func = g_str_hash;
-            equal_func = g_str_equal;
-            break;
-        default:
-            hash_func = NULL;
-            equal_func = NULL;
-    }
-
-    hash_ = g_hash_table_new (hash_func, equal_func);
-    if (hash_ == NULL) {
-        PyErr_NoMemory();
-        Py_DECREF(py_keys);
-        Py_DECREF(py_values);
-        return FALSE;
-    }
-
-    for (i = 0; i < length; i++) {
-        GIArgument key, value;
-        PyObject *py_key = PyList_GET_ITEM (py_keys, i);
-        PyObject *py_value = PyList_GET_ITEM (py_values, i);
-        if (py_key == NULL || py_value == NULL)
-            goto err;
-
-        if (!key_in_marshaller(state,
-                               function_cache,
-                               hash_cache->key_cache,
-                               py_key,
-                               &key))
-            goto err;
-
-        if (!value_in_marshaller(state,
-                                 function_cache,
-                                 hash_cache->value_cache,
-                                 py_value,
-                                 &value))
-            goto err;
-
-        g_hash_table_insert(hash_, key.v_pointer, value.v_pointer);
-        continue;
-err:
-        /* FIXME: cleanup hash keys and values */
-        Py_XDECREF(py_key);
-        Py_XDECREF(py_value);
-        Py_DECREF(py_keys);
-        Py_DECREF(py_values);
-        g_hash_table_unref(hash_);
-        _PyGI_ERROR_PREFIX ("Item %i: ", i);
-        return FALSE;
-    }
-
-    arg->v_pointer = hash_;
-    return TRUE;
-}
-
-gboolean
-_pygi_marshal_in_gerror (PyGIInvokeState   *state,
-                         PyGIFunctionCache *function_cache,
-                         PyGIArgCache      *arg_cache,
-                         PyObject          *py_arg,
-                         GIArgument        *arg)
-{
-    PyErr_Format(PyExc_NotImplementedError,
-                 "Marshalling for GErrors is not implemented");
-    return FALSE;
-}
-
-gboolean
-_pygi_marshal_in_interface_callback (PyGIInvokeState   *state,
-                                     PyGIFunctionCache *function_cache,
-                                     PyGIArgCache      *arg_cache,
-                                     PyObject          *py_arg,
-                                     GIArgument        *arg)
-{
-    GICallableInfo *callable_info;
-    PyGICClosure *closure;
-    PyGIArgCache *user_data_cache = NULL;
-    PyGIArgCache *destroy_cache = NULL;
-    PyGICallbackCache *callback_cache;
-    PyObject *py_user_data = NULL;
-
-    callback_cache = (PyGICallbackCache *)arg_cache;
-
-    if (callback_cache->user_data_index > 0) {
-        user_data_cache = function_cache->args_cache[callback_cache->user_data_index];
-        if (user_data_cache->py_arg_index < state->n_py_in_args) {
-            py_user_data = PyTuple_GetItem(state->py_in_args, user_data_cache->py_arg_index);
-            if (!py_user_data)
-                return FALSE;
-        } else {
-            py_user_data = Py_None;
-            Py_INCREF(Py_None);
-        }
-    }
-
-    if (py_arg == Py_None && !(py_user_data == Py_None || py_user_data == NULL)) {
-        Py_DECREF(py_user_data);
-        PyErr_Format(PyExc_TypeError,
-                     "When passing None for a callback userdata must also be None");
-
-        return FALSE;
-    }
-
-    if (py_arg == Py_None) {
-        Py_XDECREF(py_user_data);
-        return TRUE;
-    }
-
-    if (!PyCallable_Check(py_arg)) {
-        Py_XDECREF(py_user_data);
-        PyErr_Format(PyExc_TypeError,
-                    "Callback needs to be a function or method not %s",
-                    py_arg->ob_type->tp_name);
-
-        return FALSE;
-    }
-
-    if (callback_cache->destroy_notify_index > 0)
-        destroy_cache = function_cache->args_cache[callback_cache->destroy_notify_index];
-
-    callable_info = (GICallableInfo *)callback_cache->interface_info;
-
-    closure = _pygi_make_native_closure (callable_info, callback_cache->scope, py_arg, py_user_data);
-    arg->v_pointer = closure->closure;
-    if (user_data_cache != NULL) {
-        state->in_args[user_data_cache->c_arg_index].v_pointer = closure;
-    }
-
-    if (destroy_cache) {
-        PyGICClosure *destroy_notify = _pygi_destroy_notify_create();
-        state->in_args[destroy_cache->c_arg_index].v_pointer = destroy_notify->closure;
-    }
-
-    return TRUE;
-}
-
-gboolean
-_pygi_marshal_in_interface_enum (PyGIInvokeState   *state,
-                                 PyGIFunctionCache *function_cache,
-                                 PyGIArgCache      *arg_cache,
-                                 PyObject          *py_arg,
-                                 GIArgument        *arg)
-{
-    PyObject *int_;
-    gint is_instance;
-    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
-
-    is_instance = PyObject_IsInstance(py_arg, iface_cache->py_type);
-
-    int_ = PYGLIB_PyNumber_Long(py_arg);
-    if (int_ == NULL) {
-        PyErr_Clear();
-        goto err;
-    }
-
-    arg->v_long = PYGLIB_PyLong_AsLong(int_);
-    Py_DECREF(int_);
-
-    /* If this is not an instance of the Enum type that we want
-     * we need to check if the value is equivilant to one of the
-     * Enum's memebers */
-    if (!is_instance) {
-        int i;
-        gboolean is_found = FALSE;
-
-        for (i = 0; i < g_enum_info_get_n_values(iface_cache->interface_info); i++) {
-            GIValueInfo *value_info =
-                g_enum_info_get_value(iface_cache->interface_info, i);
-            glong enum_value = g_value_info_get_value(value_info);
-            g_base_info_unref( (GIBaseInfo *)value_info);
-            if (arg->v_long == enum_value) {
-                is_found = TRUE;
-                break;
-            }
-        }
-
-        if (!is_found)
-            goto err;
-    }
-
-    return TRUE;
-
-err:
-    PyErr_Format(PyExc_TypeError, "Expected a %s, but got %s",
-                 iface_cache->type_name, py_arg->ob_type->tp_name);
-    return FALSE;
-}
-
-gboolean
-_pygi_marshal_in_interface_flags (PyGIInvokeState   *state,
-                                  PyGIFunctionCache *function_cache,
-                                  PyGIArgCache      *arg_cache,
-                                  PyObject          *py_arg,
-                                  GIArgument        *arg)
-{
-    PyObject *int_;
-    gint is_instance;
-    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
-
-    is_instance = PyObject_IsInstance(py_arg, iface_cache->py_type);
-
-    int_ = PYGLIB_PyNumber_Long(py_arg);
-    if (int_ == NULL) {
-        PyErr_Clear();
-        goto err;
-    }
-
-    arg->v_long = PYGLIB_PyLong_AsLong(int_);
-    Py_DECREF(int_);
-
-    /* only 0 or argument of type Flag is allowed */
-    if (!is_instance && arg->v_long != 0)
-        goto err;
-
-    return TRUE;
-
-err:
-    PyErr_Format (PyExc_TypeError, "Expected a %s, but got %s",
-                  iface_cache->type_name, py_arg->ob_type->tp_name);
-    return FALSE;
-
-}
-
-gboolean
-_pygi_marshal_in_interface_struct (PyGIInvokeState   *state,
-                                   PyGIFunctionCache *function_cache,
-                                   PyGIArgCache      *arg_cache,
-                                   PyObject          *py_arg,
-                                   GIArgument        *arg)
-{
-    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
-
-    if (py_arg == Py_None) {
-        arg->v_pointer = NULL;
-        return TRUE;
-    }
-
-    /* FIXME: handle this large if statement in the cache
-     *        and set the correct marshaller
-     */
-
-    if (iface_cache->g_type == G_TYPE_CLOSURE) {
-        GClosure *closure;
-        if (!PyCallable_Check(py_arg)) {
-            PyErr_Format(PyExc_TypeError, "Must be callable, not %s",
-                         py_arg->ob_type->tp_name);
-            return FALSE;
-        }
-
-        closure = pyg_closure_new(py_arg, NULL, NULL);
-        if (closure == NULL) {
-            PyErr_SetString(PyExc_RuntimeError, "PyObject conversion to GClosure failed");
-            return FALSE;
-        }
-
-        arg->v_pointer = closure;
-        return TRUE;
-    } else if (iface_cache->g_type == G_TYPE_VALUE) {
-        GValue *value;
-        GType object_type;
-
-        object_type = pyg_type_from_object_strict( (PyObject *) py_arg->ob_type, FALSE);
-        if (object_type == G_TYPE_INVALID) {
-            PyErr_SetString (PyExc_RuntimeError, "unable to retrieve object's GType");
-            return FALSE;
-        }
-
-        value = g_slice_new0 (GValue);
-        g_value_init (value, object_type);
-        if (pyg_value_from_pyobject(value, py_arg) < 0) {
-            g_slice_free (GValue, value);
-            PyErr_SetString (PyExc_RuntimeError, "PyObject conversion to GValue failed");
-            return FALSE;
-        }
-
-        arg->v_pointer = value;
-        return TRUE;
-    } else if (iface_cache->is_foreign) {
-        gboolean success;
-        success = pygi_struct_foreign_convert_to_g_argument(py_arg,
-                                                            iface_cache->interface_info,
-                                                            arg_cache->transfer,
-                                                            arg);
-
-        return success;
-    } else if (!PyObject_IsInstance(py_arg, iface_cache->py_type)) {
-        PyErr_Format (PyExc_TypeError, "Expected %s, but got %s",
-                      iface_cache->type_name,
-                      iface_cache->py_type->ob_type->tp_name);
-        return FALSE;
-    }
-
-    if (g_type_is_a (iface_cache->g_type, G_TYPE_BOXED)) {
-        arg->v_pointer = pyg_boxed_get(py_arg, void);
-        if (arg_cache->transfer == GI_TRANSFER_EVERYTHING) {
-            arg->v_pointer = g_boxed_copy(iface_cache->g_type, arg->v_pointer);
-        }
-    } else if (g_type_is_a (iface_cache->g_type, G_TYPE_POINTER) ||
-               iface_cache->g_type  == G_TYPE_NONE) {
-        arg->v_pointer = pyg_pointer_get(py_arg, void);
-    } else {
-        PyErr_Format (PyExc_NotImplementedError, "structure type '%s' is not supported yet", g_type_name(iface_cache->g_type));
-        return FALSE;
-    }
-    return TRUE;
-}
-
-gboolean
-_pygi_marshal_in_interface_boxed (PyGIInvokeState   *state,
-                                  PyGIFunctionCache *function_cache,
-                                  PyGIArgCache      *arg_cache,
-                                  PyObject          *py_arg,
-                                  GIArgument        *arg)
-{
-    PyErr_Format(PyExc_NotImplementedError,
-                 "Marshalling for this type is not implemented yet");
-    return FALSE;
-}
-
-gboolean
-_pygi_marshal_in_interface_object (PyGIInvokeState   *state,
-                                   PyGIFunctionCache *function_cache,
-                                   PyGIArgCache      *arg_cache,
-                                   PyObject          *py_arg,
-                                   GIArgument        *arg)
-{
-    if (py_arg == Py_None) {
-        arg->v_pointer = NULL;
-        return TRUE;
-    }
-
-    if (!PyObject_IsInstance (py_arg, ((PyGIInterfaceCache *)arg_cache)->py_type)) {
-        PyErr_Format (PyExc_TypeError, "Expected %s, but got %s",
-                      ((PyGIInterfaceCache *)arg_cache)->type_name,
-                      ((PyGIInterfaceCache *)arg_cache)->py_type->ob_type->tp_name);
-        return FALSE;
-    }
-
-    arg->v_pointer = pygobject_get(py_arg);
-    if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
-        g_object_ref(arg->v_pointer);
-
-    return TRUE;
-}
-
-gboolean
-_pygi_marshal_in_interface_union (PyGIInvokeState   *state,
-                                  PyGIFunctionCache *function_cache,
-                                  PyGIArgCache      *arg_cache,
-                                  PyObject          *py_arg,
-                                  GIArgument        *arg)
-{
-    PyErr_Format(PyExc_NotImplementedError,
-                 "Marshalling for this type is not implemented yet");
-    return FALSE;
-}
-
-PyObject *
-_pygi_marshal_out_void (PyGIInvokeState   *state,
-                        PyGIFunctionCache *function_cache,
-                        PyGIArgCache      *arg_cache,
-                        GIArgument        *arg)
-{
-    PyObject *py_obj = NULL;
-    if (arg_cache->is_pointer)
-        py_obj = arg->v_pointer;
-    else
-        py_obj = Py_None;
-
-    Py_XINCREF(py_obj);
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_boolean (PyGIInvokeState   *state,
-                           PyGIFunctionCache *function_cache,
-                           PyGIArgCache      *arg_cache,
-                           GIArgument        *arg)
-{
-    PyObject *py_obj = PyBool_FromLong(arg->v_boolean);
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_int8 (PyGIInvokeState   *state,
-                        PyGIFunctionCache *function_cache,
-                        PyGIArgCache      *arg_cache,
-                        GIArgument        *arg)
-{
-    PyObject *py_obj = PYGLIB_PyLong_FromLong(arg->v_int8);
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_uint8 (PyGIInvokeState   *state,
-                         PyGIFunctionCache *function_cache,
-                         PyGIArgCache      *arg_cache,
-                         GIArgument        *arg)
-{
-    PyObject *py_obj =  PYGLIB_PyLong_FromLong(arg->v_uint8);
-
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_int16 (PyGIInvokeState   *state,
-                         PyGIFunctionCache *function_cache,
-                         PyGIArgCache      *arg_cache,
-                         GIArgument        *arg)
-{
-    PyObject *py_obj =  PYGLIB_PyLong_FromLong(arg->v_int16);
-
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_uint16 (PyGIInvokeState   *state,
-                          PyGIFunctionCache *function_cache,
-                          PyGIArgCache      *arg_cache,
-                          GIArgument        *arg)
-{
-    PyObject *py_obj =  PYGLIB_PyLong_FromLong(arg->v_uint16);
-
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_int32 (PyGIInvokeState   *state,
-                         PyGIFunctionCache *function_cache,
-                         PyGIArgCache      *arg_cache,
-                         GIArgument        *arg)
-{
-    PyObject *py_obj = PYGLIB_PyLong_FromLong(arg->v_int32);
-
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_uint32 (PyGIInvokeState   *state,
-                          PyGIFunctionCache *function_cache,
-                          PyGIArgCache      *arg_cache,
-                          GIArgument        *arg)
-{
-    PyObject *py_obj = PyLong_FromLongLong(arg->v_uint32);
-
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_int64 (PyGIInvokeState   *state,
-                         PyGIFunctionCache *function_cache,
-                         PyGIArgCache      *arg_cache,
-                         GIArgument        *arg)
-{
-    PyObject *py_obj = PyLong_FromLongLong(arg->v_int64);
-
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_uint64 (PyGIInvokeState   *state,
-                          PyGIFunctionCache *function_cache,
-                          PyGIArgCache      *arg_cache,
-                          GIArgument        *arg)
-{
-    PyObject *py_obj = PyLong_FromUnsignedLongLong(arg->v_uint64);
-
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_float (PyGIInvokeState   *state,
-                         PyGIFunctionCache *function_cache,
-                         PyGIArgCache      *arg_cache,
-                         GIArgument        *arg)
-{
-    PyObject *py_obj = PyFloat_FromDouble (arg->v_float);
-
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_double (PyGIInvokeState   *state,
-                          PyGIFunctionCache *function_cache,
-                          PyGIArgCache      *arg_cache,
-                          GIArgument        *arg)
-{
-    PyObject *py_obj = PyFloat_FromDouble (arg->v_double);
-
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_unichar (PyGIInvokeState   *state,
-                           PyGIFunctionCache *function_cache,
-                           PyGIArgCache      *arg_cache,
-                           GIArgument        *arg)
-{
-    PyObject *py_obj = NULL;
-
-    /* Preserve the bidirectional mapping between 0 and "" */
-    if (arg->v_uint32 == 0) {
-        py_obj = PYGLIB_PyUnicode_FromString ("");
-    } else if (g_unichar_validate (arg->v_uint32)) {
-        gchar utf8[6];
-        gint bytes;
-
-        bytes = g_unichar_to_utf8 (arg->v_uint32, utf8);
-        py_obj = PYGLIB_PyUnicode_FromStringAndSize ((char*)utf8, bytes);
-    } else {
-        /* TODO: Convert the error to an exception. */
-        PyErr_Format (PyExc_TypeError,
-                      "Invalid unicode codepoint %" G_GUINT32_FORMAT,
-                      arg->v_uint32);
-    }
-
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_gtype (PyGIInvokeState   *state,
-                         PyGIFunctionCache *function_cache,
-                         PyGIArgCache      *arg_cache,
-                         GIArgument        *arg)
-{
-    PyObject *py_obj = NULL;
-
-    py_obj = pyg_type_wrapper_new( (GType)arg->v_long);
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_utf8 (PyGIInvokeState   *state,
-                        PyGIFunctionCache *function_cache,
-                        PyGIArgCache      *arg_cache,
-                        GIArgument        *arg)
-{
-    PyObject *py_obj = NULL;
-    if (arg->v_string == NULL) {
-        py_obj = Py_None;
-        Py_INCREF (py_obj);
-        return py_obj;
-     }
-
-    py_obj = PYGLIB_PyUnicode_FromString (arg->v_string);
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_filename (PyGIInvokeState   *state,
-                            PyGIFunctionCache *function_cache,
-                            PyGIArgCache      *arg_cache,
-                            GIArgument        *arg)
-{
-    gchar *string;
-    PyObject *py_obj = NULL;
-    GError *error = NULL;
-
-    if (arg->v_string == NULL) {
-        py_obj = Py_None;
-        Py_INCREF (py_obj);
-        return py_obj;
-    }
-
-    string = g_filename_to_utf8 (arg->v_string, -1, NULL, NULL, &error);
-    if (string == NULL) {
-        PyErr_SetString (PyExc_Exception, error->message);
-        /* TODO: Convert the error to an exception. */
-        return NULL;
-    }
-
-    py_obj = PYGLIB_PyUnicode_FromString (string);
-    g_free (string);
-
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_array (PyGIInvokeState   *state,
-                         PyGIFunctionCache *function_cache,
-                         PyGIArgCache      *arg_cache,
-                         GIArgument        *arg)
-{
-    GArray *array_;
-    PyObject *py_obj = NULL;
-    PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
-
-    array_ = arg->v_pointer;
-
-     /* 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 (seq_cache->array_type == GI_ARRAY_TYPE_C) {
-        gsize len;
-        if (seq_cache->fixed_size >= 0) {
-            len = seq_cache->fixed_size;
-        } else if (seq_cache->is_zero_terminated) {
-            len = g_strv_length(arg->v_string);
-        } else {
-            GIArgument *len_arg = state->args[seq_cache->len_arg_index];
-            len = len_arg->v_long;
-        }
-
-        array_ = g_array_new(seq_cache->is_zero_terminated,
-                             FALSE,
-                             seq_cache->item_size);
-        if (array_ == NULL) {
-            PyErr_NoMemory();
-            return NULL;
-        }
-
-        array_->data = arg->v_pointer;
-        array_->len = len;
-    }
-
-    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;
-            gboolean is_struct;
-            gsize item_size;
-            PyGIMarshalOutFunc item_out_marshaller;
-            PyGIArgCache *item_arg_cache;
-
-            py_obj = PyList_New(array_->len);
-            if (py_obj == NULL) {
-                if (seq_cache->array_type == GI_ARRAY_TYPE_C)
-                    g_array_unref(array_);
-
-                return NULL;
-            }
-
-            item_arg_cache = seq_cache->item_cache;
-            item_out_marshaller = item_arg_cache->out_marshaller;
-            is_struct = FALSE;
-            if (item_arg_cache->type_tag == GI_TYPE_TAG_INTERFACE) {
-                PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)item_arg_cache;
-                switch (g_base_info_get_type(iface_cache->interface_info)) {
-                    case GI_INFO_TYPE_STRUCT:
-                        case GI_INFO_TYPE_BOXED:
-                            is_struct = TRUE;
-                        default:
-                            break;
-                }
-            }
-
-            item_size = g_array_get_element_size(array_);
-            for (i = 0; i < array_->len; i++) {
-                GIArgument item_arg;
-                PyObject *py_item;
-
-                if (is_struct) {
-                    item_arg.v_pointer = &_g_array_index(array_, GIArgument, i);
-                } else {
-                    memcpy (&item_arg, &_g_array_index (array_, GIArgument, i), item_size);
-                }
-
-                py_item = item_out_marshaller(state,
-                                              function_cache,
-                                              item_arg_cache,
-                                              &item_arg);
-
-                if (py_item == NULL) {
-                    Py_CLEAR(py_obj);
-
-                    if (seq_cache->array_type == GI_ARRAY_TYPE_C)
-                        g_array_unref(array_);
-
-                    return NULL;
-                }
-                PyList_SET_ITEM(py_obj, i, py_item);
-            }
-        }
-    }
-
-    if (seq_cache->array_type == GI_ARRAY_TYPE_C)
-        g_array_free(array_, FALSE);
-
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_glist (PyGIInvokeState   *state,
-                         PyGIFunctionCache *function_cache,
-                         PyGIArgCache      *arg_cache,
-                         GIArgument        *arg)
-{
-    GList *list_;
-    gsize length;
-    gsize i;
-
-    PyGIMarshalOutFunc item_out_marshaller;
-    PyGIArgCache *item_arg_cache;
-    PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
-
-    PyObject *py_obj = NULL;
-
-    list_ = arg->v_pointer;
-    length = g_list_length(list_);
-
-    py_obj = PyList_New(length);
-    if (py_obj == NULL)
-        return NULL;
-
-    item_arg_cache = seq_cache->item_cache;
-    item_out_marshaller = item_arg_cache->out_marshaller;
-
-    for (i = 0; list_ != NULL; list_ = g_list_next (list_), i++) {
-        GIArgument item_arg;
-        PyObject *py_item;
-
-        item_arg.v_pointer = list_->data;
-        py_item = item_out_marshaller(state,
-                                      function_cache,
-                                      item_arg_cache,
-                                      &item_arg);
-
-        if (py_item == NULL) {
-            Py_CLEAR (py_obj);
-            _PyGI_ERROR_PREFIX ("Item %zu: ", i);
-            return NULL;
-        }
-
-        PyList_SET_ITEM (py_obj, i, py_item);
-    }
-
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_gslist (PyGIInvokeState   *state,
-                          PyGIFunctionCache *function_cache,
-                          PyGIArgCache      *arg_cache,
-                          GIArgument        *arg)
-{
-    GSList *list_;
-    gsize length;
-    gsize i;
-
-    PyGIMarshalOutFunc item_out_marshaller;
-    PyGIArgCache *item_arg_cache;
-    PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
-
-    PyObject *py_obj = NULL;
-
-    list_ = arg->v_pointer;
-    length = g_slist_length(list_);
-
-    py_obj = PyList_New(length);
-    if (py_obj == NULL)
-        return NULL;
-
-    item_arg_cache = seq_cache->item_cache;
-    item_out_marshaller = item_arg_cache->out_marshaller;
-
-    for (i = 0; list_ != NULL; list_ = g_slist_next (list_), i++) {
-        GIArgument item_arg;
-        PyObject *py_item;
-
-        item_arg.v_pointer = list_->data;
-        py_item = item_out_marshaller(state,
-                                      function_cache,
-                                      item_arg_cache,
-                                      &item_arg);
-
-        if (py_item == NULL) {
-            Py_CLEAR (py_obj);
-            _PyGI_ERROR_PREFIX ("Item %zu: ", i);
-            return NULL;
-        }
-
-        PyList_SET_ITEM (py_obj, i, py_item);
-    }
-
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_ghash (PyGIInvokeState   *state,
-                         PyGIFunctionCache *function_cache,
-                         PyGIArgCache      *arg_cache,
-                         GIArgument        *arg)
-{
-    GHashTable *hash_;
-    GHashTableIter hash_table_iter;
-
-    PyGIMarshalOutFunc key_out_marshaller;
-    PyGIMarshalOutFunc value_out_marshaller;
-
-    PyGIArgCache *key_arg_cache;
-    PyGIArgCache *value_arg_cache;
-    PyGIHashCache *hash_cache = (PyGIHashCache *)arg_cache;
-
-    GIArgument key_arg;
-    GIArgument value_arg;
-
-    PyObject *py_obj = NULL;
-
-    hash_ = arg->v_pointer;
-
-    if (hash_ == NULL) {
-        py_obj = Py_None;
-        Py_INCREF (py_obj);
-        return py_obj;
-    }
-
-    py_obj = PyDict_New();
-    if (py_obj == NULL)
-        return NULL;
-
-    key_arg_cache = hash_cache->key_cache;
-    key_out_marshaller = key_arg_cache->out_marshaller;
-
-    value_arg_cache = hash_cache->value_cache;
-    value_out_marshaller = value_arg_cache->out_marshaller;
-
-    g_hash_table_iter_init(&hash_table_iter, hash_);
-    while (g_hash_table_iter_next(&hash_table_iter,
-                                  &key_arg.v_pointer,
-                                  &value_arg.v_pointer)) {
-        PyObject *py_key;
-        PyObject *py_value;
-        int retval;
-
-        py_key = key_out_marshaller(state,
-                                    function_cache,
-                                    key_arg_cache,
-                                    &key_arg);
-
-        if (py_key == NULL) {
-            Py_CLEAR (py_obj);
-            return NULL;
-        }
-
-        py_value = value_out_marshaller(state,
-                                        function_cache,
-                                        value_arg_cache,
-                                        &value_arg);
-
-        if (py_value == NULL) {
-            Py_CLEAR (py_obj);
-            Py_DECREF(py_key);
-            return NULL;
-        }
-
-        retval = PyDict_SetItem (py_obj, py_key, py_value);
-
-        Py_DECREF(py_key);
-        Py_DECREF(py_value);
-
-        if (retval < 0) {
-            Py_CLEAR(py_obj);
-            return NULL;
-        }
-    }
-
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_gerror (PyGIInvokeState   *state,
-                          PyGIFunctionCache *function_cache,
-                          PyGIArgCache      *arg_cache,
-                          GIArgument        *arg)
-{
-    PyObject *py_obj = NULL;
-
-    PyErr_Format(PyExc_NotImplementedError,
-                 "Marshalling for gerror out is not implemented");
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_interface_callback(PyGIInvokeState   *state,
-                                     PyGIFunctionCache *function_cache,
-                                     PyGIArgCache      *arg_cache,
-                                     GIArgument        *arg)
-{
-    PyObject *py_obj = NULL;
-
-    PyErr_Format(PyExc_NotImplementedError,
-                 "Callback out values are not supported");
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_interface_enum (PyGIInvokeState   *state,
-                                  PyGIFunctionCache *function_cache,
-                                  PyGIArgCache      *arg_cache,
-                                  GIArgument        *arg)
-{
-    PyObject *py_obj = NULL;
-    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
-
-    if (iface_cache->g_type == G_TYPE_NONE) {
-        py_obj = PyObject_CallFunction (iface_cache->py_type, "l", arg->v_long);
-    } else {
-        py_obj = pyg_enum_from_gtype(iface_cache->g_type, arg->v_long);
-    }
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_interface_flags (PyGIInvokeState   *state,
-                                   PyGIFunctionCache *function_cache,
-                                   PyGIArgCache      *arg_cache,
-                                   GIArgument        *arg)
-{
-    PyObject *py_obj = NULL;
-    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
-    py_obj = pyg_flags_from_gtype(iface_cache->g_type, arg->v_long);
-
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_interface_struct (PyGIInvokeState   *state,
-                                    PyGIFunctionCache *function_cache,
-                                    PyGIArgCache      *arg_cache,
-                                    GIArgument        *arg)
-{
-    PyObject *py_obj = NULL;
-    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
-    GType type = iface_cache->g_type;
-
-    if (g_type_is_a (type, G_TYPE_VALUE)) {
-        py_obj = pyg_value_as_pyobject (arg->v_pointer, FALSE);
-    } else if (g_type_is_a (type, G_TYPE_BOXED)) {
-        py_obj = _pygi_boxed_new ( (PyTypeObject *)iface_cache->py_type, arg->v_pointer, 
-                                  arg_cache->transfer == GI_TRANSFER_EVERYTHING);
-    } else if (g_type_is_a (type, G_TYPE_POINTER)) {
-        if (iface_cache->py_type == NULL ||
-                !PyType_IsSubtype( (PyTypeObject *)iface_cache->py_type, &PyGIStruct_Type)) {
-            g_warn_if_fail(arg_cache->transfer == GI_TRANSFER_NOTHING);
-            py_obj = pyg_pointer_new(type, arg->v_pointer);
-        } else {
-            py_obj = _pygi_struct_new ( (PyTypeObject *)iface_cache->py_type, arg->v_pointer, 
-                                      arg_cache->transfer == GI_TRANSFER_EVERYTHING);
-        }
-    } else if (type == G_TYPE_NONE && iface_cache->is_foreign) {
-        py_obj = pygi_struct_foreign_convert_from_g_argument (iface_cache->interface_info, arg->v_pointer);
-    } else if (type == G_TYPE_NONE) {
-        py_obj = _pygi_struct_new((PyTypeObject *) iface_cache->py_type, arg->v_pointer, 
-                                  arg_cache->transfer == GI_TRANSFER_EVERYTHING);
-    } else {
-        PyErr_Format (PyExc_NotImplementedError, "structure type '%s' is not supported yet", g_type_name (type));
-    }
-
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_interface_interface (PyGIInvokeState   *state,
-                                       PyGIFunctionCache *function_cache,
-                                       PyGIArgCache      *arg_cache,
-                                       GIArgument        *arg)
-{
-    PyObject *py_obj = NULL;
-
-    PyErr_Format(PyExc_NotImplementedError,
-                 "Marshalling for this type is not implemented yet");
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_interface_boxed (PyGIInvokeState   *state,
-                                   PyGIFunctionCache *function_cache,
-                                   PyGIArgCache      *arg_cache,
-                                   GIArgument        *arg)
-{
-    PyObject *py_obj = NULL;
-
-    PyErr_Format(PyExc_NotImplementedError,
-                 "Marshalling for this type is not implemented yet");
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_interface_object (PyGIInvokeState   *state,
-                                    PyGIFunctionCache *function_cache,
-                                    PyGIArgCache      *arg_cache,
-                                    GIArgument        *arg)
-{
-    PyObject *py_obj = pygobject_new (arg->v_pointer);
-
-    if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
-        g_object_unref (arg->v_pointer);
-    
-    return py_obj;
-}
-
-PyObject *
-_pygi_marshal_out_interface_union  (PyGIInvokeState   *state,
-                                    PyGIFunctionCache *function_cache,
-                                    PyGIArgCache      *arg_cache,
-                                    GIArgument        *arg)
-{
-    PyObject *py_obj = NULL;
-
-    PyErr_Format(PyExc_NotImplementedError,
-                 "Marshalling for this type is not implemented yet");
-    return py_obj;
-}
-
diff --git a/gi/pygi-invoke-ng.c b/gi/pygi-invoke-ng.c
new file mode 100644
index 0000000..f88965a
--- /dev/null
+++ b/gi/pygi-invoke-ng.c
@@ -0,0 +1,1179 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2005-2009 Johan Dahlin <johan gnome org>
+ *
+ *   pygi-invoke.c: main invocation function
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "pygi-invoke.h"
+
+struct invocation_state
+{
+    gboolean is_method;
+    gboolean is_constructor;
+
+    gsize n_args;
+    gsize n_in_args;
+    gsize n_out_args;
+    gsize n_backup_args;
+    Py_ssize_t n_py_args;
+    gsize n_aux_in_args;
+    gsize n_aux_out_args;
+    gsize n_return_values;
+
+    guint8 callback_index;
+    guint8 user_data_index;
+    guint8 destroy_notify_index;
+    PyGICClosure *closure;
+
+    glong error_arg_pos;
+
+    GIArgInfo **arg_infos;
+    GITypeInfo **arg_type_infos;
+    GITypeInfo *return_type_info;
+    GITypeTag return_type_tag;
+
+    GIArgument **args;
+    gboolean *args_is_auxiliary;
+
+    GIArgument *in_args;
+    GIArgument *out_args;
+    GIArgument *out_values;
+    GIArgument *backup_args;
+    GIArgument return_arg;
+
+    PyObject *return_value;
+};
+
+static void
+_initialize_invocation_state (struct invocation_state *state,
+                              GIFunctionInfo *info,
+                              PyObject *py_args)
+{
+    GIFunctionInfoFlags flags;
+
+    flags = g_function_info_get_flags (info);
+    state->is_method = (flags & GI_FUNCTION_IS_METHOD) != 0;
+    state->is_constructor = (flags & GI_FUNCTION_IS_CONSTRUCTOR) != 0;
+
+    /* Count arguments. */
+    state->n_args = g_callable_info_get_n_args ( (GICallableInfo *) info);
+    state->n_in_args = 0;
+    state->n_out_args = 0;
+    state->n_backup_args = 0;
+    state->n_aux_in_args = 0;
+    state->n_aux_out_args = 0;
+
+    /* Check the argument count. */
+    state->n_py_args = PyTuple_Size (py_args);
+    g_assert (state->n_py_args >= 0);
+
+    state->error_arg_pos = -1;
+
+    state->arg_infos = g_slice_alloc0 (sizeof (gpointer) * state->n_args);
+    state->arg_type_infos = g_slice_alloc0 (sizeof (gpointer) * state->n_args);
+    state->args_is_auxiliary = g_slice_alloc0 (sizeof (gboolean) * state->n_args);
+
+    state->return_value = NULL;
+    state->closure = NULL;
+    state->return_type_info = NULL;
+    state->args = NULL;
+    state->in_args = NULL;
+    state->out_args = NULL;
+    state->out_values = NULL;
+    state->backup_args = NULL;
+}
+
+static gboolean
+_prepare_invocation_state (struct invocation_state *state,
+                           GIFunctionInfo *function_info, PyObject *py_args)
+{
+    gsize i;
+
+    if (!_pygi_scan_for_callbacks (function_info,
+                                   state->is_method,
+                                   &state->callback_index, &state->user_data_index,
+                                   &state->destroy_notify_index))
+        return FALSE;
+
+    if (state->callback_index != G_MAXUINT8) {
+
+        if (!_pygi_create_callback (function_info,
+                                    state->is_method,
+                                    state->is_constructor,
+                                    state->n_args, state->n_py_args,
+                                    py_args, state->callback_index,
+                                    state->user_data_index,
+                                    state->destroy_notify_index, &state->closure))
+            return FALSE;
+
+        state->args_is_auxiliary[state->callback_index] = FALSE;
+        if (state->destroy_notify_index != G_MAXUINT8) {
+            state->args_is_auxiliary[state->destroy_notify_index] = TRUE;
+            state->n_aux_in_args += 1;
+        }
+    }
+
+    if (state->is_method) {
+        /* The first argument is the instance. */
+        state->n_in_args += 1;
+    }
+
+    /* We do a first (well, second) pass here over the function to scan for special cases.
+     * This is currently array+length combinations, GError and GValue.
+     */
+    for (i = 0; i < state->n_args; i++) {
+        GIDirection direction;
+        GITransfer transfer;
+        GITypeTag arg_type_tag;
+
+        state->arg_infos[i] = g_callable_info_get_arg ( (GICallableInfo *) function_info,
+                                                        i);
+
+        state->arg_type_infos[i] = g_arg_info_get_type (state->arg_infos[i]);
+
+        direction = g_arg_info_get_direction (state->arg_infos[i]);
+        transfer = g_arg_info_get_ownership_transfer (state->arg_infos[i]);
+        arg_type_tag = g_type_info_get_tag (state->arg_type_infos[i]);
+
+        if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) {
+            state->n_in_args += 1;
+        }
+        if (direction == GI_DIRECTION_INOUT) {
+            state->n_backup_args += 1;
+        }
+        if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) {
+            state->n_out_args += 1;
+        }
+
+        switch (arg_type_tag) {
+            case GI_TYPE_TAG_ARRAY:
+            {
+                gint length_arg_pos;
+
+                length_arg_pos = g_type_info_get_array_length (state->arg_type_infos[i]);
+
+                if (length_arg_pos < 0) {
+                    break;
+                }
+
+                /* For array lengths, we're going to delete the length argument;
+                 * so remove the extra backup we just added above */
+                if (direction == GI_DIRECTION_INOUT) {
+                    state->n_backup_args -= 1;
+                }
+
+                g_assert (length_arg_pos < state->n_args);
+                state->args_is_auxiliary[length_arg_pos] = TRUE;
+
+                if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) {
+                    state->n_aux_in_args += 1;
+                }
+                if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) {
+                    state->n_aux_out_args += 1;
+                }
+
+                break;
+            }
+            case GI_TYPE_TAG_ERROR:
+                g_warn_if_fail (state->error_arg_pos < 0);
+                state->error_arg_pos = i;
+                break;
+            default:
+                break;
+        }
+    }
+
+    state->return_type_info = g_callable_info_get_return_type ( (GICallableInfo *) function_info);
+    state->return_type_tag = g_type_info_get_tag (state->return_type_info);
+
+    if (state->return_type_tag == GI_TYPE_TAG_ARRAY) {
+        gint length_arg_pos;
+        length_arg_pos = g_type_info_get_array_length (state->return_type_info);
+
+        if (length_arg_pos >= 0) {
+            g_assert (length_arg_pos < state->n_args);
+            state->args_is_auxiliary[length_arg_pos] = TRUE;
+            state->n_aux_out_args += 1;
+        }
+    }
+
+    state->n_return_values = state->n_out_args - state->n_aux_out_args;
+    if (state->return_type_tag != GI_TYPE_TAG_VOID) {
+        state->n_return_values += 1;
+    }
+
+    {
+        gsize n_py_args_expected;
+        Py_ssize_t py_args_pos;
+
+        n_py_args_expected = state->n_in_args
+                             + (state->is_constructor ? 1 : 0)
+                             - state->n_aux_in_args
+                             - (state->error_arg_pos >= 0 ? 1 : 0);
+
+        if (state->n_py_args != n_py_args_expected) {
+            PyErr_Format (PyExc_TypeError,
+                          "%s() takes exactly %zd argument(s) (%zd given)",
+                          g_base_info_get_name ( (GIBaseInfo *) function_info),
+                          n_py_args_expected, state->n_py_args);
+            return FALSE;
+        }
+
+        /* Check argument typestate-> */
+        py_args_pos = 0;
+        if (state->is_constructor || state->is_method) {
+            py_args_pos += 1;
+        }
+
+        for (i = 0; i < state->n_args; i++) {
+            GIDirection direction;
+            GITypeTag type_tag;
+            PyObject *py_arg;
+            gint retval;
+            gboolean allow_none;
+
+            direction = g_arg_info_get_direction (state->arg_infos[i]);
+            type_tag = g_type_info_get_tag (state->arg_type_infos[i]);
+
+            if (direction == GI_DIRECTION_OUT
+                    || state->args_is_auxiliary[i]
+                    || type_tag == GI_TYPE_TAG_ERROR) {
+                continue;
+            }
+
+            g_assert (py_args_pos < state->n_py_args);
+            py_arg = PyTuple_GET_ITEM (py_args, py_args_pos);
+
+            allow_none = g_arg_info_may_be_null (state->arg_infos[i]);
+
+            retval = _pygi_g_type_info_check_object (state->arg_type_infos[i],
+                                                     py_arg,
+                                                     allow_none);
+
+            if (retval < 0) {
+                return FALSE;
+            } else if (!retval) {
+                _PyGI_ERROR_PREFIX ("argument %zd: ", py_args_pos);
+                return FALSE;
+            }
+
+            py_args_pos += 1;
+        }
+
+        g_assert (py_args_pos == state->n_py_args);
+    }
+
+    state->args = g_slice_alloc0 (sizeof (gpointer) * state->n_args);
+    state->in_args = g_slice_alloc0 (sizeof (GIArgument) * state->n_in_args);
+    state->out_args = g_slice_alloc0 (sizeof (GIArgument) * state->n_out_args);
+    state->out_values = g_slice_alloc0 (sizeof (GIArgument) * state->n_out_args);
+    state->backup_args = g_slice_alloc0 (sizeof (GIArgument) * state->n_backup_args);
+
+    /* Bind args so we can use an unique index. */
+    {
+        gsize in_args_pos;
+        gsize out_args_pos;
+
+        in_args_pos = state->is_method ? 1 : 0;
+        out_args_pos = 0;
+
+        for (i = 0; i < state->n_args; i++) {
+            GIDirection direction;
+            GIBaseInfo *info;
+            gboolean is_caller_allocates;
+
+            direction = g_arg_info_get_direction (state->arg_infos[i]);
+            is_caller_allocates = g_arg_info_is_caller_allocates (state->arg_infos[i]);
+
+            switch (direction) {
+                case GI_DIRECTION_IN:
+                    g_assert (in_args_pos < state->n_in_args);
+                    state->args[i] = &state->in_args[in_args_pos];
+                    in_args_pos += 1;
+                    break;
+                case GI_DIRECTION_INOUT:
+                    g_assert (in_args_pos < state->n_in_args);
+                    g_assert (out_args_pos < state->n_out_args);
+
+                    state->in_args[in_args_pos].v_pointer = &state->out_values[out_args_pos];
+                    in_args_pos += 1;
+                case GI_DIRECTION_OUT:
+                    g_assert (out_args_pos < state->n_out_args);
+
+                    /* caller allocates only applies to structures but GI has
+                     * no way to denote that yet, so we only use caller allocates
+                     * if we see  a structure
+                     */
+                    if (is_caller_allocates) {
+                        GITypeTag type_tag;
+
+                        is_caller_allocates = FALSE;
+                        type_tag = g_type_info_get_tag (state->arg_type_infos[i]);
+
+                        if (type_tag  == GI_TYPE_TAG_INTERFACE) {
+                            GIInfoType info_type;
+
+                            info = g_type_info_get_interface (state->arg_type_infos[i]);
+                            g_assert (info != NULL);
+                            info_type = g_base_info_get_type (info);
+
+                            if (info_type == GI_INFO_TYPE_STRUCT)
+                                is_caller_allocates = TRUE;
+                        }
+                    }
+
+                    if (is_caller_allocates) {
+                        /* if caller allocates only use one level of indirection */
+                        state->out_args[out_args_pos].v_pointer = NULL;
+                        state->args[i] = &state->out_args[out_args_pos];
+                        if (g_type_is_a (g_registered_type_info_get_g_type (info), G_TYPE_BOXED)) {
+                            state->args[i]->v_pointer = _pygi_boxed_alloc (info, NULL);
+                        } else if (g_struct_info_is_foreign((GIStructInfo *) info) ) {
+                            PyObject *foreign_struct =
+                                pygi_struct_foreign_convert_from_g_argument(state->arg_type_infos[i], NULL);
+
+                            pygi_struct_foreign_convert_to_g_argument(
+                                foreign_struct,
+                                state->arg_type_infos[i],
+                                GI_TRANSFER_EVERYTHING,
+                                state->args[i]);
+
+                            Py_DECREF(foreign_struct);
+                        } else {
+                            gssize size = g_struct_info_get_size ( (GIStructInfo *) info);
+                            state->args[i]->v_pointer = g_malloc0 (size);
+                        }
+                    } else {
+                        state->out_args[out_args_pos].v_pointer = &state->out_values[out_args_pos];
+                        state->out_values[out_args_pos].v_pointer = NULL;
+                        state->args[i] = &state->out_values[out_args_pos];
+                    }
+
+                    out_args_pos += 1;
+            }
+        }
+
+        g_assert (in_args_pos == state->n_in_args);
+        g_assert (out_args_pos == state->n_out_args);
+    }
+
+    /* Convert the input arguments. */
+    {
+        Py_ssize_t py_args_pos;
+        gsize backup_args_pos;
+
+        py_args_pos = 0;
+        backup_args_pos = 0;
+
+        if (state->is_constructor) {
+            /* Skip the first argument. */
+            py_args_pos += 1;
+        } else if (state->is_method) {
+            /* Get the instance. */
+            GIBaseInfo *container_info;
+            GIInfoType container_info_type;
+            PyObject *py_arg;
+            gint check_val;
+
+            container_info = g_base_info_get_container (function_info);
+            container_info_type = g_base_info_get_type (container_info);
+
+            g_assert (py_args_pos < state->n_py_args);
+            py_arg = PyTuple_GET_ITEM (py_args, py_args_pos);
+
+            /* In python 2 python takes care of checking the type
+             * of the self instance.  In python 3 it does not
+             * so we have to check it here
+             */
+            check_val = _pygi_g_type_interface_check_object(container_info,
+                                                            py_arg);
+            if (check_val < 0) {
+                return FALSE;
+            } else if (!check_val) {
+                _PyGI_ERROR_PREFIX ("instance: ");
+                return FALSE;
+            }
+
+            switch (container_info_type) {
+                case GI_INFO_TYPE_UNION:
+                case GI_INFO_TYPE_STRUCT:
+                {
+                    GType type;
+
+                    type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) container_info);
+
+                    if (g_type_is_a (type, G_TYPE_BOXED)) {
+                        g_assert (state->n_in_args > 0);
+                        state->in_args[0].v_pointer = pyg_boxed_get (py_arg, void);
+                    } else if (g_type_is_a (type, G_TYPE_POINTER) || type == G_TYPE_NONE) {
+                        g_assert (state->n_in_args > 0);
+                        state->in_args[0].v_pointer = pyg_pointer_get (py_arg, void);
+                    } else {
+                        PyErr_Format (PyExc_TypeError, "unable to convert an instance of '%s'", g_type_name (type));
+                        return FALSE;
+                    }
+
+                    break;
+                }
+                case GI_INFO_TYPE_OBJECT:
+                case GI_INFO_TYPE_INTERFACE:
+                    g_assert (state->n_in_args > 0);
+                    state->in_args[0].v_pointer = pygobject_get (py_arg);
+                    break;
+                default:
+                    /* Other types don't have methods. */
+                    g_assert_not_reached();
+            }
+
+            py_args_pos += 1;
+        }
+
+        for (i = 0; i < state->n_args; i++) {
+            GIDirection direction;
+
+            if (i == state->callback_index) {
+                if (state->closure)
+                    state->args[i]->v_pointer = state->closure->closure;
+                else
+                    /* Some callbacks params accept NULL */
+                    state->args[i]->v_pointer = NULL;
+                py_args_pos++;
+                continue;
+            } else if (i == state->user_data_index) {
+                state->args[i]->v_pointer = state->closure;
+                py_args_pos++;
+                continue;
+            } else if (i == state->destroy_notify_index) {
+                if (state->closure) {
+                    /* No need to clean up if the callback is NULL */
+                    PyGICClosure *destroy_notify = _pygi_destroy_notify_create();
+                    state->args[i]->v_pointer = destroy_notify->closure;
+                }
+                continue;
+            }
+
+            if (state->args_is_auxiliary[i]) {
+                continue;
+            }
+
+            direction = g_arg_info_get_direction (state->arg_infos[i]);
+
+            if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) {
+                PyObject *py_arg;
+                GITypeTag arg_type_tag;
+                GITransfer transfer;
+
+                arg_type_tag = g_type_info_get_tag (state->arg_type_infos[i]);
+
+                if (arg_type_tag == GI_TYPE_TAG_ERROR) {
+                    GError **error;
+
+                    error = g_slice_new (GError *);
+                    *error = NULL;
+
+                    state->args[i]->v_pointer = error;
+                    continue;
+                }
+
+                transfer = g_arg_info_get_ownership_transfer (state->arg_infos[i]);
+
+                g_assert (py_args_pos < state->n_py_args);
+                py_arg = PyTuple_GET_ITEM (py_args, py_args_pos);
+
+                *state->args[i] = _pygi_argument_from_object (py_arg, state->arg_type_infos[i], transfer);
+
+                if (PyErr_Occurred()) {
+                    /* TODO: release previous input arguments. */
+                    return FALSE;
+                }
+
+                if (direction == GI_DIRECTION_INOUT) {
+                    /* We need to keep a copy of the argument to be able to release it later. */
+                    g_assert (backup_args_pos < state->n_backup_args);
+                    state->backup_args[backup_args_pos] = *state->args[i];
+                    backup_args_pos += 1;
+                }
+
+                if (arg_type_tag == GI_TYPE_TAG_ARRAY) {
+                    GArray *array;
+                    gssize length_arg_pos;
+
+                    array = state->args[i]->v_pointer;
+
+                    length_arg_pos = g_type_info_get_array_length (state->arg_type_infos[i]);
+                    if (length_arg_pos >= 0) {
+                        int len = 0;
+                        /* Set the auxiliary argument holding the length. */
+                        if (array)
+                            len = array->len;
+
+                        state->args[length_arg_pos]->v_size = len;
+                    }
+
+                    /* Get rid of the GArray. */
+                    if ( (array != NULL) &&
+                            (g_type_info_get_array_type (state->arg_type_infos[i]) == GI_ARRAY_TYPE_C)) {
+                        state->args[i]->v_pointer = array->data;
+
+                        if (direction != GI_DIRECTION_INOUT || transfer != GI_TRANSFER_NOTHING) {
+                            /* The array hasn't been referenced anywhere, so free it to avoid losing memory. */
+                            g_array_free (array, FALSE);
+                        }
+                    }
+                }
+
+                py_args_pos += 1;
+            }
+        }
+
+        g_assert (py_args_pos == state->n_py_args);
+        g_assert (backup_args_pos == state->n_backup_args);
+    }
+
+    return TRUE;
+}
+
+static inline gboolean
+_invoke_function (PyGIInvokeState *state,
+                  PyGIFunctionCache *cache,
+                  GIFunctionInfo *function_info)
+{
+    GError *error;
+    gint retval;
+
+    error = NULL;
+
+    pyg_begin_allow_threads;
+
+    /* FIXME: use this for now but we can streamline the call */
+    retval = g_function_info_invoke ( (GIFunctionInfo *) function_info,
+                                      state->in_args,
+                                      cache->n_in_args,
+                                      state->out_args,
+                                      cache->n_out_args,
+                                      &state->return_arg,
+                                      &error);
+    pyg_end_allow_threads;
+
+    if (!retval) {
+        g_assert (error != NULL);
+        /* TODO: raise the right error, out of the error domain. */
+        PyErr_SetString (PyExc_RuntimeError, error->message);
+        g_error_free (error);
+
+        /* TODO: release input arguments. */
+
+        return FALSE;
+    }
+
+    if (state->error != NULL) {
+        /* TODO: raise the right error, out of the error domain, if applicable. */
+        PyErr_SetString (PyExc_Exception, state->error->message);
+
+        /* TODO: release input arguments. */
+
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+static gboolean
+_process_invocation_state (struct invocation_state *state,
+                           GIFunctionInfo *function_info, PyObject *py_args)
+{
+    gsize i;
+
+    /* Convert the return value. */
+    if (state->is_constructor) {
+        PyTypeObject *py_type;
+        GIBaseInfo *info;
+        GIInfoType info_type;
+        GITransfer transfer;
+
+        if (state->return_arg.v_pointer == NULL) {
+            PyErr_SetString (PyExc_TypeError, "constructor returned NULL");
+            return FALSE;
+        }
+
+        g_assert (state->n_py_args > 0);
+        py_type = (PyTypeObject *) PyTuple_GET_ITEM (py_args, 0);
+
+        info = g_type_info_get_interface (state->return_type_info);
+        g_assert (info != NULL);
+
+        info_type = g_base_info_get_type (info);
+
+        transfer = g_callable_info_get_caller_owns ( (GICallableInfo *) function_info);
+
+        switch (info_type) {
+            case GI_INFO_TYPE_UNION:
+            case GI_INFO_TYPE_STRUCT:
+            {
+                GType type;
+
+                type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info);
+
+                if (g_type_is_a (type, G_TYPE_BOXED)) {
+                    g_warn_if_fail (transfer == GI_TRANSFER_EVERYTHING);
+                    state->return_value = _pygi_boxed_new (py_type, state->return_arg.v_pointer, transfer == GI_TRANSFER_EVERYTHING);
+                } else if (type == G_TYPE_NONE && g_struct_info_is_foreign (info)) {
+                    state->return_value =
+                        pygi_struct_foreign_convert_from_g_argument (
+                            state->return_type_info, state->return_arg.v_pointer);
+                } else if (g_type_is_a (type, G_TYPE_POINTER) || type == G_TYPE_NONE) {
+                    if (transfer != GI_TRANSFER_NOTHING)
+                        g_warning ("Return argument in %s returns a struct "
+                                   "with a transfer mode of \"full\" "
+                                   "Transfer mode should be set to None for "
+                                   "struct types as there is no way to free "
+                                   "them safely.  Ignoring transfer mode "
+                                   "to prevent a potential invalid free. "
+                                   "This may cause a leak in your application.",
+                                   g_base_info_get_name ( (GIBaseInfo *) function_info) );
+
+                    state->return_value = _pygi_struct_new (py_type, state->return_arg.v_pointer, FALSE);
+                } else {
+                    PyErr_Format (PyExc_TypeError, "cannot create '%s' instances", py_type->tp_name);
+                    g_base_info_unref (info);
+                    return FALSE;
+                }
+
+                break;
+            }
+            case GI_INFO_TYPE_OBJECT:
+                if (state->return_arg.v_pointer == NULL) {
+                    PyErr_SetString (PyExc_TypeError, "constructor returned NULL");
+                    break;
+                }
+                state->return_value = pygobject_new (state->return_arg.v_pointer);
+                if (transfer == GI_TRANSFER_EVERYTHING) {
+                    /* The new wrapper increased the reference count, so decrease it. */
+                    g_object_unref (state->return_arg.v_pointer);
+                }
+                break;
+            default:
+                /* Other types don't have neither methods nor constructors. */
+                g_assert_not_reached();
+        }
+
+        g_base_info_unref (info);
+
+        if (state->return_value == NULL) {
+            /* TODO: release arguments. */
+            return FALSE;
+        }
+    } else {
+        GITransfer transfer;
+
+        if ( (state->return_type_tag == GI_TYPE_TAG_ARRAY) &&
+                (g_type_info_get_array_type (state->return_type_info) == GI_ARRAY_TYPE_C)) {
+            /* Create a #GArray. */
+            state->return_arg.v_pointer = _pygi_argument_to_array (&state->return_arg, state->args, state->return_type_info, state->is_method);
+        }
+
+        transfer = g_callable_info_get_caller_owns ( (GICallableInfo *) function_info);
+
+        state->return_value = _pygi_argument_to_object (&state->return_arg, state->return_type_info, transfer);
+        if (state->return_value == NULL) {
+            /* TODO: release argument. */
+            return FALSE;
+        }
+
+        _pygi_argument_release (&state->return_arg, state->return_type_info, transfer, GI_DIRECTION_OUT);
+
+        if (state->return_type_tag == GI_TYPE_TAG_ARRAY
+                && transfer == GI_TRANSFER_NOTHING) {
+            /* We created a #GArray, so free it. */
+            state->return_arg.v_pointer = g_array_free (state->return_arg.v_pointer, FALSE);
+        }
+    }
+
+    /* Convert output arguments and release arguments. */
+    {
+        gsize return_values_pos;
+
+        return_values_pos = 0;
+
+        if (state->n_return_values > 1) {
+            /* Return a tuple. */
+            PyObject *return_values;
+
+            return_values = PyTuple_New (state->n_return_values);
+            if (return_values == NULL) {
+                /* TODO: release arguments. */
+                return FALSE;
+            }
+
+            if (state->return_type_tag == GI_TYPE_TAG_VOID) {
+                /* The current return value is None. */
+                Py_DECREF (state->return_value);
+            } else {
+                /* Put the return value first. */
+                g_assert (state->return_value != NULL);
+                PyTuple_SET_ITEM (return_values, return_values_pos, state->return_value);
+                return_values_pos += 1;
+            }
+
+            state->return_value = return_values;
+        }
+
+        for (i = 0; i < state->n_args; i++) {
+            GIDirection direction;
+            GITypeTag type_tag;
+            GITransfer transfer;
+
+            if (state->args_is_auxiliary[i]) {
+                /* Auxiliary arguments are handled at the same time as their relatives. */
+                continue;
+            }
+
+            direction = g_arg_info_get_direction (state->arg_infos[i]);
+            transfer = g_arg_info_get_ownership_transfer (state->arg_infos[i]);
+
+            type_tag = g_type_info_get_tag (state->arg_type_infos[i]);
+
+            if ( (type_tag == GI_TYPE_TAG_ARRAY) &&
+                    (g_type_info_get_array_type (state->arg_type_infos[i]) == GI_ARRAY_TYPE_C) &&
+                    (direction != GI_DIRECTION_IN || transfer == GI_TRANSFER_NOTHING)) {
+                /* Create a #GArray. */
+                state->args[i]->v_pointer = _pygi_argument_to_array (state->args[i], state->args, state->arg_type_infos[i], state->is_method);
+            }
+
+            if (direction == GI_DIRECTION_INOUT || direction == GI_DIRECTION_OUT) {
+                /* Convert the argument. */
+                PyObject *obj;
+
+                /* If we created it, deallocate when it goes out of scope
+                 * otherwise it is unsafe to deallocate random structures
+                 * we are given
+                 */
+                if (type_tag == GI_TYPE_TAG_INTERFACE) {
+                    GIBaseInfo *info;
+                    GIInfoType info_type;
+
+                    info = g_type_info_get_interface (state->arg_type_infos[i]);
+                    g_assert (info != NULL);
+                    info_type = g_base_info_get_type (info);
+
+                    if ( (info_type == GI_INFO_TYPE_STRUCT) &&
+                             !g_struct_info_is_foreign((GIStructInfo *) info) ) {
+                        if (g_arg_info_is_caller_allocates (state->arg_infos[i])) {
+                            transfer = GI_TRANSFER_EVERYTHING;
+                        } else if (transfer == GI_TRANSFER_EVERYTHING) {
+                            transfer = GI_TRANSFER_NOTHING;
+                            g_warning ("Out argument %ld in %s returns a struct "
+                                       "with a transfer mode of \"full\". "
+                                       "Transfer mode should be set to \"none\" for "
+                                       "struct type returns as there is no way to free "
+                                       "them safely.  Ignoring transfer mode "
+                                       "to prevent a potential invalid free. "
+                                       "This may cause a leak in your application.",
+                                       i, g_base_info_get_name ( (GIBaseInfo *) function_info) );
+                        }
+                    }
+                }
+
+                obj = _pygi_argument_to_object (state->args[i], state->arg_type_infos[i], transfer);
+                if (obj == NULL) {
+                    /* TODO: release arguments. */
+                    return FALSE;
+                }
+
+                g_assert (return_values_pos < state->n_return_values);
+
+                if (state->n_return_values > 1) {
+                    PyTuple_SET_ITEM (state->return_value, return_values_pos, obj);
+                } else {
+                    /* The current return value is None. */
+                    Py_DECREF (state->return_value);
+                    state->return_value = obj;
+                }
+
+                return_values_pos += 1;
+            }
+
+        }
+
+        g_assert (state->n_return_values <= 1 || return_values_pos == state->n_return_values);
+    }
+
+    return TRUE;
+}
+
+static void
+_free_invocation_state (struct invocation_state *state)
+{
+    gsize i;
+    gsize backup_args_pos;
+
+    if (state->return_type_info != NULL) {
+        g_base_info_unref ( (GIBaseInfo *) state->return_type_info);
+    }
+
+    if (state->closure != NULL) {
+        if (state->closure->scope == GI_SCOPE_TYPE_CALL)
+            _pygi_invoke_closure_free (state->closure);
+    }
+
+    /* release all arguments. */
+    backup_args_pos = 0;
+    for (i = 0; i < state->n_args; i++) {
+
+        if (state->args_is_auxiliary[i]) {
+            /* Auxiliary arguments are not released. */
+            continue;
+        }
+
+        if (state->arg_infos[i] != NULL
+            && state->arg_type_infos[i] != NULL) {
+            GIDirection direction;
+            GITypeTag type_tag;
+            GITransfer transfer;
+
+            direction = g_arg_info_get_direction (state->arg_infos[i]);
+            transfer = g_arg_info_get_ownership_transfer (state->arg_infos[i]);
+
+            /* Release the argument. */
+            if (direction == GI_DIRECTION_INOUT) {
+                if (state->args != NULL) {
+                    _pygi_argument_release (&state->backup_args[backup_args_pos],
+                                            state->arg_type_infos[i],
+                                            transfer, GI_DIRECTION_IN);
+                }
+                backup_args_pos += 1;
+            }
+            if (state->args != NULL && state->args[i] != NULL) {
+                _pygi_argument_release (state->args[i], state->arg_type_infos[i],
+                                        transfer, direction);
+
+                type_tag = g_type_info_get_tag (state->arg_type_infos[i]);
+                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. */
+                    state->args[i]->v_pointer = g_array_free (state->args[i]->v_pointer, FALSE);
+                }
+            }
+
+        }
+
+        if (state->arg_type_infos[i] != NULL)
+            g_base_info_unref ( (GIBaseInfo *) state->arg_type_infos[i]);
+        if (state->arg_infos[i] != NULL)
+            g_base_info_unref ( (GIBaseInfo *) state->arg_infos[i]);
+    }
+    g_assert (backup_args_pos == state->n_backup_args);
+
+    g_slice_free1 (sizeof (gpointer) * state->n_args, state->arg_infos);
+    g_slice_free1 (sizeof (gpointer) * state->n_args, state->arg_type_infos);
+    g_slice_free1 (sizeof (gboolean) * state->n_args, state->args_is_auxiliary);
+
+    if (state->args != NULL) {
+        g_slice_free1 (sizeof (gpointer) * state->n_args, state->args);
+    }
+
+    if (state->in_args != NULL) {
+        g_slice_free1 (sizeof (GIArgument) * state->n_in_args, state->in_args);
+    }
+
+    if (state->out_args != NULL) {
+        g_slice_free1 (sizeof (GIArgument) * state->n_out_args, state->out_args);
+    }
+
+    if (state->out_values != NULL) {
+        g_slice_free1 (sizeof (GIArgument) * state->n_out_args, state->out_values);
+    }
+
+    if (state->backup_args != NULL) {
+        g_slice_free1 (sizeof (GIArgument) * state->n_backup_args, state->backup_args);
+    }
+
+    if (PyErr_Occurred()) {
+        Py_CLEAR (state->return_value);
+    }
+}
+
+static inline gboolean
+_invoke_state_init_from_function_cache(PyGIInvokeState *state,
+                                       PyGIFunctionCache *cache,
+                                       PyObject *py_args)
+{
+    state->py_in_args = py_args;
+    state->n_py_in_args = PySequence_Length(py_args);
+    state->args = g_slice_alloc0(cache->n_args * sizeof(GIArgument *));
+    if (state->args == NULL && cache->n_args != 0) {
+        PyErr_NoMemory();
+        return FALSE;
+    }
+
+    state->in_args = g_slice_alloc0(cache->n_in_args * sizeof(GIArgument));
+    if (state->in_args == NULL && cache->n_in_args != 0) {
+        PyErr_NoMemory();
+        return FALSE;
+    }
+
+    state->out_values = g_slice_alloc0(cache->n_out_args * sizeof(GIArgument));
+    if (state->out_values == NULL && cache->n_out_args != 0) {
+        PyErr_NoMemory();
+        return FALSE;
+    }
+
+    state->out_args = g_slice_alloc0(cache->n_out_args * sizeof(GIArgument));
+    if (state->out_args == NULL && cache->n_out_args != 0) {
+        PyErr_NoMemory();
+        return FALSE;
+    }
+
+    state->error = NULL;
+
+    return TRUE;
+}
+
+static inline void
+_invoke_state_clear(PyGIInvokeState *state, PyGIFunctionCache *cache)
+{
+    g_slice_free1(cache->n_args * sizeof(GIArgument *), state->args);
+    g_slice_free1(cache->n_in_args * sizeof(GIArgument), state->in_args);
+    g_slice_free1(cache->n_out_args * sizeof(GIArgument), state->out_args);
+    g_slice_free1(cache->n_out_args * sizeof(GIArgument), state->out_values);
+}
+
+static inline gboolean
+_invoke_marshal_in_args(PyGIInvokeState *state, PyGIFunctionCache *cache)
+{
+    int i, in_count, out_count;
+    in_count = 0;
+    out_count = 0;
+
+    if (state->n_py_in_args > cache->n_py_args) {
+        PyErr_Format(PyExc_TypeError,
+                     "%s() takes exactly %zd argument(s) (%zd given)",
+                     cache->name,
+                     cache->n_py_args,
+                     state->n_py_in_args);
+        return FALSE;
+    }
+
+    for (i = 0; i < cache->n_args; i++) {
+        GIArgument *c_arg;
+        PyGIArgCache *arg_cache = cache->args_cache[i];
+        PyObject *py_arg = NULL;
+
+        switch (arg_cache->direction) {
+            case GI_DIRECTION_IN:
+                state->args[i] = &(state->in_args[in_count]);
+                in_count++;
+
+                if (arg_cache->aux_type > 0)
+                    continue;
+
+                if (arg_cache->py_arg_index >= state->n_py_in_args) {
+                    PyErr_Format(PyExc_TypeError,
+                                 "%s() takes exactly %zd argument(s) (%zd given)",
+                                  cache->name,
+                                  cache->n_py_args,
+                                  state->n_py_in_args);
+                    return FALSE;
+                }
+
+                py_arg =
+                    PyTuple_GET_ITEM(state->py_in_args,
+                                     arg_cache->py_arg_index);
+
+                break;
+            case GI_DIRECTION_INOUT:
+                /* this will be filled in if it is an aux value */
+                if (state->in_args[in_count].v_pointer != NULL)
+                    state->out_values[out_count] = state->in_args[in_count];
+
+                state->in_args[in_count].v_pointer = &state->out_values[out_count];
+                in_count++;
+
+                if (arg_cache->aux_type != PYGI_AUX_TYPE_IGNORE) {
+                    if (arg_cache->py_arg_index >= state->n_py_in_args) {
+                        PyErr_Format(PyExc_TypeError,
+                                     "%s() takes exactly %zd argument(s) (%zd given)",
+                                      cache->name,
+                                      cache->n_py_args,
+                                      state->n_py_in_args);
+                        return FALSE;
+                    }
+
+                    py_arg =
+                        PyTuple_GET_ITEM(state->py_in_args,
+                                         arg_cache->py_arg_index);
+                }
+            case GI_DIRECTION_OUT:
+                if (arg_cache->is_caller_allocates) {
+                    PyGIInterfaceCache *iface_cache =
+                        (PyGIInterfaceCache *)arg_cache;
+
+                    g_assert(arg_cache->type_tag == GI_TYPE_TAG_INTERFACE);
+
+                    state->out_args[out_count].v_pointer = NULL;
+                    state->args[i] = &state->out_args[out_count];
+                    if (iface_cache->g_type == G_TYPE_BOXED) {
+                        state->args[i]->v_pointer =
+                            _pygi_boxed_alloc(iface_cache->interface_info, NULL);
+                    } else if (iface_cache->is_foreign) {
+                        PyObject *foreign_struct =
+                            pygi_struct_foreign_convert_from_g_argument(
+                                iface_cache->interface_info,
+                                NULL);
+
+                        pygi_struct_foreign_convert_to_g_argument(
+                            foreign_struct,
+                            iface_cache->interface_info,
+                            GI_TRANSFER_EVERYTHING,
+                            state->args[i]);
+                    } else {
+                        gssize size =
+                            g_struct_info_get_size(
+                                (GIStructInfo *)iface_cache->interface_info);
+                        state->args[i]->v_pointer = g_malloc0(size);
+                    }
+
+                } else {
+                    state->out_args[out_count].v_pointer = &state->out_values[out_count];
+                    state->args[i] = &state->out_values[out_count];
+                }
+                out_count++;
+                break;
+        }
+
+        c_arg = state->args[i];
+        if (arg_cache->in_marshaller != NULL) {
+            if (!arg_cache->allow_none && py_arg == Py_None) {
+                PyErr_Format(PyExc_TypeError,
+                             "Argument %i does not allow None as a value",
+                             i);
+
+                return FALSE;
+            }
+            gboolean success = arg_cache->in_marshaller(state,
+                                                        cache,
+                                                        arg_cache,
+                                                        py_arg,
+                                                        c_arg);
+            if (!success)
+                return FALSE;
+        }
+
+    }
+
+    return TRUE;
+}
+
+static inline PyObject *
+_invoke_marshal_out_args(PyGIInvokeState *state, PyGIFunctionCache *cache)
+{
+    PyObject *py_out = NULL;
+    PyObject *py_return = NULL;
+    int total_out_args = cache->n_out_args;
+    gboolean has_return = FALSE;
+
+    if (cache->return_cache) {
+        if (cache->is_constructor) {
+            if (state->return_arg.v_pointer == NULL) {
+                PyErr_SetString (PyExc_TypeError, "constructor returned NULL");
+                return NULL;
+            }
+        }
+
+        py_return = cache->return_cache->out_marshaller(state,
+                                                        cache,
+                                                        cache->return_cache,
+                                                        &state->return_arg);
+        if (py_return == NULL)
+            return NULL;
+
+        if (cache->return_cache->type_tag != GI_TYPE_TAG_VOID) {
+            total_out_args++;
+            has_return = TRUE;
+        }
+    }
+
+    total_out_args -= cache->n_out_aux_args;
+
+    if (cache->n_out_args - cache->n_out_aux_args  == 0) {
+        py_out = py_return;
+    } else if (total_out_args == 1) {
+        /* if we get here there is one out arg an no return */
+        PyGIArgCache *arg_cache = (PyGIArgCache *)cache->out_args->data;
+        py_out = arg_cache->out_marshaller(state,
+                                           cache,
+                                           arg_cache,
+                                           state->args[arg_cache->c_arg_index]);
+    } else {
+        int out_cache_index = 0;
+        int py_arg_index = 0;
+        GSList *cache_item = cache->out_args;
+        /* return a tuple */
+        py_out = PyTuple_New(total_out_args);
+        if (has_return) {
+            PyTuple_SET_ITEM(py_out, py_arg_index, py_return);
+            py_arg_index++;
+        }
+
+        for(; py_arg_index < total_out_args; py_arg_index++) {
+            PyGIArgCache *arg_cache = (PyGIArgCache *)cache_item->data;
+            PyObject *py_obj = arg_cache->out_marshaller(state,
+                                                         cache,
+                                                         arg_cache,
+                                                         state->args[arg_cache->c_arg_index]);
+
+            if (py_obj == NULL)
+                return NULL;
+
+            PyTuple_SET_ITEM(py_out, py_arg_index, py_obj);
+            cache_item = cache_item->next;
+        }
+    }
+    return py_out;
+}
+
+PyObject *
+_wrap_g_function_info_invoke (PyGIBaseInfo *self, PyObject *py_args)
+{
+    PyGIInvokeState state = { 0, };
+    PyObject *ret;
+
+    if (self->cache == NULL) {
+        self->cache = _pygi_function_cache_new(self->info);
+        if (self->cache == NULL)
+            return NULL;
+    }
+
+    _invoke_state_init_from_function_cache(&state, self->cache, py_args);
+    if (!_invoke_marshal_in_args (&state, self->cache))
+        goto err;
+
+    if (!_invoke_function(&state, self->cache, self->info))
+        goto err;
+
+    ret = _invoke_marshal_out_args (&state, self->cache);
+    _invoke_state_clear (&state, self->cache);
+    return ret;
+
+err:
+    _invoke_state_clear (&state, self->cache);
+    return NULL;
+}
+
diff --git a/gi/pygi-invoke.c b/gi/pygi-invoke.c
index f88965a..a2b0fef 100644
--- a/gi/pygi-invoke.c
+++ b/gi/pygi-invoke.c
@@ -21,6 +21,7 @@
  * USA
  */
 
+#include <pyglib.h>
 #include "pygi-invoke.h"
 
 struct invocation_state
@@ -58,19 +59,46 @@ struct invocation_state
     GIArgument *backup_args;
     GIArgument return_arg;
 
-    PyObject *return_value;
+    PyObject  *return_value;
+
+    GType      implementor_gtype;
+
+    /* hack to avoid treating C arrays as GArrays during free
+     * due to overly complicated array handling
+     * this will be removed when the new invoke branch is merged
+     */
+    gboolean c_arrays_are_wrapped;
 };
 
-static void
+static gboolean
 _initialize_invocation_state (struct invocation_state *state,
                               GIFunctionInfo *info,
-                              PyObject *py_args)
+                              PyObject *py_args,
+                              PyObject *kwargs)
 {
-    GIFunctionInfoFlags flags;
+    if (g_base_info_get_type (info) == GI_INFO_TYPE_FUNCTION) {
+        GIFunctionInfoFlags flags = g_function_info_get_flags (info);
+
+        state->is_method = (flags & GI_FUNCTION_IS_METHOD) != 0;
+        state->is_constructor = (flags & GI_FUNCTION_IS_CONSTRUCTOR) != 0;
+        state->implementor_gtype = 0;
+    } else {
+        PyObject *obj;
 
-    flags = g_function_info_get_flags (info);
-    state->is_method = (flags & GI_FUNCTION_IS_METHOD) != 0;
-    state->is_constructor = (flags & GI_FUNCTION_IS_CONSTRUCTOR) != 0;
+        state->is_method = TRUE;
+        state->is_constructor = FALSE;
+
+        obj = PyDict_GetItemString (kwargs, "gtype");
+        if (obj == NULL) {
+            PyErr_SetString (PyExc_TypeError,
+                             "need the GType of the implementor class");
+            return FALSE;
+        }
+
+        state->implementor_gtype = pyg_type_from_object (obj);
+        if (state->implementor_gtype == 0)
+            return FALSE;
+    }
 
     /* Count arguments. */
     state->n_args = g_callable_info_get_n_args ( (GICallableInfo *) info);
@@ -98,6 +126,13 @@ _initialize_invocation_state (struct invocation_state *state,
     state->out_args = NULL;
     state->out_values = NULL;
     state->backup_args = NULL;
+
+    /* HACK: this gets marked FALSE whenever a C array in the args is
+     *       not wrapped by a GArray
+     */
+    state->c_arrays_are_wrapped = TRUE;
+
+    return TRUE;
 }
 
 static gboolean
@@ -532,6 +567,20 @@ _prepare_invocation_state (struct invocation_state *state,
                             (g_type_info_get_array_type (state->arg_type_infos[i]) == GI_ARRAY_TYPE_C)) {
                         state->args[i]->v_pointer = array->data;
 
+                        /* HACK: We have unwrapped a C array so
+                         *       set the state to reflect this.
+                         *       If there is an error between now
+                         *       and when we rewrap the array
+                         *       we will leak C arrays due to
+                         *       being in an inconsitant state.
+                         *       e.g. for interfaces with more
+                         *       than one C array argument, an
+                         *       error may occure when not all
+                         *       C arrays have been rewrapped.
+                         *       This will be removed once the invoke
+                         *       rewrite branch is merged.
+                         */
+                        state->c_arrays_are_wrapped = FALSE;
                         if (direction != GI_DIRECTION_INOUT || transfer != GI_TRANSFER_NOTHING) {
                             /* The array hasn't been referenced anywhere, so free it to avoid losing memory. */
                             g_array_free (array, FALSE);
@@ -550,10 +599,9 @@ _prepare_invocation_state (struct invocation_state *state,
     return TRUE;
 }
 
-static inline gboolean
-_invoke_function (PyGIInvokeState *state,
-                  PyGIFunctionCache *cache,
-                  GIFunctionInfo *function_info)
+static gboolean
+_invoke_function (struct invocation_state *state,
+                  GICallableInfo *callable_info, PyObject *py_args)
 {
     GError *error;
     gint retval;
@@ -561,35 +609,44 @@ _invoke_function (PyGIInvokeState *state,
     error = NULL;
 
     pyg_begin_allow_threads;
-
-    /* FIXME: use this for now but we can streamline the call */
-    retval = g_function_info_invoke ( (GIFunctionInfo *) function_info,
-                                      state->in_args,
-                                      cache->n_in_args,
-                                      state->out_args,
-                                      cache->n_out_args,
-                                      &state->return_arg,
-                                      &error);
+    if (g_base_info_get_type (callable_info) == GI_INFO_TYPE_FUNCTION) {
+        retval = g_function_info_invoke ( (GIFunctionInfo *) callable_info,
+                                          state->in_args,
+                                          state->n_in_args,
+                                          state->out_args,
+                                          state->n_out_args,
+                                          &state->return_arg,
+                                          &error);
+    } else {
+        retval = g_vfunc_info_invoke ( (GIVFuncInfo *) callable_info,
+                                       state->implementor_gtype,
+                                       state->in_args,
+                                       state->n_in_args,
+                                       state->out_args,
+                                       state->n_out_args,
+                                       &state->return_arg,
+                                       &error);
+    }
     pyg_end_allow_threads;
 
     if (!retval) {
-        g_assert (error != NULL);
-        /* TODO: raise the right error, out of the error domain. */
-        PyErr_SetString (PyExc_RuntimeError, error->message);
-        g_error_free (error);
+        pyglib_error_check(&error);
 
         /* TODO: release input arguments. */
 
         return FALSE;
     }
 
-    if (state->error != NULL) {
-        /* TODO: raise the right error, out of the error domain, if applicable. */
-        PyErr_SetString (PyExc_Exception, state->error->message);
+    if (state->error_arg_pos >= 0) {
+        GError **error;
 
-        /* TODO: release input arguments. */
+        error = state->args[state->error_arg_pos]->v_pointer;
 
-        return FALSE;
+        if (pyglib_error_check(error)) {
+            /* TODO: release input arguments. */
+
+            return FALSE;
+        }
     }
 
     return TRUE;
@@ -768,13 +825,16 @@ _process_invocation_state (struct invocation_state *state,
                 if (type_tag == GI_TYPE_TAG_INTERFACE) {
                     GIBaseInfo *info;
                     GIInfoType info_type;
+                    GType type;
 
                     info = g_type_info_get_interface (state->arg_type_infos[i]);
                     g_assert (info != NULL);
                     info_type = g_base_info_get_type (info);
+                    type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info);
 
                     if ( (info_type == GI_INFO_TYPE_STRUCT) &&
-                             !g_struct_info_is_foreign((GIStructInfo *) info) ) {
+                             !g_struct_info_is_foreign((GIStructInfo *) info) &&
+                             !g_type_is_a (type, G_TYPE_BOXED)) {
                         if (g_arg_info_is_caller_allocates (state->arg_infos[i])) {
                             transfer = GI_TRANSFER_EVERYTHING;
                         } else if (transfer == GI_TRANSFER_EVERYTHING) {
@@ -812,6 +872,14 @@ _process_invocation_state (struct invocation_state *state,
 
         }
 
+        /* HACK: We rewrapped any C arrays above in a GArray so they are ok to
+         *       free as GArrays.  We will always leak C arrays if there is
+         *       an error before we reach this state as there is no easy way
+         *       to know which arrays were wrapped if there are more than one.
+         *       This will be removed with better array handling once merge
+         *       the invoke rewrite branch.
+         */
+        state->c_arrays_are_wrapped = TRUE;
         g_assert (state->n_return_values <= 1 || return_values_pos == state->n_return_values);
     }
 
@@ -861,13 +929,26 @@ _free_invocation_state (struct invocation_state *state)
                 backup_args_pos += 1;
             }
             if (state->args != NULL && state->args[i] != NULL) {
-                _pygi_argument_release (state->args[i], state->arg_type_infos[i],
-                                        transfer, direction);
-
                 type_tag = g_type_info_get_tag (state->arg_type_infos[i]);
+
+                if (type_tag == GI_TYPE_TAG_ARRAY &&
+                        (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) &&
+                        (g_type_info_get_array_type (state->arg_type_infos[i]) == GI_ARRAY_TYPE_C) &&
+                        !state->c_arrays_are_wrapped) {
+                    /* HACK: Noop - we are in an inconsitant state due to
+                     *       complex array handler so leak any C arrays
+                     *       as we don't know if we can free them safely.
+                     *       This will be removed when we merge the
+                     *       invoke rewrite branch.
+                     */
+                } else {
+                    _pygi_argument_release (state->args[i], state->arg_type_infos[i],
+                                            transfer, direction);
+                }
+
                 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. */
+                    /* We created an *out* #GArray and it has not been released above, so free it. */
                     state->args[i]->v_pointer = g_array_free (state->args[i]->v_pointer, FALSE);
                 }
             }
@@ -910,270 +991,34 @@ _free_invocation_state (struct invocation_state *state)
     }
 }
 
-static inline gboolean
-_invoke_state_init_from_function_cache(PyGIInvokeState *state,
-                                       PyGIFunctionCache *cache,
-                                       PyObject *py_args)
-{
-    state->py_in_args = py_args;
-    state->n_py_in_args = PySequence_Length(py_args);
-    state->args = g_slice_alloc0(cache->n_args * sizeof(GIArgument *));
-    if (state->args == NULL && cache->n_args != 0) {
-        PyErr_NoMemory();
-        return FALSE;
-    }
-
-    state->in_args = g_slice_alloc0(cache->n_in_args * sizeof(GIArgument));
-    if (state->in_args == NULL && cache->n_in_args != 0) {
-        PyErr_NoMemory();
-        return FALSE;
-    }
-
-    state->out_values = g_slice_alloc0(cache->n_out_args * sizeof(GIArgument));
-    if (state->out_values == NULL && cache->n_out_args != 0) {
-        PyErr_NoMemory();
-        return FALSE;
-    }
-
-    state->out_args = g_slice_alloc0(cache->n_out_args * sizeof(GIArgument));
-    if (state->out_args == NULL && cache->n_out_args != 0) {
-        PyErr_NoMemory();
-        return FALSE;
-    }
-
-    state->error = NULL;
-
-    return TRUE;
-}
-
-static inline void
-_invoke_state_clear(PyGIInvokeState *state, PyGIFunctionCache *cache)
-{
-    g_slice_free1(cache->n_args * sizeof(GIArgument *), state->args);
-    g_slice_free1(cache->n_in_args * sizeof(GIArgument), state->in_args);
-    g_slice_free1(cache->n_out_args * sizeof(GIArgument), state->out_args);
-    g_slice_free1(cache->n_out_args * sizeof(GIArgument), state->out_values);
-}
 
-static inline gboolean
-_invoke_marshal_in_args(PyGIInvokeState *state, PyGIFunctionCache *cache)
+PyObject *
+_wrap_g_callable_info_invoke (PyGIBaseInfo *self, PyObject *py_args,
+                              PyObject *kwargs)
 {
-    int i, in_count, out_count;
-    in_count = 0;
-    out_count = 0;
-
-    if (state->n_py_in_args > cache->n_py_args) {
-        PyErr_Format(PyExc_TypeError,
-                     "%s() takes exactly %zd argument(s) (%zd given)",
-                     cache->name,
-                     cache->n_py_args,
-                     state->n_py_in_args);
-        return FALSE;
-    }
-
-    for (i = 0; i < cache->n_args; i++) {
-        GIArgument *c_arg;
-        PyGIArgCache *arg_cache = cache->args_cache[i];
-        PyObject *py_arg = NULL;
-
-        switch (arg_cache->direction) {
-            case GI_DIRECTION_IN:
-                state->args[i] = &(state->in_args[in_count]);
-                in_count++;
-
-                if (arg_cache->aux_type > 0)
-                    continue;
-
-                if (arg_cache->py_arg_index >= state->n_py_in_args) {
-                    PyErr_Format(PyExc_TypeError,
-                                 "%s() takes exactly %zd argument(s) (%zd given)",
-                                  cache->name,
-                                  cache->n_py_args,
-                                  state->n_py_in_args);
-                    return FALSE;
-                }
-
-                py_arg =
-                    PyTuple_GET_ITEM(state->py_in_args,
-                                     arg_cache->py_arg_index);
-
-                break;
-            case GI_DIRECTION_INOUT:
-                /* this will be filled in if it is an aux value */
-                if (state->in_args[in_count].v_pointer != NULL)
-                    state->out_values[out_count] = state->in_args[in_count];
-
-                state->in_args[in_count].v_pointer = &state->out_values[out_count];
-                in_count++;
-
-                if (arg_cache->aux_type != PYGI_AUX_TYPE_IGNORE) {
-                    if (arg_cache->py_arg_index >= state->n_py_in_args) {
-                        PyErr_Format(PyExc_TypeError,
-                                     "%s() takes exactly %zd argument(s) (%zd given)",
-                                      cache->name,
-                                      cache->n_py_args,
-                                      state->n_py_in_args);
-                        return FALSE;
-                    }
-
-                    py_arg =
-                        PyTuple_GET_ITEM(state->py_in_args,
-                                         arg_cache->py_arg_index);
-                }
-            case GI_DIRECTION_OUT:
-                if (arg_cache->is_caller_allocates) {
-                    PyGIInterfaceCache *iface_cache =
-                        (PyGIInterfaceCache *)arg_cache;
-
-                    g_assert(arg_cache->type_tag == GI_TYPE_TAG_INTERFACE);
-
-                    state->out_args[out_count].v_pointer = NULL;
-                    state->args[i] = &state->out_args[out_count];
-                    if (iface_cache->g_type == G_TYPE_BOXED) {
-                        state->args[i]->v_pointer =
-                            _pygi_boxed_alloc(iface_cache->interface_info, NULL);
-                    } else if (iface_cache->is_foreign) {
-                        PyObject *foreign_struct =
-                            pygi_struct_foreign_convert_from_g_argument(
-                                iface_cache->interface_info,
-                                NULL);
-
-                        pygi_struct_foreign_convert_to_g_argument(
-                            foreign_struct,
-                            iface_cache->interface_info,
-                            GI_TRANSFER_EVERYTHING,
-                            state->args[i]);
-                    } else {
-                        gssize size =
-                            g_struct_info_get_size(
-                                (GIStructInfo *)iface_cache->interface_info);
-                        state->args[i]->v_pointer = g_malloc0(size);
-                    }
-
-                } else {
-                    state->out_args[out_count].v_pointer = &state->out_values[out_count];
-                    state->args[i] = &state->out_values[out_count];
-                }
-                out_count++;
-                break;
-        }
-
-        c_arg = state->args[i];
-        if (arg_cache->in_marshaller != NULL) {
-            if (!arg_cache->allow_none && py_arg == Py_None) {
-                PyErr_Format(PyExc_TypeError,
-                             "Argument %i does not allow None as a value",
-                             i);
-
-                return FALSE;
-            }
-            gboolean success = arg_cache->in_marshaller(state,
-                                                        cache,
-                                                        arg_cache,
-                                                        py_arg,
-                                                        c_arg);
-            if (!success)
-                return FALSE;
-        }
+    struct invocation_state state = { 0, };
 
+    if (!_initialize_invocation_state (&state, self->info, py_args, kwargs)) {
+        _free_invocation_state (&state);
+        return NULL;
     }
 
-    return TRUE;
-}
-
-static inline PyObject *
-_invoke_marshal_out_args(PyGIInvokeState *state, PyGIFunctionCache *cache)
-{
-    PyObject *py_out = NULL;
-    PyObject *py_return = NULL;
-    int total_out_args = cache->n_out_args;
-    gboolean has_return = FALSE;
-
-    if (cache->return_cache) {
-        if (cache->is_constructor) {
-            if (state->return_arg.v_pointer == NULL) {
-                PyErr_SetString (PyExc_TypeError, "constructor returned NULL");
-                return NULL;
-            }
-        }
-
-        py_return = cache->return_cache->out_marshaller(state,
-                                                        cache,
-                                                        cache->return_cache,
-                                                        &state->return_arg);
-        if (py_return == NULL)
-            return NULL;
-
-        if (cache->return_cache->type_tag != GI_TYPE_TAG_VOID) {
-            total_out_args++;
-            has_return = TRUE;
-        }
+    if (!_prepare_invocation_state (&state, self->info, py_args)) {
+        _free_invocation_state (&state);
+        return NULL;
     }
 
-    total_out_args -= cache->n_out_aux_args;
-
-    if (cache->n_out_args - cache->n_out_aux_args  == 0) {
-        py_out = py_return;
-    } else if (total_out_args == 1) {
-        /* if we get here there is one out arg an no return */
-        PyGIArgCache *arg_cache = (PyGIArgCache *)cache->out_args->data;
-        py_out = arg_cache->out_marshaller(state,
-                                           cache,
-                                           arg_cache,
-                                           state->args[arg_cache->c_arg_index]);
-    } else {
-        int out_cache_index = 0;
-        int py_arg_index = 0;
-        GSList *cache_item = cache->out_args;
-        /* return a tuple */
-        py_out = PyTuple_New(total_out_args);
-        if (has_return) {
-            PyTuple_SET_ITEM(py_out, py_arg_index, py_return);
-            py_arg_index++;
-        }
-
-        for(; py_arg_index < total_out_args; py_arg_index++) {
-            PyGIArgCache *arg_cache = (PyGIArgCache *)cache_item->data;
-            PyObject *py_obj = arg_cache->out_marshaller(state,
-                                                         cache,
-                                                         arg_cache,
-                                                         state->args[arg_cache->c_arg_index]);
-
-            if (py_obj == NULL)
-                return NULL;
-
-            PyTuple_SET_ITEM(py_out, py_arg_index, py_obj);
-            cache_item = cache_item->next;
-        }
+    if (!_invoke_function (&state, self->info, py_args)) {
+        _free_invocation_state (&state);
+        return NULL;
     }
-    return py_out;
-}
 
-PyObject *
-_wrap_g_function_info_invoke (PyGIBaseInfo *self, PyObject *py_args)
-{
-    PyGIInvokeState state = { 0, };
-    PyObject *ret;
-
-    if (self->cache == NULL) {
-        self->cache = _pygi_function_cache_new(self->info);
-        if (self->cache == NULL)
-            return NULL;
+    if (!_process_invocation_state (&state, self->info, py_args)) {
+        _free_invocation_state (&state);
+        return NULL;
     }
 
-    _invoke_state_init_from_function_cache(&state, self->cache, py_args);
-    if (!_invoke_marshal_in_args (&state, self->cache))
-        goto err;
-
-    if (!_invoke_function(&state, self->cache, self->info))
-        goto err;
-
-    ret = _invoke_marshal_out_args (&state, self->cache);
-    _invoke_state_clear (&state, self->cache);
-    return ret;
-
-err:
-    _invoke_state_clear (&state, self->cache);
-    return NULL;
+    _free_invocation_state (&state);
+    return state.return_value;
 }
 
diff --git a/gi/pygi-marshal.c b/gi/pygi-marshal.c
new file mode 100644
index 0000000..fa744f3
--- /dev/null
+++ b/gi/pygi-marshal.c
@@ -0,0 +1,3916 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2005-2009 Johan Dahlin <johan gnome org>
+ *
+ *   pygi-argument.c: GIArgument - PyObject conversion functions.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "pygi-private.h"
+
+#include <string.h>
+#include <time.h>
+
+#include <datetime.h>
+#include <pygobject.h>
+#include <pyglib-python-compat.h>
+
+#include "pygi-cache.h"
+
+static void
+_pygi_g_type_tag_py_bounds (GITypeTag   type_tag,
+                            PyObject  **lower,
+                            PyObject  **upper)
+{
+    switch (type_tag) {
+        case GI_TYPE_TAG_INT8:
+            *lower = PYGLIB_PyLong_FromLong (-128);
+            *upper = PYGLIB_PyLong_FromLong (127);
+            break;
+        case GI_TYPE_TAG_UINT8:
+            *upper = PYGLIB_PyLong_FromLong (255);
+            *lower = PYGLIB_PyLong_FromLong (0);
+            break;
+        case GI_TYPE_TAG_INT16:
+            *lower = PYGLIB_PyLong_FromLong (-32768);
+            *upper = PYGLIB_PyLong_FromLong (32767);
+            break;
+        case GI_TYPE_TAG_UINT16:
+            *upper = PYGLIB_PyLong_FromLong (65535);
+            *lower = PYGLIB_PyLong_FromLong (0);
+            break;
+        case GI_TYPE_TAG_INT32:
+            *lower = PYGLIB_PyLong_FromLong (G_MININT32);
+            *upper = PYGLIB_PyLong_FromLong (G_MAXINT32);
+            break;
+        case GI_TYPE_TAG_UINT32:
+            /* Note: On 32-bit archs, this number doesn't fit in a long. */
+            *upper = PyLong_FromLongLong (G_MAXUINT32);
+            *lower = PYGLIB_PyLong_FromLong (0);
+            break;
+        case GI_TYPE_TAG_INT64:
+            /* Note: On 32-bit archs, these numbers don't fit in a long. */
+            *lower = PyLong_FromLongLong (G_MININT64);
+            *upper = PyLong_FromLongLong (G_MAXINT64);
+            break;
+        case GI_TYPE_TAG_UINT64:
+            *upper = PyLong_FromUnsignedLongLong (G_MAXUINT64);
+            *lower = PYGLIB_PyLong_FromLong (0);
+            break;
+        case GI_TYPE_TAG_FLOAT:
+            *upper = PyFloat_FromDouble (G_MAXFLOAT);
+            *lower = PyFloat_FromDouble (-G_MAXFLOAT);
+            break;
+        case GI_TYPE_TAG_DOUBLE:
+            *upper = PyFloat_FromDouble (G_MAXDOUBLE);
+            *lower = PyFloat_FromDouble (-G_MAXDOUBLE);
+            break;
+        default:
+            PyErr_SetString (PyExc_TypeError, "Non-numeric type tag");
+            *lower = *upper = NULL;
+            return;
+    }
+}
+
+gint
+_pygi_g_registered_type_info_check_object (GIRegisteredTypeInfo *info,
+                                           gboolean              is_instance,
+                                           PyObject             *object)
+{
+    gint retval;
+
+    GType g_type;
+    PyObject *py_type;
+    gchar *type_name_expected = NULL;
+    GIInfoType interface_type;
+
+    interface_type = g_base_info_get_type (info);
+    if ( (interface_type == GI_INFO_TYPE_STRUCT) &&
+            (g_struct_info_is_foreign ( (GIStructInfo*) info))) {
+        /* TODO: Could we check is the correct foreign type? */
+        return 1;
+    }
+
+    g_type = g_registered_type_info_get_g_type (info);
+    if (g_type != G_TYPE_NONE) {
+        py_type = _pygi_type_get_from_g_type (g_type);
+    } else {
+        py_type = _pygi_type_import_by_gi_info ( (GIBaseInfo *) info);
+    }
+
+    if (py_type == NULL) {
+        return 0;
+    }
+
+    g_assert (PyType_Check (py_type));
+
+    if (is_instance) {
+        retval = PyObject_IsInstance (object, py_type);
+        if (!retval) {
+            type_name_expected = _pygi_g_base_info_get_fullname (
+                                     (GIBaseInfo *) info);
+        }
+    } else {
+        if (!PyObject_Type (py_type)) {
+            type_name_expected = "type";
+            retval = 0;
+        } else if (!PyType_IsSubtype ( (PyTypeObject *) object,
+                                       (PyTypeObject *) py_type)) {
+            type_name_expected = _pygi_g_base_info_get_fullname (
+                                     (GIBaseInfo *) info);
+            retval = 0;
+        } else {
+            retval = 1;
+        }
+    }
+
+    Py_DECREF (py_type);
+
+    if (!retval) {
+        PyTypeObject *object_type;
+
+        if (type_name_expected == NULL) {
+            return -1;
+        }
+
+        object_type = (PyTypeObject *) PyObject_Type (object);
+        if (object_type == NULL) {
+            return -1;
+        }
+
+        PyErr_Format (PyExc_TypeError, "Must be %s, not %s",
+                      type_name_expected, object_type->tp_name);
+
+        g_free (type_name_expected);
+    }
+
+    return retval;
+}
+
+gint
+_pygi_g_type_interface_check_object (GIBaseInfo *info,
+                                     PyObject   *object)
+{
+    gint retval = 1;
+    GIInfoType info_type;
+
+    info_type = g_base_info_get_type (info);
+    switch (info_type) {
+        case GI_INFO_TYPE_CALLBACK:
+            if (!PyCallable_Check (object)) {
+                PyErr_Format (PyExc_TypeError, "Must be callable, not %s",
+                              object->ob_type->tp_name);
+                retval = 0;
+            }
+            break;
+        case GI_INFO_TYPE_ENUM:
+            retval = 0;
+            if (PyNumber_Check (object)) {
+                PyObject *number = PYGLIB_PyNumber_Long (object);
+                if (number == NULL)
+                    PyErr_Clear();
+                else {
+                    glong value = PYGLIB_PyLong_AsLong (number);
+                    int i;
+                    for (i = 0; i < g_enum_info_get_n_values (info); i++) {
+                        GIValueInfo *value_info = g_enum_info_get_value (info, i);
+                        glong enum_value = g_value_info_get_value (value_info);
+                        if (value == enum_value) {
+                            retval = 1;
+                            break;
+                        }
+                    }
+                }
+            }
+            if (retval < 1)
+                retval = _pygi_g_registered_type_info_check_object (
+                             (GIRegisteredTypeInfo *) info, TRUE, object);
+            break;
+        case GI_INFO_TYPE_FLAGS:
+            if (PyNumber_Check (object)) {
+                /* Accept 0 as a valid flag value */
+                PyObject *number = PYGLIB_PyNumber_Long (object);
+                if (number == NULL)
+                    PyErr_Clear();
+                else {
+                    long value = PYGLIB_PyLong_AsLong (number);
+                    if (value == 0)
+                        break;
+                    else if (value == -1)
+                        PyErr_Clear();
+                }
+            }
+            retval = _pygi_g_registered_type_info_check_object (
+                         (GIRegisteredTypeInfo *) info, TRUE, object);
+            break;
+        case GI_INFO_TYPE_STRUCT:
+        {
+            GType type;
+
+            /* Handle special cases. */
+            type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info);
+            if (g_type_is_a (type, G_TYPE_CLOSURE)) {
+                if (!PyCallable_Check (object)) {
+                    PyErr_Format (PyExc_TypeError, "Must be callable, not %s",
+                                  object->ob_type->tp_name);
+                    retval = 0;
+                }
+                break;
+            } else if (g_type_is_a (type, G_TYPE_VALUE)) {
+                /* we can't check g_values because we don't have
+                 * enough context so just pass them through */
+                break;
+            }
+
+            /* Fallback. */
+        }
+        case GI_INFO_TYPE_BOXED:
+        case GI_INFO_TYPE_INTERFACE:
+        case GI_INFO_TYPE_OBJECT:
+        case GI_INFO_TYPE_UNION:
+            retval = _pygi_g_registered_type_info_check_object ( (GIRegisteredTypeInfo *) info, TRUE, object);
+            break;
+        default:
+            g_assert_not_reached();
+    }
+
+    return retval;
+}
+
+gint
+_pygi_g_type_info_check_object (GITypeInfo *type_info,
+                                PyObject   *object,
+                                gboolean   allow_none)
+{
+    GITypeTag type_tag;
+    gint retval = 1;
+
+    if (allow_none && object == Py_None) {
+        return retval;
+    }
+
+    type_tag = g_type_info_get_tag (type_info);
+
+    switch (type_tag) {
+        case GI_TYPE_TAG_VOID:
+            /* No check; VOID means undefined type */
+            break;
+        case GI_TYPE_TAG_BOOLEAN:
+            /* No check; every Python object has a truth value. */
+            break;
+        case GI_TYPE_TAG_UINT8:
+            /* UINT8 types can be characters */
+            if (PYGLIB_PyBytes_Check(object)) {
+                if (PYGLIB_PyBytes_Size(object) != 1) {
+                    PyErr_Format (PyExc_TypeError, "Must be a single character");
+                    retval = 0;
+                    break;
+                }
+
+                break;
+            }
+        case GI_TYPE_TAG_INT8:
+        case GI_TYPE_TAG_INT16:
+        case GI_TYPE_TAG_UINT16:
+        case GI_TYPE_TAG_INT32:
+        case GI_TYPE_TAG_UINT32:
+        case GI_TYPE_TAG_INT64:
+        case GI_TYPE_TAG_UINT64:
+        case GI_TYPE_TAG_FLOAT:
+        case GI_TYPE_TAG_DOUBLE:
+        {
+            PyObject *number, *lower, *upper;
+
+            if (!PyNumber_Check (object)) {
+                PyErr_Format (PyExc_TypeError, "Must be number, not %s",
+                              object->ob_type->tp_name);
+                retval = 0;
+                break;
+            }
+
+            if (type_tag == GI_TYPE_TAG_FLOAT || type_tag == GI_TYPE_TAG_DOUBLE) {
+                number = PyNumber_Float (object);
+            } else {
+                number = PYGLIB_PyNumber_Long (object);
+            }
+
+            _pygi_g_type_tag_py_bounds (type_tag, &lower, &upper);
+
+            if (lower == NULL || upper == NULL || number == NULL) {
+                retval = -1;
+                goto check_number_release;
+            }
+
+            /* Check bounds */
+            if (PyObject_RichCompareBool (lower, number, Py_GT)
+                    || PyObject_RichCompareBool (upper, number, Py_LT)) {
+                PyObject *lower_str;
+                PyObject *upper_str;
+
+                if (PyErr_Occurred()) {
+                    retval = -1;
+                    goto check_number_release;
+                }
+
+                lower_str = PyObject_Str (lower);
+                upper_str = PyObject_Str (upper);
+                if (lower_str == NULL || upper_str == NULL) {
+                    retval = -1;
+                    goto check_number_error_release;
+                }
+
+#if PY_VERSION_HEX < 0x03000000
+                PyErr_Format (PyExc_ValueError, "Must range from %s to %s",
+                              PyString_AS_STRING (lower_str),
+                              PyString_AS_STRING (upper_str));
+#else
+                {
+                    PyObject *lower_pybytes_obj = PyUnicode_AsUTF8String (lower_str);
+                    if (!lower_pybytes_obj)
+                        goto utf8_fail;
+
+                    PyObject *upper_pybytes_obj = PyUnicode_AsUTF8String (upper_str);                    
+                    if (!upper_pybytes_obj) {
+                        Py_DECREF(lower_pybytes_obj);
+                        goto utf8_fail;
+                    }
+
+                    PyErr_Format (PyExc_ValueError, "Must range from %s to %s",
+                                  PyBytes_AsString (lower_pybytes_obj),
+                                  PyBytes_AsString (upper_pybytes_obj));
+                    Py_DECREF (lower_pybytes_obj);
+                    Py_DECREF (upper_pybytes_obj);
+                }
+utf8_fail:
+#endif
+                retval = 0;
+
+check_number_error_release:
+                Py_XDECREF (lower_str);
+                Py_XDECREF (upper_str);
+            }
+
+check_number_release:
+            Py_XDECREF (number);
+            Py_XDECREF (lower);
+            Py_XDECREF (upper);
+            break;
+        }
+        case GI_TYPE_TAG_GTYPE:
+        {
+            if (pyg_type_from_object (object) == 0) {
+                PyErr_Format (PyExc_TypeError, "Must be gobject.GType, not %s",
+                              object->ob_type->tp_name);
+                retval = 0;
+            }
+            break;
+        }
+        case GI_TYPE_TAG_UNICHAR:
+        {
+            Py_ssize_t size;
+            if (PyUnicode_Check (object)) {
+                size = PyUnicode_GET_SIZE (object);
+#if PY_VERSION_HEX < 0x03000000
+            } else if (PyString_Check (object)) {
+                PyObject *pyuni = PyUnicode_FromEncodedObject (object, "UTF-8", "strict");
+                size = PyUnicode_GET_SIZE (pyuni);
+                Py_DECREF(pyuni);
+#endif
+            } else {
+                PyErr_Format (PyExc_TypeError, "Must be string, not %s",
+                              object->ob_type->tp_name);
+                retval = 0;
+                break;
+            }
+
+            if (size != 1) {
+                PyErr_Format (PyExc_TypeError, "Must be a one character string, not %ld characters",
+                              size);
+                retval = 0;
+                break;
+            }
+
+            break;
+        }
+        case GI_TYPE_TAG_UTF8:
+        case GI_TYPE_TAG_FILENAME:
+            if (!PYGLIB_PyBaseString_Check (object) ) {
+                PyErr_Format (PyExc_TypeError, "Must be string, not %s",
+                              object->ob_type->tp_name);
+                retval = 0;
+            }
+            break;
+        case GI_TYPE_TAG_ARRAY:
+        {
+            gssize fixed_size;
+            Py_ssize_t length;
+            GITypeInfo *item_type_info;
+            Py_ssize_t i;
+
+            if (!PySequence_Check (object)) {
+                PyErr_Format (PyExc_TypeError, "Must be sequence, not %s",
+                              object->ob_type->tp_name);
+                retval = 0;
+                break;
+            }
+
+            length = PySequence_Length (object);
+            if (length < 0) {
+                retval = -1;
+                break;
+            }
+
+            fixed_size = g_type_info_get_array_fixed_size (type_info);
+            if (fixed_size >= 0 && length != fixed_size) {
+                PyErr_Format (PyExc_ValueError, "Must contain %zd items, not %zd",
+                              fixed_size, length);
+                retval = 0;
+                break;
+            }
+
+            item_type_info = g_type_info_get_param_type (type_info, 0);
+            g_assert (item_type_info != NULL);
+
+            /* FIXME: This is insain.  We really should only check the first
+             *        object and perhaps have a debugging mode.  Large arrays
+             *        will cause apps to slow to a crawl.
+             */
+            for (i = 0; i < length; i++) {
+                PyObject *item;
+
+                item = PySequence_GetItem (object, i);
+                if (item == NULL) {
+                    retval = -1;
+                    break;
+                }
+
+                retval = _pygi_g_type_info_check_object (item_type_info, item, TRUE);
+
+                Py_DECREF (item);
+
+                if (retval < 0) {
+                    break;
+                }
+                if (!retval) {
+                    _PyGI_ERROR_PREFIX ("Item %zd: ", i);
+                    break;
+                }
+            }
+
+            g_base_info_unref ( (GIBaseInfo *) item_type_info);
+
+            break;
+        }
+        case GI_TYPE_TAG_INTERFACE:
+        {
+            GIBaseInfo *info;
+
+            info = g_type_info_get_interface (type_info);
+            g_assert (info != NULL);
+
+            retval = _pygi_g_type_interface_check_object(info, object);
+
+            g_base_info_unref (info);
+            break;
+        }
+        case GI_TYPE_TAG_GLIST:
+        case GI_TYPE_TAG_GSLIST:
+        {
+            Py_ssize_t length;
+            GITypeInfo *item_type_info;
+            Py_ssize_t i;
+
+            if (!PySequence_Check (object)) {
+                PyErr_Format (PyExc_TypeError, "Must be sequence, not %s",
+                              object->ob_type->tp_name);
+                retval = 0;
+                break;
+            }
+
+            length = PySequence_Length (object);
+            if (length < 0) {
+                retval = -1;
+                break;
+            }
+
+            item_type_info = g_type_info_get_param_type (type_info, 0);
+            g_assert (item_type_info != NULL);
+
+            for (i = 0; i < length; i++) {
+                PyObject *item;
+
+                item = PySequence_GetItem (object, i);
+                if (item == NULL) {
+                    retval = -1;
+                    break;
+                }
+
+                retval = _pygi_g_type_info_check_object (item_type_info, item, TRUE);
+
+                Py_DECREF (item);
+
+                if (retval < 0) {
+                    break;
+                }
+                if (!retval) {
+                    _PyGI_ERROR_PREFIX ("Item %zd: ", i);
+                    break;
+                }
+            }
+
+            g_base_info_unref ( (GIBaseInfo *) item_type_info);
+            break;
+        }
+        case GI_TYPE_TAG_GHASH:
+        {
+            Py_ssize_t length;
+            PyObject *keys;
+            PyObject *values;
+            GITypeInfo *key_type_info;
+            GITypeInfo *value_type_info;
+            Py_ssize_t i;
+
+            keys = PyMapping_Keys (object);
+            if (keys == NULL) {
+                PyErr_Format (PyExc_TypeError, "Must be mapping, not %s",
+                              object->ob_type->tp_name);
+                retval = 0;
+                break;
+            }
+
+            length = PyMapping_Length (object);
+            if (length < 0) {
+                Py_DECREF (keys);
+                retval = -1;
+                break;
+            }
+
+            values = PyMapping_Values (object);
+            if (values == NULL) {
+                retval = -1;
+                Py_DECREF (keys);
+                break;
+            }
+
+            key_type_info = g_type_info_get_param_type (type_info, 0);
+            g_assert (key_type_info != NULL);
+
+            value_type_info = g_type_info_get_param_type (type_info, 1);
+            g_assert (value_type_info != NULL);
+
+            for (i = 0; i < length; i++) {
+                PyObject *key;
+                PyObject *value;
+
+                key = PyList_GET_ITEM (keys, i);
+                value = PyList_GET_ITEM (values, i);
+
+                retval = _pygi_g_type_info_check_object (key_type_info, key, TRUE);
+                if (retval < 0) {
+                    break;
+                }
+                if (!retval) {
+                    _PyGI_ERROR_PREFIX ("Key %zd :", i);
+                    break;
+                }
+
+                retval = _pygi_g_type_info_check_object (value_type_info, value, TRUE);
+                if (retval < 0) {
+                    break;
+                }
+                if (!retval) {
+                    _PyGI_ERROR_PREFIX ("Value %zd :", i);
+                    break;
+                }
+            }
+
+            g_base_info_unref ( (GIBaseInfo *) key_type_info);
+            g_base_info_unref ( (GIBaseInfo *) value_type_info);
+            Py_DECREF (values);
+            Py_DECREF (keys);
+            break;
+        }
+        case GI_TYPE_TAG_ERROR:
+            PyErr_SetString (PyExc_NotImplementedError, "Error marshalling is not supported yet");
+            /* TODO */
+            break;
+    }
+
+    return retval;
+}
+
+GArray *
+_pygi_argument_to_array (GIArgument  *arg,
+                         GIArgument  *args[],
+                         GITypeInfo *type_info,
+                         gboolean is_method)
+{
+    GITypeInfo *item_type_info;
+    gboolean is_zero_terminated;
+    gsize item_size;
+    gssize length;
+    GArray *g_array;
+
+    if (arg->v_pointer == NULL) {
+        return NULL;
+    }
+
+    is_zero_terminated = g_type_info_is_zero_terminated (type_info);
+    item_type_info = g_type_info_get_param_type (type_info, 0);
+
+    item_size = _pygi_g_type_info_size (item_type_info);
+
+    g_base_info_unref ( (GIBaseInfo *) item_type_info);
+
+    if (is_zero_terminated) {
+        length = g_strv_length (arg->v_pointer);
+    } 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_assert (length >= 0);
+
+    g_array = g_array_new (is_zero_terminated, FALSE, item_size);
+
+    g_array->data = arg->v_pointer;
+    g_array->len = length;
+
+    return g_array;
+}
+
+GIArgument
+_pygi_argument_from_object (PyObject   *object,
+                            GITypeInfo *type_info,
+                            GITransfer  transfer)
+{
+    GIArgument arg;
+    GITypeTag type_tag;
+
+    memset(&arg, 0, sizeof(GIArgument));
+    type_tag = g_type_info_get_tag (type_info);
+
+    switch (type_tag) {
+        case GI_TYPE_TAG_VOID:
+            g_warn_if_fail (transfer == GI_TRANSFER_NOTHING);
+            arg.v_pointer = object;
+            break;
+        case GI_TYPE_TAG_BOOLEAN:
+        {
+            arg.v_boolean = PyObject_IsTrue (object);
+            break;
+        }
+        case GI_TYPE_TAG_UINT8:
+            if (PYGLIB_PyBytes_Check(object)) {
+                arg.v_long = (long)(PYGLIB_PyBytes_AsString(object)[0]);
+                break;
+            }
+
+        case GI_TYPE_TAG_INT8:
+        case GI_TYPE_TAG_INT16:
+        case GI_TYPE_TAG_UINT16:
+        case GI_TYPE_TAG_INT32:
+        {
+            PyObject *int_;
+
+            int_ = PYGLIB_PyNumber_Long (object);
+            if (int_ == NULL) {
+                break;
+            }
+
+            arg.v_long = PYGLIB_PyLong_AsLong (int_);
+
+            Py_DECREF (int_);
+
+            break;
+        }
+        case GI_TYPE_TAG_UINT32:
+        case GI_TYPE_TAG_UINT64:
+        {
+            PyObject *number;
+            guint64 value;
+
+            number = PYGLIB_PyNumber_Long (object);
+            if (number == NULL) {
+                break;
+            }
+
+#if PY_VERSION_HEX < 0x03000000
+            if (PyInt_Check (number)) {
+                value = PyInt_AS_LONG (number);
+            } else
+#endif
+            value = PyLong_AsUnsignedLongLong (number);
+
+            arg.v_uint64 = value;
+
+            Py_DECREF (number);
+
+            break;
+        }
+        case GI_TYPE_TAG_INT64:
+        {
+            PyObject *number;
+            gint64 value;
+
+            number = PYGLIB_PyNumber_Long (object);
+            if (number == NULL) {
+                break;
+            }
+
+#if PY_VERSION_HEX < 0x03000000
+            if (PyInt_Check (number)) {
+                value = PyInt_AS_LONG (number);
+            } else
+#endif
+            value = PyLong_AsLongLong (number);
+
+            arg.v_int64 = value;
+
+            Py_DECREF (number);
+
+            break;
+        }
+        case GI_TYPE_TAG_FLOAT:
+        {
+            PyObject *float_;
+
+            float_ = PyNumber_Float (object);
+            if (float_ == NULL) {
+                break;
+            }
+
+            arg.v_float = (float) PyFloat_AsDouble (float_);
+            Py_DECREF (float_);
+
+            break;
+        }
+        case GI_TYPE_TAG_DOUBLE:
+        {
+            PyObject *float_;
+
+            float_ = PyNumber_Float (object);
+            if (float_ == NULL) {
+                break;
+            }
+
+            arg.v_double = PyFloat_AsDouble (float_);
+            Py_DECREF (float_);
+
+            break;
+        }
+        case GI_TYPE_TAG_GTYPE:
+        {
+            arg.v_long = pyg_type_from_object (object);
+
+            break;
+        }
+        case GI_TYPE_TAG_UNICHAR:
+        {
+            gchar *string;
+
+            if (object == Py_None) {
+                arg.v_uint32 = 0;
+                break;
+            }
+
+#if PY_VERSION_HEX < 0x03000000
+            if (PyUnicode_Check(object)) {
+                 PyObject *pystr_obj = PyUnicode_AsUTF8String (object);
+
+                 if (!pystr_obj)
+                     break;
+
+                 string = g_strdup(PyString_AsString (pystr_obj));
+                 Py_DECREF(pystr_obj);
+            } else {
+                 string = g_strdup(PyString_AsString (object));
+            }
+#else
+            {
+                PyObject *pybytes_obj = PyUnicode_AsUTF8String (object);
+                if (!pybytes_obj)
+                    break;
+
+                string = g_strdup(PyBytes_AsString (pybytes_obj));
+                Py_DECREF (pybytes_obj);
+            }
+#endif
+
+            arg.v_uint32 = g_utf8_get_char (string);
+
+            break;
+        }
+        case GI_TYPE_TAG_UTF8:
+        {
+            gchar *string;
+
+            if (object == Py_None) {
+                arg.v_string = NULL;
+                break;
+            }
+#if PY_VERSION_HEX < 0x03000000
+            if (PyUnicode_Check(object)) {
+                 PyObject *pystr_obj = PyUnicode_AsUTF8String (object);
+                 
+                 if (!pystr_obj)
+                     break;
+
+                 string = g_strdup(PyString_AsString (pystr_obj));
+                 Py_DECREF(pystr_obj);
+            } else {
+                 string = g_strdup(PyString_AsString (object));
+            }
+#else
+            {
+                PyObject *pybytes_obj = PyUnicode_AsUTF8String (object);
+                if (!pybytes_obj)
+                    break;
+
+                string = g_strdup(PyBytes_AsString (pybytes_obj));
+                Py_DECREF (pybytes_obj);
+            }
+#endif
+            arg.v_string = string;
+
+            break;
+        }
+        case GI_TYPE_TAG_FILENAME:
+        {
+            GError *error = NULL;
+            gchar *string;
+
+#if PY_VERSION_HEX < 0x03000000
+            string = g_strdup(PyString_AsString (object));
+#else
+            {
+                PyObject *pybytes_obj = PyUnicode_AsUTF8String (object);
+                if (!pybytes_obj)
+                    break;
+
+                string = g_strdup(PyBytes_AsString (pybytes_obj));
+                Py_DECREF (pybytes_obj);
+            }
+#endif
+
+            if (string == NULL) {
+                break;
+            }
+
+            arg.v_string = g_filename_from_utf8 (string, -1, NULL, NULL, &error);
+            g_free(string);
+
+            if (arg.v_string == NULL) {
+                PyErr_SetString (PyExc_Exception, error->message);
+                /* TODO: Convert the error to an exception. */
+            }
+
+            break;
+        }
+        case GI_TYPE_TAG_ARRAY:
+        {
+            Py_ssize_t length;
+            gboolean is_zero_terminated;
+            GITypeInfo *item_type_info;
+            gsize item_size;
+            GArray *array;
+            GITransfer item_transfer;
+            Py_ssize_t i;
+
+            if (object == Py_None) {
+                arg.v_pointer = NULL;
+                break;
+            }
+
+            length = PySequence_Length (object);
+            if (length < 0) {
+                break;
+            }
+
+            is_zero_terminated = g_type_info_is_zero_terminated (type_info);
+            item_type_info = g_type_info_get_param_type (type_info, 0);
+
+            item_size = _pygi_g_type_info_size (item_type_info);
+
+            array = g_array_sized_new (is_zero_terminated, FALSE, item_size, length);
+            if (array == NULL) {
+                g_base_info_unref ( (GIBaseInfo *) item_type_info);
+                PyErr_NoMemory();
+                break;
+            }
+
+            if (g_type_info_get_tag (item_type_info) == GI_TYPE_TAG_UINT8 &&
+                PYGLIB_PyBytes_Check(object)) {
+
+                memcpy(array->data, PYGLIB_PyBytes_AsString(object), length);
+                array->len = length;
+                goto array_success;
+            }
+
+
+            item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
+
+            for (i = 0; i < length; i++) {
+                PyObject *py_item;
+                GIArgument item;
+
+                py_item = PySequence_GetItem (object, i);
+                if (py_item == NULL) {
+                    goto array_item_error;
+                }
+
+                item = _pygi_argument_from_object (py_item, item_type_info, item_transfer);
+
+                Py_DECREF (py_item);
+
+                if (PyErr_Occurred()) {
+                    goto array_item_error;
+                }
+
+                g_array_insert_val (array, i, item);
+                continue;
+
+array_item_error:
+                /* Free everything we have converted so far. */
+                _pygi_argument_release ( (GIArgument *) &array, type_info,
+                                         GI_TRANSFER_NOTHING, GI_DIRECTION_IN);
+                array = NULL;
+
+                _PyGI_ERROR_PREFIX ("Item %zd: ", i);
+                break;
+            }
+
+array_success:
+            arg.v_pointer = array;
+
+            g_base_info_unref ( (GIBaseInfo *) item_type_info);
+            break;
+        }
+        case GI_TYPE_TAG_INTERFACE:
+        {
+            GIBaseInfo *info;
+            GIInfoType info_type;
+
+            info = g_type_info_get_interface (type_info);
+            info_type = g_base_info_get_type (info);
+
+            switch (info_type) {
+                case GI_INFO_TYPE_CALLBACK:
+                    /* This should be handled in invoke() */
+                    g_assert_not_reached();
+                    break;
+                case GI_INFO_TYPE_BOXED:
+                case GI_INFO_TYPE_STRUCT:
+                case GI_INFO_TYPE_UNION:
+                {
+                    GType type;
+
+                    if (object == Py_None) {
+                        arg.v_pointer = NULL;
+                        break;
+                    }
+
+                    type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info);
+
+                    /* Handle special cases first. */
+                    if (g_type_is_a (type, G_TYPE_VALUE)) {
+                        GValue *value;
+                        GType object_type;
+                        gint retval;
+
+                        object_type = pyg_type_from_object_strict ( (PyObject *) object->ob_type, FALSE);
+                        if (object_type == G_TYPE_INVALID) {
+                            PyErr_SetString (PyExc_RuntimeError, "unable to retrieve object's GType");
+                            break;
+                        }
+
+                        g_warn_if_fail (transfer == GI_TRANSFER_NOTHING);
+
+                        value = g_slice_new0 (GValue);
+                        g_value_init (value, object_type);
+
+                        retval = pyg_value_from_pyobject (value, object);
+                        if (retval < 0) {
+                            g_slice_free (GValue, value);
+                            PyErr_SetString (PyExc_RuntimeError, "PyObject conversion to GValue failed");
+                            break;
+                        }
+
+                        arg.v_pointer = value;
+                    } else if (g_type_is_a (type, G_TYPE_CLOSURE)) {
+                        GClosure *closure;
+
+                        g_warn_if_fail (transfer == GI_TRANSFER_NOTHING);
+
+                        closure = pyg_closure_new (object, NULL, NULL);
+                        if (closure == NULL) {
+                            PyErr_SetString (PyExc_RuntimeError, "PyObject conversion to GClosure failed");
+                            break;
+                        }
+
+                        arg.v_pointer = closure;
+                    } else if (g_type_is_a (type, G_TYPE_BOXED)) {
+                        arg.v_pointer = pyg_boxed_get (object, void);
+                        if (transfer == GI_TRANSFER_EVERYTHING) {
+                            arg.v_pointer = g_boxed_copy (type, arg.v_pointer);
+                        }
+                    } else if ( (type == G_TYPE_NONE) && (g_struct_info_is_foreign (info))) {
+                        PyObject *result;
+                        result = pygi_struct_foreign_convert_to_g_argument (
+                                     object, type_info, transfer, &arg);
+                    } else if (g_type_is_a (type, G_TYPE_POINTER) || type == G_TYPE_NONE) {
+                        g_warn_if_fail (!g_type_info_is_pointer (type_info) || transfer == GI_TRANSFER_NOTHING);
+                        arg.v_pointer = pyg_pointer_get (object, void);
+                    } else {
+                        PyErr_Format (PyExc_NotImplementedError, "structure type '%s' is not supported yet", g_type_name (type));
+                    }
+
+                    break;
+                }
+                case GI_INFO_TYPE_ENUM:
+                case GI_INFO_TYPE_FLAGS:
+                {
+                    PyObject *int_;
+
+                    int_ = PYGLIB_PyNumber_Long (object);
+                    if (int_ == NULL) {
+                        break;
+                    }
+
+                    arg.v_long = PYGLIB_PyLong_AsLong (int_);
+
+                    Py_DECREF (int_);
+
+                    break;
+                }
+                case GI_INFO_TYPE_INTERFACE:
+                case GI_INFO_TYPE_OBJECT:
+                    if (object == Py_None) {
+                        arg.v_pointer = NULL;
+                        break;
+                    }
+
+                    arg.v_pointer = pygobject_get (object);
+                    if (transfer == GI_TRANSFER_EVERYTHING) {
+                        g_object_ref (arg.v_pointer);
+                    }
+
+                    break;
+                default:
+                    g_assert_not_reached();
+            }
+            g_base_info_unref (info);
+            break;
+        }
+        case GI_TYPE_TAG_GLIST:
+        case GI_TYPE_TAG_GSLIST:
+        {
+            Py_ssize_t length;
+            GITypeInfo *item_type_info;
+            GSList *list = NULL;
+            GITransfer item_transfer;
+            Py_ssize_t i;
+
+            if (object == Py_None) {
+                arg.v_pointer = NULL;
+                break;
+            }
+
+            length = PySequence_Length (object);
+            if (length < 0) {
+                break;
+            }
+
+            item_type_info = g_type_info_get_param_type (type_info, 0);
+            g_assert (item_type_info != NULL);
+
+            item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
+
+            for (i = length - 1; i >= 0; i--) {
+                PyObject *py_item;
+                GIArgument item;
+
+                py_item = PySequence_GetItem (object, i);
+                if (py_item == NULL) {
+                    goto list_item_error;
+                }
+
+                item = _pygi_argument_from_object (py_item, item_type_info, item_transfer);
+
+                Py_DECREF (py_item);
+
+                if (PyErr_Occurred()) {
+                    goto list_item_error;
+                }
+
+                if (type_tag == GI_TYPE_TAG_GLIST) {
+                    list = (GSList *) g_list_prepend ( (GList *) list, item.v_pointer);
+                } else {
+                    list = g_slist_prepend (list, item.v_pointer);
+                }
+
+                continue;
+
+list_item_error:
+                /* Free everything we have converted so far. */
+                _pygi_argument_release ( (GIArgument *) &list, type_info,
+                                         GI_TRANSFER_NOTHING, GI_DIRECTION_IN);
+                list = NULL;
+
+                _PyGI_ERROR_PREFIX ("Item %zd: ", i);
+                break;
+            }
+
+            arg.v_pointer = list;
+
+            g_base_info_unref ( (GIBaseInfo *) item_type_info);
+
+            break;
+        }
+        case GI_TYPE_TAG_GHASH:
+        {
+            Py_ssize_t length;
+            PyObject *keys;
+            PyObject *values;
+            GITypeInfo *key_type_info;
+            GITypeInfo *value_type_info;
+            GITypeTag key_type_tag;
+            GHashFunc hash_func;
+            GEqualFunc equal_func;
+            GHashTable *hash_table;
+            GITransfer item_transfer;
+            Py_ssize_t i;
+
+
+            if (object == Py_None) {
+                arg.v_pointer = NULL;
+                break;
+            }
+
+            length = PyMapping_Length (object);
+            if (length < 0) {
+                break;
+            }
+
+            keys = PyMapping_Keys (object);
+            if (keys == NULL) {
+                break;
+            }
+
+            values = PyMapping_Values (object);
+            if (values == NULL) {
+                Py_DECREF (keys);
+                break;
+            }
+
+            key_type_info = g_type_info_get_param_type (type_info, 0);
+            g_assert (key_type_info != NULL);
+
+            value_type_info = g_type_info_get_param_type (type_info, 1);
+            g_assert (value_type_info != NULL);
+
+            key_type_tag = g_type_info_get_tag (key_type_info);
+
+            switch (key_type_tag) {
+                case GI_TYPE_TAG_UTF8:
+                case GI_TYPE_TAG_FILENAME:
+                    hash_func = g_str_hash;
+                    equal_func = g_str_equal;
+                    break;
+                default:
+                    hash_func = NULL;
+                    equal_func = NULL;
+            }
+
+            hash_table = g_hash_table_new (hash_func, equal_func);
+            if (hash_table == NULL) {
+                PyErr_NoMemory();
+                goto hash_table_release;
+            }
+
+            item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
+
+            for (i = 0; i < length; i++) {
+                PyObject *py_key;
+                PyObject *py_value;
+                GIArgument key;
+                GIArgument value;
+
+                py_key = PyList_GET_ITEM (keys, i);
+                py_value = PyList_GET_ITEM (values, i);
+
+                key = _pygi_argument_from_object (py_key, key_type_info, item_transfer);
+                if (PyErr_Occurred()) {
+                    goto hash_table_item_error;
+                }
+
+                value = _pygi_argument_from_object (py_value, value_type_info, item_transfer);
+                if (PyErr_Occurred()) {
+                    _pygi_argument_release (&key, type_info, GI_TRANSFER_NOTHING, GI_DIRECTION_IN);
+                    goto hash_table_item_error;
+                }
+
+                g_hash_table_insert (hash_table, key.v_pointer, value.v_pointer);
+                continue;
+
+hash_table_item_error:
+                /* Free everything we have converted so far. */
+                _pygi_argument_release ( (GIArgument *) &hash_table, type_info,
+                                         GI_TRANSFER_NOTHING, GI_DIRECTION_IN);
+                hash_table = NULL;
+
+                _PyGI_ERROR_PREFIX ("Item %zd: ", i);
+                break;
+            }
+
+            arg.v_pointer = hash_table;
+
+hash_table_release:
+            g_base_info_unref ( (GIBaseInfo *) key_type_info);
+            g_base_info_unref ( (GIBaseInfo *) value_type_info);
+            Py_DECREF (keys);
+            Py_DECREF (values);
+            break;
+        }
+        case GI_TYPE_TAG_ERROR:
+            PyErr_SetString (PyExc_NotImplementedError, "error marshalling is not supported yet");
+            /* TODO */
+            break;
+    }
+
+    return arg;
+}
+
+PyObject *
+_pygi_argument_to_object (GIArgument  *arg,
+                          GITypeInfo *type_info,
+                          GITransfer transfer)
+{
+    GITypeTag type_tag;
+    PyObject *object = NULL;
+
+    type_tag = g_type_info_get_tag (type_info);
+    switch (type_tag) {
+        case GI_TYPE_TAG_VOID:
+            if (g_type_info_is_pointer (type_info)) {
+                /* Raw Python objects are passed to void* args */
+                g_warn_if_fail (transfer == GI_TRANSFER_NOTHING);
+                object = arg->v_pointer;
+            } else
+                object = Py_None;
+            Py_XINCREF (object);
+            break;
+        case GI_TYPE_TAG_BOOLEAN:
+        {
+            object = PyBool_FromLong (arg->v_boolean);
+            break;
+        }
+        case GI_TYPE_TAG_INT8:
+        {
+            object = PYGLIB_PyLong_FromLong (arg->v_int8);
+            break;
+        }
+        case GI_TYPE_TAG_UINT8:
+        {
+            object = PYGLIB_PyLong_FromLong (arg->v_uint8);
+            break;
+        }
+        case GI_TYPE_TAG_INT16:
+        {
+            object = PYGLIB_PyLong_FromLong (arg->v_int16);
+            break;
+        }
+        case GI_TYPE_TAG_UINT16:
+        {
+            object = PYGLIB_PyLong_FromLong (arg->v_uint16);
+            break;
+        }
+        case GI_TYPE_TAG_INT32:
+        {
+            object = PYGLIB_PyLong_FromLong (arg->v_int32);
+            break;
+        }
+        case GI_TYPE_TAG_UINT32:
+        {
+            object = PyLong_FromLongLong (arg->v_uint32);
+            break;
+        }
+        case GI_TYPE_TAG_INT64:
+        {
+            object = PyLong_FromLongLong (arg->v_int64);
+            break;
+        }
+        case GI_TYPE_TAG_UINT64:
+        {
+            object = PyLong_FromUnsignedLongLong (arg->v_uint64);
+            break;
+        }
+        case GI_TYPE_TAG_FLOAT:
+        {
+            object = PyFloat_FromDouble (arg->v_float);
+            break;
+        }
+        case GI_TYPE_TAG_DOUBLE:
+        {
+            object = PyFloat_FromDouble (arg->v_double);
+            break;
+        }
+        case GI_TYPE_TAG_GTYPE:
+        {
+            object = pyg_type_wrapper_new ( (GType) arg->v_long);
+            break;
+        }
+        case GI_TYPE_TAG_UNICHAR:
+        {
+            /* Preserve the bidirectional mapping between 0 and "" */
+            if (arg->v_uint32 == 0) {
+                object = PYGLIB_PyUnicode_FromString ("");
+            } else if (g_unichar_validate (arg->v_uint32)) {
+                gchar utf8[6];
+                gint bytes;
+
+                bytes = g_unichar_to_utf8 (arg->v_uint32, utf8);
+                object = PYGLIB_PyUnicode_FromStringAndSize ((char*)utf8, bytes);
+            } else {
+                /* TODO: Convert the error to an exception. */
+                PyErr_Format (PyExc_TypeError,
+                              "Invalid unicode codepoint %" G_GUINT32_FORMAT,
+                              arg->v_uint32);
+                object = Py_None;
+                Py_INCREF (object);
+            }
+            break;
+        }
+        case GI_TYPE_TAG_UTF8:
+            if (arg->v_string == NULL) {
+                object = Py_None;
+                Py_INCREF (object);
+                break;
+            }
+
+            object = PYGLIB_PyUnicode_FromString (arg->v_string);
+            break;
+        case GI_TYPE_TAG_FILENAME:
+        {
+            GError *error = NULL;
+            gchar *string;
+
+            if (arg->v_string == NULL) {
+                object = Py_None;
+                Py_INCREF (object);
+                break;
+            }
+
+            string = g_filename_to_utf8 (arg->v_string, -1, NULL, NULL, &error);
+            if (string == NULL) {
+                PyErr_SetString (PyExc_Exception, error->message);
+                /* TODO: Convert the error to an exception. */
+                break;
+            }
+
+            object = PYGLIB_PyUnicode_FromString (string);
+
+            g_free (string);
+
+            break;
+        }
+        case GI_TYPE_TAG_ARRAY:
+        {
+            GArray *array;
+            GITypeInfo *item_type_info;
+            GITypeTag item_type_tag;
+            GITransfer item_transfer;
+            gsize i, item_size;
+
+            array = arg->v_pointer;
+
+            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_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
+
+            if (item_type_tag == GI_TYPE_TAG_UINT8) {
+                /* Return as a byte array */
+                if (arg->v_pointer == NULL) {
+                    object = PYGLIB_PyBytes_FromString ("");
+                    break;
+                }
+
+                object = PYGLIB_PyBytes_FromStringAndSize(array->data, array->len);
+                break;
+
+            } else {
+                if (arg->v_pointer == NULL) {
+                    object = PyList_New (0);
+                    break;
+                }
+
+                object = PyList_New (array->len);
+                if (object == NULL) {
+                    break;
+                }
+
+            }
+            item_size = g_array_get_element_size (array);
+
+            for (i = 0; i < array->len; i++) {
+                GIArgument item;
+                PyObject *py_item;
+                gboolean is_struct = FALSE;
+
+                if (item_type_tag == GI_TYPE_TAG_INTERFACE) {
+                    GIBaseInfo *iface_info = g_type_info_get_interface (item_type_info);
+                    switch (g_base_info_get_type (iface_info)) {
+                        case GI_INFO_TYPE_STRUCT:
+                        case GI_INFO_TYPE_BOXED:
+                            is_struct = TRUE;
+                        default:
+                            break;
+                    }
+                    g_base_info_unref ( (GIBaseInfo *) iface_info);
+                }
+
+                if (is_struct) {
+                    item.v_pointer = &_g_array_index (array, GIArgument, i);
+                } else {
+                    memcpy (&item, &_g_array_index (array, GIArgument, i), item_size);
+                }
+
+                py_item = _pygi_argument_to_object (&item, item_type_info, item_transfer);
+                if (py_item == NULL) {
+                    Py_CLEAR (object);
+                    _PyGI_ERROR_PREFIX ("Item %zu: ", i);
+                    break;
+                }
+
+                PyList_SET_ITEM (object, i, py_item);
+            }
+
+            g_base_info_unref ( (GIBaseInfo *) item_type_info);
+            break;
+        }
+        case GI_TYPE_TAG_INTERFACE:
+        {
+            GIBaseInfo *info;
+            GIInfoType info_type;
+
+            info = g_type_info_get_interface (type_info);
+            info_type = g_base_info_get_type (info);
+
+            switch (info_type) {
+                case GI_INFO_TYPE_CALLBACK:
+                {
+                    /* There is no way we can support a callback return
+                     * as we are never sure if the callback was set from C
+                     * or Python.  API that return callbacks are broken
+                     * so we print a warning and send back a None
+                     */
+
+                    g_warning ("You are trying to use an API which returns a callback."
+                               "Callback returns can not be supported. Returning None instead.");
+                    object = Py_None;
+                    Py_INCREF (object);
+                    break;
+                }
+                case GI_INFO_TYPE_BOXED:
+                case GI_INFO_TYPE_STRUCT:
+                case GI_INFO_TYPE_UNION:
+                {
+                    GType type;
+
+                    if (arg->v_pointer == NULL) {
+                        object = Py_None;
+                        Py_INCREF (object);
+                        break;
+                    }
+
+                    type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info);
+                    if (g_type_is_a (type, G_TYPE_VALUE)) {
+                        object = pyg_value_as_pyobject (arg->v_pointer, FALSE);
+                    } else if (g_type_is_a (type, G_TYPE_BOXED)) {
+                        PyObject *py_type;
+
+                        py_type = _pygi_type_get_from_g_type (type);
+                        if (py_type == NULL)
+                            break;
+
+                        object = _pygi_boxed_new ( (PyTypeObject *) py_type, arg->v_pointer, transfer == GI_TRANSFER_EVERYTHING);
+
+                        Py_DECREF (py_type);
+                    } else if (g_type_is_a (type, G_TYPE_POINTER)) {
+                        PyObject *py_type;
+
+                        py_type = _pygi_type_get_from_g_type (type);
+
+                        if (py_type == NULL || !PyType_IsSubtype ( (PyTypeObject *) type, &PyGIStruct_Type)) {
+                            g_warn_if_fail (transfer == GI_TRANSFER_NOTHING);
+                            object = pyg_pointer_new (type, arg->v_pointer);
+                        } else {
+                            object = _pygi_struct_new ( (PyTypeObject *) py_type, arg->v_pointer, transfer == GI_TRANSFER_EVERYTHING);
+                        }
+
+                        Py_XDECREF (py_type);
+                    } else if ( (type == G_TYPE_NONE) && (g_struct_info_is_foreign (info))) {
+                        object = pygi_struct_foreign_convert_from_g_argument (type_info, arg->v_pointer);
+                    } else if (type == G_TYPE_NONE) {
+                        PyObject *py_type;
+
+                        py_type = _pygi_type_import_by_gi_info (info);
+                        if (py_type == NULL) {
+                            break;
+                        }
+
+                        /* Only structs created in invoke can be safely marked
+                         * GI_TRANSFER_EVERYTHING. Trust that invoke has
+                         * filtered correctly
+                         */
+                        object = _pygi_struct_new ( (PyTypeObject *) py_type, arg->v_pointer,
+                                                    transfer == GI_TRANSFER_EVERYTHING);
+
+                        Py_DECREF (py_type);
+                    } else {
+                        PyErr_Format (PyExc_NotImplementedError, "structure type '%s' is not supported yet", g_type_name (type));
+                    }
+
+                    break;
+                }
+                case GI_INFO_TYPE_ENUM:
+                case GI_INFO_TYPE_FLAGS:
+                {
+                    GType type;
+
+                    type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info);
+
+                    if (type == G_TYPE_NONE) {
+                        /* An enum with a GType of None is an enum without GType */
+                        PyObject *py_type = _pygi_type_import_by_gi_info (info);
+                        PyObject *py_args = NULL;
+
+                        if (!py_type)
+                            return NULL;
+
+                        py_args = PyTuple_New (1);
+                        if (PyTuple_SetItem (py_args, 0, PyLong_FromLong (arg->v_long)) != 0) {
+                            Py_DECREF (py_args);
+                            Py_DECREF (py_type);
+                            return NULL;
+                        }
+
+                        object = PyObject_CallFunction (py_type, "l", arg->v_long);
+
+                        Py_DECREF (py_args);
+                        Py_DECREF (py_type);
+
+                    } else if (info_type == GI_INFO_TYPE_ENUM) {
+                        object = pyg_enum_from_gtype (type, arg->v_long);
+                    } else {
+                        object = pyg_flags_from_gtype (type, arg->v_long);
+                    }
+
+                    break;
+                }
+                case GI_INFO_TYPE_INTERFACE:
+                case GI_INFO_TYPE_OBJECT:
+                    if (arg->v_pointer == NULL) {
+                        object = Py_None;
+                        Py_INCREF (object);
+                        break;
+                    }
+                    object = pygobject_new (arg->v_pointer);
+                    break;
+                default:
+                    g_assert_not_reached();
+            }
+
+            g_base_info_unref (info);
+            break;
+        }
+        case GI_TYPE_TAG_GLIST:
+        case GI_TYPE_TAG_GSLIST:
+        {
+            GSList *list;
+            gsize length;
+            GITypeInfo *item_type_info;
+            GITransfer item_transfer;
+            gsize i;
+
+            list = arg->v_pointer;
+            length = g_slist_length (list);
+
+            object = PyList_New (length);
+            if (object == NULL) {
+                break;
+            }
+
+            item_type_info = g_type_info_get_param_type (type_info, 0);
+            g_assert (item_type_info != NULL);
+
+            item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
+
+            for (i = 0; list != NULL; list = g_slist_next (list), i++) {
+                GIArgument item;
+                PyObject *py_item;
+
+                item.v_pointer = list->data;
+
+                py_item = _pygi_argument_to_object (&item, item_type_info, item_transfer);
+                if (py_item == NULL) {
+                    Py_CLEAR (object);
+                    _PyGI_ERROR_PREFIX ("Item %zu: ", i);
+                    break;
+                }
+
+                PyList_SET_ITEM (object, i, py_item);
+            }
+
+            g_base_info_unref ( (GIBaseInfo *) item_type_info);
+            break;
+        }
+        case GI_TYPE_TAG_GHASH:
+        {
+            GITypeInfo *key_type_info;
+            GITypeInfo *value_type_info;
+            GITransfer item_transfer;
+            GHashTableIter hash_table_iter;
+            GIArgument key;
+            GIArgument value;
+
+            if (arg->v_pointer == NULL) {
+                object = Py_None;
+                Py_INCREF (object);
+                break;
+            }
+
+            object = PyDict_New();
+            if (object == NULL) {
+                break;
+            }
+
+            key_type_info = g_type_info_get_param_type (type_info, 0);
+            g_assert (key_type_info != NULL);
+            g_assert (g_type_info_get_tag (key_type_info) != GI_TYPE_TAG_VOID);
+
+            value_type_info = g_type_info_get_param_type (type_info, 1);
+            g_assert (value_type_info != NULL);
+            g_assert (g_type_info_get_tag (value_type_info) != GI_TYPE_TAG_VOID);
+
+            item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
+
+            g_hash_table_iter_init (&hash_table_iter, (GHashTable *) arg->v_pointer);
+            while (g_hash_table_iter_next (&hash_table_iter, &key.v_pointer, &value.v_pointer)) {
+                PyObject *py_key;
+                PyObject *py_value;
+                int retval;
+
+                py_key = _pygi_argument_to_object (&key, key_type_info, item_transfer);
+                if (py_key == NULL) {
+                    break;
+                }
+
+                py_value = _pygi_argument_to_object (&value, value_type_info, item_transfer);
+                if (py_value == NULL) {
+                    Py_DECREF (py_key);
+                    break;
+                }
+
+                retval = PyDict_SetItem (object, py_key, py_value);
+
+                Py_DECREF (py_key);
+                Py_DECREF (py_value);
+
+                if (retval < 0) {
+                    Py_CLEAR (object);
+                    break;
+                }
+            }
+
+            g_base_info_unref ( (GIBaseInfo *) key_type_info);
+            g_base_info_unref ( (GIBaseInfo *) value_type_info);
+            break;
+        }
+        case GI_TYPE_TAG_ERROR:
+            /* Errors should be handled in the invoke wrapper. */
+            g_assert_not_reached();
+    }
+
+    return object;
+}
+
+void
+_pygi_argument_release (GIArgument   *arg,
+                        GITypeInfo  *type_info,
+                        GITransfer   transfer,
+                        GIDirection  direction)
+{
+    GITypeTag type_tag;
+    gboolean is_out = (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT);
+
+    type_tag = g_type_info_get_tag (type_info);
+
+    switch (type_tag) {
+        case GI_TYPE_TAG_VOID:
+            /* Don't do anything, it's transparent to the C side */
+            break;
+        case GI_TYPE_TAG_BOOLEAN:
+        case GI_TYPE_TAG_INT8:
+        case GI_TYPE_TAG_UINT8:
+        case GI_TYPE_TAG_INT16:
+        case GI_TYPE_TAG_UINT16:
+        case GI_TYPE_TAG_INT32:
+        case GI_TYPE_TAG_UINT32:
+        case GI_TYPE_TAG_INT64:
+        case GI_TYPE_TAG_UINT64:
+        case GI_TYPE_TAG_FLOAT:
+        case GI_TYPE_TAG_DOUBLE:
+        case GI_TYPE_TAG_GTYPE:
+        case GI_TYPE_TAG_UNICHAR:
+            break;
+        case GI_TYPE_TAG_FILENAME:
+        case GI_TYPE_TAG_UTF8:
+            /* With allow-none support the string could be NULL */
+            if ((arg->v_string != NULL &&
+                    (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING))
+                    || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) {
+                g_free (arg->v_string);
+            }
+            break;
+        case GI_TYPE_TAG_ARRAY:
+        {
+            GArray *array;
+            gsize i;
+
+            if (arg->v_pointer == NULL) {
+                return;
+            }
+
+            array = arg->v_pointer;
+
+            if ( (direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING)
+                    || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) {
+                GITypeInfo *item_type_info;
+                GITransfer item_transfer;
+
+                item_type_info = g_type_info_get_param_type (type_info, 0);
+
+                item_transfer = direction == GI_DIRECTION_IN ? GI_TRANSFER_NOTHING : GI_TRANSFER_EVERYTHING;
+
+                /* Free the items */
+                for (i = 0; i < array->len; i++) {
+                    GIArgument *item;
+                    item = &_g_array_index (array, GIArgument, i);
+                    _pygi_argument_release (item, item_type_info, item_transfer, direction);
+                }
+
+                g_base_info_unref ( (GIBaseInfo *) item_type_info);
+            }
+
+            if ( (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING)
+                    || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) {
+                g_array_free (array, TRUE);
+            }
+
+            break;
+        }
+        case GI_TYPE_TAG_INTERFACE:
+        {
+            GIBaseInfo *info;
+            GIInfoType info_type;
+
+            info = g_type_info_get_interface (type_info);
+            info_type = g_base_info_get_type (info);
+
+            switch (info_type) {
+                case GI_INFO_TYPE_CALLBACK:
+                    /* TODO */
+                    break;
+                case GI_INFO_TYPE_BOXED:
+                case GI_INFO_TYPE_STRUCT:
+                case GI_INFO_TYPE_UNION:
+                {
+                    GType type;
+
+                    if (arg->v_pointer == NULL) {
+                        return;
+                    }
+
+                    type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info);
+
+                    if (g_type_is_a (type, G_TYPE_VALUE)) {
+                        GValue *value;
+
+                        value = arg->v_pointer;
+
+                        if ( (direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING)
+                                || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) {
+                            g_value_unset (value);
+                        }
+
+                        if ( (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING)
+                                || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) {
+                            g_slice_free (GValue, value);
+                        }
+                    } else if (g_type_is_a (type, G_TYPE_CLOSURE)) {
+                        if (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) {
+                            g_closure_unref (arg->v_pointer);
+                        }
+                    } else if (g_struct_info_is_foreign ( (GIStructInfo*) info)) {
+                        if (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING) {
+                            pygi_struct_foreign_release (info, arg->v_pointer);
+                        }
+                    } else if (g_type_is_a (type, G_TYPE_BOXED)) {
+                    } else if (g_type_is_a (type, G_TYPE_POINTER) || type == G_TYPE_NONE) {
+                        g_warn_if_fail (!g_type_info_is_pointer (type_info) || transfer == GI_TRANSFER_NOTHING);
+                    }
+
+                    break;
+                }
+                case GI_INFO_TYPE_ENUM:
+                case GI_INFO_TYPE_FLAGS:
+                    break;
+                case GI_INFO_TYPE_INTERFACE:
+                case GI_INFO_TYPE_OBJECT:
+                    if (arg->v_pointer == NULL) {
+                        return;
+                    }
+                    if (is_out && transfer == GI_TRANSFER_EVERYTHING) {
+                        g_object_unref (arg->v_pointer);
+                    }
+                    break;
+                default:
+                    g_assert_not_reached();
+            }
+
+            g_base_info_unref (info);
+            break;
+        }
+        case GI_TYPE_TAG_GLIST:
+        case GI_TYPE_TAG_GSLIST:
+        {
+            GSList *list;
+
+            if (arg->v_pointer == NULL) {
+                return;
+            }
+
+            list = arg->v_pointer;
+
+            if ( (direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING)
+                    || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) {
+                GITypeInfo *item_type_info;
+                GITransfer item_transfer;
+                GSList *item;
+
+                item_type_info = g_type_info_get_param_type (type_info, 0);
+                g_assert (item_type_info != NULL);
+
+                item_transfer = direction == GI_DIRECTION_IN ? GI_TRANSFER_NOTHING : GI_TRANSFER_EVERYTHING;
+
+                /* Free the items */
+                for (item = list; item != NULL; item = g_slist_next (item)) {
+                    _pygi_argument_release ( (GIArgument *) &item->data, item_type_info,
+                                             item_transfer, direction);
+                }
+
+                g_base_info_unref ( (GIBaseInfo *) item_type_info);
+            }
+
+            if ( (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING)
+                    || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) {
+                if (type_tag == GI_TYPE_TAG_GLIST) {
+                    g_list_free ( (GList *) list);
+                } else {
+                    /* type_tag == GI_TYPE_TAG_GSLIST */
+                    g_slist_free (list);
+                }
+            }
+
+            break;
+        }
+        case GI_TYPE_TAG_GHASH:
+        {
+            GHashTable *hash_table;
+
+            if (arg->v_pointer == NULL) {
+                return;
+            }
+
+            hash_table = arg->v_pointer;
+
+            if (direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING) {
+                /* We created the table without a destroy function, so keys and
+                 * values need to be released. */
+                GITypeInfo *key_type_info;
+                GITypeInfo *value_type_info;
+                GITransfer item_transfer;
+                GHashTableIter hash_table_iter;
+                gpointer key;
+                gpointer value;
+
+                key_type_info = g_type_info_get_param_type (type_info, 0);
+                g_assert (key_type_info != NULL);
+
+                value_type_info = g_type_info_get_param_type (type_info, 1);
+                g_assert (value_type_info != NULL);
+
+                if (direction == GI_DIRECTION_IN) {
+                    item_transfer = GI_TRANSFER_NOTHING;
+                } else {
+                    item_transfer = GI_TRANSFER_EVERYTHING;
+                }
+
+                g_hash_table_iter_init (&hash_table_iter, hash_table);
+                while (g_hash_table_iter_next (&hash_table_iter, &key, &value)) {
+                    _pygi_argument_release ( (GIArgument *) &key, key_type_info,
+                                             item_transfer, direction);
+                    _pygi_argument_release ( (GIArgument *) &value, value_type_info,
+                                             item_transfer, direction);
+                }
+
+                g_base_info_unref ( (GIBaseInfo *) key_type_info);
+                g_base_info_unref ( (GIBaseInfo *) value_type_info);
+            } else if (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_CONTAINER) {
+                /* Be careful to avoid keys and values being freed if the
+                 * callee gave a destroy function. */
+                g_hash_table_steal_all (hash_table);
+            }
+
+            if ( (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING)
+                    || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) {
+                g_hash_table_unref (hash_table);
+            }
+
+            break;
+        }
+        case GI_TYPE_TAG_ERROR:
+        {
+            GError *error;
+
+            if (arg->v_pointer == NULL) {
+                return;
+            }
+
+            error = * (GError **) arg->v_pointer;
+
+            if (error != NULL) {
+                g_error_free (error);
+            }
+
+            g_slice_free (GError *, arg->v_pointer);
+            break;
+        }
+    }
+}
+
+void
+_pygi_argument_init (void)
+{
+    PyDateTime_IMPORT;
+    _pygobject_import();
+}
+
+/*** argument marshaling and validating routines ***/
+
+gboolean
+_pygi_marshal_in_void (PyGIInvokeState   *state,
+                       PyGIFunctionCache *function_cache,
+                       PyGIArgCache      *arg_cache,
+                       PyObject          *py_arg,
+                       GIArgument        *arg)
+{
+    g_warn_if_fail (arg_cache->transfer == GI_TRANSFER_NOTHING);
+
+    arg->v_pointer = py_arg;
+
+    return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_boolean (PyGIInvokeState   *state,
+                          PyGIFunctionCache *function_cache,
+                          PyGIArgCache      *arg_cache,
+                          PyObject          *py_arg,
+                          GIArgument        *arg)
+{
+    arg->v_boolean = PyObject_IsTrue(py_arg);
+
+    return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_int8 (PyGIInvokeState   *state,
+                       PyGIFunctionCache *function_cache,
+                       PyGIArgCache      *arg_cache,
+                       PyObject          *py_arg,
+                       GIArgument        *arg)
+{
+    PyObject *py_long;
+    long long_;
+
+    if (!PyNumber_Check(py_arg)) {
+        PyErr_Format (PyExc_TypeError, "Must be number, not %s",
+                      py_arg->ob_type->tp_name);
+        return FALSE;
+    }
+
+    py_long = PYGLIB_PyNumber_Long(py_arg);
+    if (!py_long)
+        return FALSE;
+
+    long_ = PYGLIB_PyLong_AsLong(py_long);
+    Py_DECREF(py_long);
+
+    if (PyErr_Occurred())
+        return FALSE;
+
+    if (long_ < -128 || long_ > 127) {
+        PyErr_Format (PyExc_ValueError, "%ld not in range %d to %d", long_, -128, 127);
+        return FALSE;
+    }
+
+    arg->v_long = long_;
+
+    return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_uint8 (PyGIInvokeState   *state,
+                        PyGIFunctionCache *function_cache,
+                        PyGIArgCache      *arg_cache,
+                        PyObject          *py_arg,
+                        GIArgument        *arg)
+{
+    unsigned long long_;
+
+    if (PYGLIB_PyBytes_Check(py_arg)) {
+
+        if (PYGLIB_PyBytes_Size(py_arg) != 1) {
+            PyErr_Format (PyExc_TypeError, "Must be a single character");
+            return FALSE;
+        }
+
+        long_ = (unsigned char)(PYGLIB_PyBytes_AsString(py_arg)[0]);
+
+    } else if (PyNumber_Check(py_arg)) {
+        PyObject *py_long;
+        py_long = PYGLIB_PyNumber_Long(py_arg);
+        if (!py_long)
+            return FALSE;
+
+        long_ = PYGLIB_PyLong_AsLong(py_long);
+        Py_DECREF(py_long);
+
+        if (PyErr_Occurred())
+            return FALSE;
+    } else {
+        PyErr_Format (PyExc_TypeError, "Must be number or single byte string, not %s",
+                      py_arg->ob_type->tp_name);
+        return FALSE;
+    }
+
+    if (long_ < 0 || long_ > 255) {
+        PyErr_Format (PyExc_ValueError, "%ld not in range %d to %d", long_, 0, 255);
+        return FALSE;
+    }
+
+    arg->v_long = long_;
+
+    return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_int16 (PyGIInvokeState   *state,
+                        PyGIFunctionCache *function_cache,
+                        PyGIArgCache      *arg_cache,
+                        PyObject          *py_arg,
+                        GIArgument        *arg)
+{
+    PyObject *py_long;
+    long long_;
+
+    if (!PyNumber_Check(py_arg)) {
+        PyErr_Format (PyExc_TypeError, "Must be number, not %s",
+                      py_arg->ob_type->tp_name);
+        return FALSE;
+    }
+
+    py_long = PYGLIB_PyNumber_Long(py_arg);
+    if (!py_long)
+        return FALSE;
+
+    long_ = PYGLIB_PyLong_AsLong(py_long);
+    Py_DECREF(py_long);
+
+    if (PyErr_Occurred())
+        return FALSE;
+
+    if (long_ < -32768 || long_ > 32767) {
+        PyErr_Format (PyExc_ValueError, "%ld not in range %d to %d", long_, -32768, 32767);
+        return FALSE;
+    }
+
+    arg->v_long = long_;
+
+    return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_uint16 (PyGIInvokeState   *state,
+                         PyGIFunctionCache *function_cache,
+                         PyGIArgCache      *arg_cache,
+                         PyObject          *py_arg,
+                         GIArgument        *arg)
+{
+    PyObject *py_long;
+    long long_;
+
+    if (!PyNumber_Check(py_arg)) {
+        PyErr_Format (PyExc_TypeError, "Must be number, not %s",
+                      py_arg->ob_type->tp_name);
+        return FALSE;
+    }
+
+    py_long = PYGLIB_PyNumber_Long(py_arg);
+    if (!py_long)
+        return FALSE;
+
+    long_ = PYGLIB_PyLong_AsLong(py_long);
+    Py_DECREF(py_long);
+
+    if (PyErr_Occurred())
+        return FALSE;
+
+    if (long_ < 0 || long_ > 65535) {
+        PyErr_Format (PyExc_ValueError, "%li not in range %d to %d", long_, 0, 65535);
+        return FALSE;
+    }
+
+    arg->v_long = long_;
+
+    return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_int32 (PyGIInvokeState   *state,
+                        PyGIFunctionCache *function_cache,
+                        PyGIArgCache      *arg_cache,
+                        PyObject          *py_arg,
+                        GIArgument        *arg)
+{
+    PyObject *py_long;
+    long long_;
+
+    if (!PyNumber_Check(py_arg)) {
+        PyErr_Format (PyExc_TypeError, "Must be number, not %s",
+                      py_arg->ob_type->tp_name);
+        return FALSE;
+    }
+
+    py_long = PYGLIB_PyNumber_Long(py_arg);
+    if (!py_long)
+        return FALSE;
+
+    long_ = PYGLIB_PyLong_AsLong(py_long);
+    Py_DECREF(py_long);
+
+    if (PyErr_Occurred())
+        return FALSE;
+
+    if (long_ < G_MININT32 || long_ > G_MAXINT32) {
+        PyErr_Format (PyExc_ValueError, "%ld not in range %d to %d", long_, G_MININT32, G_MAXINT32);
+        return FALSE;
+    }
+
+    arg->v_long = long_;
+
+    return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_uint32 (PyGIInvokeState   *state,
+                         PyGIFunctionCache *function_cache,
+                         PyGIArgCache      *arg_cache,
+                         PyObject          *py_arg,
+                         GIArgument        *arg)
+{
+    PyObject *py_long;
+    long long long_;
+
+    if (!PyNumber_Check(py_arg)) {
+        PyErr_Format (PyExc_TypeError, "Must be number, not %s",
+                      py_arg->ob_type->tp_name);
+        return FALSE;
+    }
+
+    py_long = PYGLIB_PyNumber_Long(py_arg);
+    if (!py_long)
+        return FALSE;
+
+#if PY_VERSION_HEX < 0x03000000
+    if (PyInt_Check (py_long))
+        long_ = PyInt_AsLong (py_long);
+    else
+#endif
+        long_ = PyLong_AsLongLong(py_long);
+
+    Py_DECREF(py_long);
+
+    if (PyErr_Occurred())
+        return FALSE;
+
+    if (long_ < 0 || long_ > G_MAXUINT32) {
+        PyErr_Format (PyExc_ValueError, "%lli not in range %i to %u", long_, 0, G_MAXUINT32);
+        return FALSE;
+    }
+
+    arg->v_uint64 = long_;
+
+    return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_int64 (PyGIInvokeState   *state,
+                        PyGIFunctionCache *function_cache,
+                        PyGIArgCache      *arg_cache,
+                        PyObject          *py_arg,
+                        GIArgument        *arg)
+{
+    PyObject *py_long;
+    long long long_;
+
+    if (!PyNumber_Check(py_arg)) {
+        PyErr_Format (PyExc_TypeError, "Must be number, not %s",
+                      py_arg->ob_type->tp_name);
+        return FALSE;
+    }
+
+    py_long = PYGLIB_PyNumber_Long(py_arg);
+    if (!py_long)
+        return FALSE;
+
+#if PY_VERSION_HEX < 0x03000000
+    if (PyInt_Check (py_long))
+        long_ = PyInt_AS_LONG (py_long);
+    else
+#endif
+        long_ = PyLong_AsLongLong(py_long);
+
+    Py_DECREF(py_long);
+
+    if (PyErr_Occurred()) {
+        /* OverflowError occured but range errors should be returned as ValueError */
+        char *long_str;
+        PyObject *py_str = PyObject_Str(py_long);
+
+        if (PyUnicode_Check(py_str)) {
+            PyObject *py_bytes = PyUnicode_AsUTF8String(py_str);
+            if (py_bytes == NULL)
+                return FALSE;
+
+            long_str = g_strdup(PYGLIB_PyBytes_AsString(py_bytes));
+            if (long_str == NULL) {
+                PyErr_NoMemory();
+                return FALSE;
+            }
+
+            Py_DECREF(py_bytes);
+        } else {
+            long_str = g_strdup(PYGLIB_PyBytes_AsString(py_str));
+        }
+
+        Py_DECREF(py_str);
+        PyErr_Clear();
+        PyErr_Format(PyExc_ValueError, "%s not in range %ld to %ld",
+                     long_str, G_MININT64, G_MAXINT64);
+
+        g_free(long_str);
+        return FALSE;
+    }
+
+    if (long_ < G_MININT64 || long_ > G_MAXINT64) {
+        PyErr_Format (PyExc_ValueError, "%lld not in range %ld to %ld", long_, G_MININT64, G_MAXINT64);
+        return FALSE;
+    }
+
+    arg->v_int64 = long_;
+
+    return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_uint64 (PyGIInvokeState   *state,
+                         PyGIFunctionCache *function_cache,
+                         PyGIArgCache      *arg_cache,
+                         PyObject          *py_arg,
+                         GIArgument        *arg)
+{
+    PyObject *py_long;
+    guint64 ulong_;
+
+    if (!PyNumber_Check(py_arg)) {
+        PyErr_Format (PyExc_TypeError, "Must be number, not %s",
+                      py_arg->ob_type->tp_name);
+        return FALSE;
+    }
+
+    py_long = PYGLIB_PyNumber_Long(py_arg);
+    if (!py_long)
+        return FALSE;
+
+#if PY_VERSION_HEX < 0x03000000
+    if (PyInt_Check (py_long)) {
+        long long_ = PyInt_AsLong(py_long);
+        if (long_ < 0) {
+            PyErr_Format (PyExc_ValueError, "%ld not in range %d to %llu",
+                          long_, 0, G_MAXUINT64);
+            return FALSE;
+        }
+        ulong_ = long_;
+    } else
+#endif
+        ulong_ = PyLong_AsUnsignedLongLong(py_long);
+
+    Py_DECREF(py_long);
+
+    if (PyErr_Occurred()) {
+        /* OverflowError occured but range errors should be returned as ValueError */
+        char *long_str;
+        PyObject *py_str = PyObject_Str(py_long);
+
+        if (PyUnicode_Check(py_str)) {
+            PyObject *py_bytes = PyUnicode_AsUTF8String(py_str);
+            if (py_bytes == NULL)
+                return FALSE;
+
+            long_str = g_strdup(PYGLIB_PyBytes_AsString(py_bytes));
+            if (long_str == NULL) {
+                PyErr_NoMemory();
+                return FALSE;
+            }
+
+            Py_DECREF(py_bytes);
+        } else {
+            long_str = g_strdup(PYGLIB_PyBytes_AsString(py_str));
+        }
+
+        Py_DECREF(py_str);
+        PyErr_Clear();
+        PyErr_Format(PyExc_ValueError, "%s not in range %d to %llu",
+                     long_str, 0, G_MAXUINT64);
+
+        g_free(long_str);
+        return FALSE;
+    }
+
+    if (ulong_ > G_MAXUINT64) {
+        PyErr_Format (PyExc_ValueError, "%llu not in range %d to %llu", ulong_, 0, G_MAXUINT64);
+        return FALSE;
+    }
+
+    arg->v_uint64 = ulong_;
+
+    return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_float (PyGIInvokeState   *state,
+                        PyGIFunctionCache *function_cache,
+                        PyGIArgCache      *arg_cache,
+                        PyObject          *py_arg,
+                        GIArgument        *arg)
+{
+    PyObject *py_float;
+    double double_;
+
+    if (!PyNumber_Check(py_arg)) {
+        PyErr_Format (PyExc_TypeError, "Must be number, not %s",
+                      py_arg->ob_type->tp_name);
+        return FALSE;
+    }
+
+    py_float = PyNumber_Float(py_arg);
+    if (!py_float)
+        return FALSE;
+
+    double_ = PyFloat_AsDouble(py_float);
+    Py_DECREF(py_float);
+
+    if (PyErr_Occurred())
+        return FALSE;
+
+    if (double_ < -G_MAXFLOAT || double_ > G_MAXFLOAT) {
+        PyErr_Format (PyExc_ValueError, "%f not in range %f to %f", double_, -G_MAXFLOAT, G_MAXFLOAT);
+        return FALSE;
+    }
+
+    arg->v_float = double_;
+
+    return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_double (PyGIInvokeState   *state,
+                         PyGIFunctionCache *function_cache,
+                         PyGIArgCache      *arg_cache,
+                         PyObject          *py_arg,
+                         GIArgument        *arg)
+{
+    PyObject *py_float;
+    double double_;
+
+    if (!PyNumber_Check(py_arg)) {
+        PyErr_Format (PyExc_TypeError, "Must be number, not %s",
+                      py_arg->ob_type->tp_name);
+        return FALSE;
+    }
+
+    py_float = PyNumber_Float(py_arg);
+    if (!py_float)
+        return FALSE;
+
+    double_ = PyFloat_AsDouble(py_float);
+    Py_DECREF(py_float);
+
+    if (PyErr_Occurred())
+        return FALSE;
+
+    if (double_ < -G_MAXDOUBLE || double_ > G_MAXDOUBLE) {
+        PyErr_Format (PyExc_ValueError, "%f not in range %f to %f", double_, -G_MAXDOUBLE, G_MAXDOUBLE);
+        return FALSE;
+    }
+
+    arg->v_double = double_;
+
+    return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_unichar (PyGIInvokeState   *state,
+                          PyGIFunctionCache *function_cache,
+                          PyGIArgCache      *arg_cache,
+                          PyObject          *py_arg,
+                          GIArgument        *arg)
+{
+    Py_ssize_t size;
+    gchar *string_;
+
+    if (PyUnicode_Check (py_arg)) {
+       PyObject *py_bytes;
+
+       size = PyUnicode_GET_SIZE (py_arg);
+       py_bytes = PyUnicode_AsUTF8String(py_arg);
+       string_ = strdup(PYGLIB_PyBytes_AsString(py_bytes));
+       Py_DECREF(py_bytes);
+
+#if PY_VERSION_HEX < 0x03000000
+    } else if (PyString_Check (py_arg)) {
+       PyObject *pyuni = PyUnicode_FromEncodedObject (py_arg, "UTF-8", "strict");
+       if (!pyuni)
+           return FALSE;
+
+       size = PyUnicode_GET_SIZE (pyuni);
+       string_ = g_strdup(PyString_AsString(py_arg));
+       Py_DECREF(pyuni);
+#endif
+    } else {
+       PyErr_Format (PyExc_TypeError, "Must be string, not %s",
+                     py_arg->ob_type->tp_name);
+       return FALSE;
+    }
+
+    if (size != 1) {
+       PyErr_Format (PyExc_TypeError, "Must be a one character string, not %ld characters",
+                     size);
+       g_free(string_);
+       return FALSE;
+    }
+
+    arg->v_uint32 = g_utf8_get_char(string_);
+    g_free(string_);
+
+    return TRUE;
+}
+gboolean
+_pygi_marshal_in_gtype (PyGIInvokeState   *state,
+                        PyGIFunctionCache *function_cache,
+                        PyGIArgCache      *arg_cache,
+                        PyObject          *py_arg,
+                        GIArgument        *arg)
+{
+    long type_ = pyg_type_from_object (py_arg);
+
+    if (type_ == 0) {
+        PyErr_Format (PyExc_TypeError, "Must be gobject.GType, not %s",
+                      py_arg->ob_type->tp_name);
+        return FALSE;
+    }
+
+    arg->v_long = type_;
+    return TRUE;
+}
+gboolean
+_pygi_marshal_in_utf8 (PyGIInvokeState   *state,
+                       PyGIFunctionCache *function_cache,
+                       PyGIArgCache      *arg_cache,
+                       PyObject          *py_arg,
+                       GIArgument        *arg)
+{
+    gchar *string_;
+
+    if (py_arg == Py_None) {
+        arg->v_pointer = NULL;
+        return TRUE;
+    }
+
+    if (PyUnicode_Check(py_arg)) {
+        PyObject *pystr_obj = PyUnicode_AsUTF8String (py_arg);
+        if (!pystr_obj)
+            return FALSE;
+
+        string_ = g_strdup(PYGLIB_PyBytes_AsString (pystr_obj));
+        Py_DECREF(pystr_obj);
+    }
+#if PY_VERSION_HEX < 0x03000000
+    else if (PyString_Check(py_arg)) {
+        string_ = g_strdup(PyString_AsString (py_arg));
+    }
+#endif
+    else {
+        PyErr_Format (PyExc_TypeError, "Must be string, not %s",
+                      py_arg->ob_type->tp_name);
+        return FALSE;
+    }
+
+    arg->v_string = string_;
+    return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_filename (PyGIInvokeState   *state,
+                           PyGIFunctionCache *function_cache,
+                           PyGIArgCache      *arg_cache,
+                           PyObject          *py_arg,
+                           GIArgument        *arg)
+{
+    gchar *string_;
+    GError *error = NULL;
+
+    if (PyUnicode_Check(py_arg)) {
+        PyObject *pystr_obj = PyUnicode_AsUTF8String (py_arg);
+        if (!pystr_obj)
+            return FALSE;
+
+        string_ = g_strdup(PYGLIB_PyBytes_AsString (pystr_obj));
+        Py_DECREF(pystr_obj);
+    }
+#if PY_VERSION_HEX < 0x03000000
+    else if (PyString_Check(py_arg)) {
+        string_ = g_strdup(PyString_AsString (py_arg));
+    }
+#endif
+    else {
+        PyErr_Format (PyExc_TypeError, "Must be string, not %s",
+                      py_arg->ob_type->tp_name);
+        return FALSE;
+    }
+
+    arg->v_string = g_filename_from_utf8 (string_, -1, NULL, NULL, &error);
+    g_free(string_);
+
+    if (arg->v_string == NULL) {
+        PyErr_SetString (PyExc_Exception, error->message);
+        g_error_free(error);
+        /* TODO: Convert the error to an exception. */
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_array (PyGIInvokeState   *state,
+                        PyGIFunctionCache *function_cache,
+                        PyGIArgCache      *arg_cache,
+                        PyObject          *py_arg,
+                        GIArgument        *arg)
+{
+    PyGIMarshalInFunc in_marshaller;
+    int i;
+    Py_ssize_t length;
+    GArray *array_ = NULL;
+    PyGISequenceCache *sequence_cache = (PyGISequenceCache *)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 (sequence_cache->fixed_size >= 0 &&
+        sequence_cache->fixed_size != length) {
+        PyErr_Format (PyExc_ValueError, "Must contain %zd items, not %zd",
+                      sequence_cache->fixed_size, length);
+
+        return FALSE;
+    }
+
+    array_ = g_array_sized_new (sequence_cache->is_zero_terminated,
+                                FALSE,
+                                sequence_cache->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);
+
+        goto array_success;
+    }
+
+    in_marshaller = sequence_cache->item_cache->in_marshaller;
+    for (i = 0; i < length; i++) {
+        GIArgument item;
+        PyObject *py_item = PySequence_GetItem (py_arg, i);
+        if (py_item == NULL)
+            goto err;
+
+        if (!in_marshaller(state,
+                           function_cache,
+                           sequence_cache->item_cache,
+                           py_item,
+                           &item))
+            goto err;
+
+        g_array_insert_val(array_, i, item);
+        continue;
+err:
+        if (sequence_cache->item_cache->cleanup != NULL) {
+            GDestroyNotify cleanup = sequence_cache->item_cache->cleanup;
+            /*for(j = 0; j < i; j++)
+                cleanup((gpointer)(array_->data[j]));*/
+        }
+
+        g_array_free(array_, TRUE);
+        _PyGI_ERROR_PREFIX ("Item %i: ", i);
+        return FALSE;
+    }
+
+array_success:
+    if (sequence_cache->len_arg_index >= 0) {
+        /* we have an aux arg to handle */
+        PyGIArgCache *aux_cache =
+            function_cache->args_cache[sequence_cache->len_arg_index];
+
+        if (aux_cache->direction == GI_DIRECTION_INOUT) {
+            gint *len_arg = (gint *)state->in_args[aux_cache->c_arg_index].v_pointer;
+            /* if we are not setup yet just set the in arg */
+            if (len_arg == NULL)
+                state->in_args[aux_cache->c_arg_index].v_long = length;
+            else
+                *len_arg = length;
+        } else {              
+            state->in_args[aux_cache->c_arg_index].v_long = length;
+        }
+    }
+
+    if (sequence_cache->array_type == GI_ARRAY_TYPE_C) {
+        arg->v_pointer = array_->data;
+        g_array_free(array_, FALSE);
+    } else {
+        arg->v_pointer = array_;
+    }
+
+    return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_glist (PyGIInvokeState   *state,
+                        PyGIFunctionCache *function_cache,
+                        PyGIArgCache      *arg_cache,
+                        PyObject          *py_arg,
+                        GIArgument        *arg)
+{
+    PyGIMarshalInFunc in_marshaller;
+    int i;
+    Py_ssize_t length;
+    GList *list_ = NULL;
+    PyGISequenceCache *sequence_cache = (PyGISequenceCache *)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 (sequence_cache->fixed_size >= 0 &&
+        sequence_cache->fixed_size != length) {
+        PyErr_Format (PyExc_ValueError, "Must contain %zd items, not %zd",
+                      sequence_cache->fixed_size, length);
+
+        return FALSE;
+    }
+
+    in_marshaller = sequence_cache->item_cache->in_marshaller;
+    for (i = 0; i < length; i++) {
+        GIArgument item;
+        PyObject *py_item = PySequence_GetItem (py_arg, i);
+        if (py_item == NULL)
+            goto err;
+
+        if (!in_marshaller(state,
+                           function_cache,
+                           sequence_cache->item_cache,
+                           py_item,
+                           &item))
+            goto err;
+
+        list_ = g_list_append(list_, item.v_pointer);
+        continue;
+err:
+        if (sequence_cache->item_cache->cleanup != NULL) {
+            GDestroyNotify cleanup = sequence_cache->item_cache->cleanup;
+        }
+
+        g_list_free(list_);
+        _PyGI_ERROR_PREFIX ("Item %i: ", i);
+        return FALSE;
+    }
+
+    arg->v_pointer = list_;
+    return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_gslist (PyGIInvokeState   *state,
+                         PyGIFunctionCache *function_cache,
+                         PyGIArgCache      *arg_cache,
+                         PyObject          *py_arg,
+                         GIArgument        *arg)
+{
+    PyGIMarshalInFunc in_marshaller;
+    int i;
+    Py_ssize_t length;
+    GSList *list_ = NULL;
+    PyGISequenceCache *sequence_cache = (PyGISequenceCache *)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 (sequence_cache->fixed_size >= 0 &&
+        sequence_cache->fixed_size != length) {
+        PyErr_Format (PyExc_ValueError, "Must contain %zd items, not %zd",
+                      sequence_cache->fixed_size, length);
+
+        return FALSE;
+    }
+
+    in_marshaller = sequence_cache->item_cache->in_marshaller;
+    for (i = 0; i < length; i++) {
+        GIArgument item;
+        PyObject *py_item = PySequence_GetItem (py_arg, i);
+        if (py_item == NULL)
+            goto err;
+
+        if (!in_marshaller(state,
+                           function_cache,
+                           sequence_cache->item_cache,
+                           py_item,
+                           &item))
+            goto err;
+
+        list_ = g_slist_append(list_, item.v_pointer);
+        continue;
+err:
+        if (sequence_cache->item_cache->cleanup != NULL) {
+            GDestroyNotify cleanup = sequence_cache->item_cache->cleanup;
+        }
+
+        g_slist_free(list_);
+        _PyGI_ERROR_PREFIX ("Item %i: ", i);
+        return FALSE;
+    }
+
+    arg->v_pointer = list_;
+    return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_ghash (PyGIInvokeState   *state,
+                        PyGIFunctionCache *function_cache,
+                        PyGIArgCache      *arg_cache,
+                        PyObject          *py_arg,
+                        GIArgument        *arg)
+{
+    PyGIMarshalInFunc key_in_marshaller;
+    PyGIMarshalInFunc value_in_marshaller;
+
+    int i;
+    Py_ssize_t length;
+    PyObject *py_keys, *py_values;
+
+    GHashFunc hash_func;
+    GEqualFunc equal_func;
+
+    GHashTable *hash_ = NULL;
+    PyGIHashCache *hash_cache = (PyGIHashCache *)arg_cache;
+
+    if (py_arg == Py_None) {
+        arg->v_pointer = NULL;
+        return TRUE;
+    }
+
+    py_keys = PyMapping_Keys(py_arg);
+    if (py_keys == NULL) {
+        PyErr_Format (PyExc_TypeError, "Must be mapping, not %s",
+                      py_arg->ob_type->tp_name);
+        return FALSE;
+    }
+
+    length = PyMapping_Length(py_arg);
+    if (length < 0) {
+        Py_DECREF(py_keys);
+        return FALSE;
+    }
+
+    py_values = PyMapping_Values(py_arg);
+    if (py_values == NULL) {
+        Py_DECREF(py_keys);
+        return FALSE;
+    }
+
+    key_in_marshaller = hash_cache->key_cache->in_marshaller;
+    value_in_marshaller = hash_cache->value_cache->in_marshaller;
+
+    switch (hash_cache->key_cache->type_tag) {
+        case GI_TYPE_TAG_UTF8:
+        case GI_TYPE_TAG_FILENAME:
+            hash_func = g_str_hash;
+            equal_func = g_str_equal;
+            break;
+        default:
+            hash_func = NULL;
+            equal_func = NULL;
+    }
+
+    hash_ = g_hash_table_new (hash_func, equal_func);
+    if (hash_ == NULL) {
+        PyErr_NoMemory();
+        Py_DECREF(py_keys);
+        Py_DECREF(py_values);
+        return FALSE;
+    }
+
+    for (i = 0; i < length; i++) {
+        GIArgument key, value;
+        PyObject *py_key = PyList_GET_ITEM (py_keys, i);
+        PyObject *py_value = PyList_GET_ITEM (py_values, i);
+        if (py_key == NULL || py_value == NULL)
+            goto err;
+
+        if (!key_in_marshaller(state,
+                               function_cache,
+                               hash_cache->key_cache,
+                               py_key,
+                               &key))
+            goto err;
+
+        if (!value_in_marshaller(state,
+                                 function_cache,
+                                 hash_cache->value_cache,
+                                 py_value,
+                                 &value))
+            goto err;
+
+        g_hash_table_insert(hash_, key.v_pointer, value.v_pointer);
+        continue;
+err:
+        /* FIXME: cleanup hash keys and values */
+        Py_XDECREF(py_key);
+        Py_XDECREF(py_value);
+        Py_DECREF(py_keys);
+        Py_DECREF(py_values);
+        g_hash_table_unref(hash_);
+        _PyGI_ERROR_PREFIX ("Item %i: ", i);
+        return FALSE;
+    }
+
+    arg->v_pointer = hash_;
+    return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_gerror (PyGIInvokeState   *state,
+                         PyGIFunctionCache *function_cache,
+                         PyGIArgCache      *arg_cache,
+                         PyObject          *py_arg,
+                         GIArgument        *arg)
+{
+    PyErr_Format(PyExc_NotImplementedError,
+                 "Marshalling for GErrors is not implemented");
+    return FALSE;
+}
+
+gboolean
+_pygi_marshal_in_interface_callback (PyGIInvokeState   *state,
+                                     PyGIFunctionCache *function_cache,
+                                     PyGIArgCache      *arg_cache,
+                                     PyObject          *py_arg,
+                                     GIArgument        *arg)
+{
+    GICallableInfo *callable_info;
+    PyGICClosure *closure;
+    PyGIArgCache *user_data_cache = NULL;
+    PyGIArgCache *destroy_cache = NULL;
+    PyGICallbackCache *callback_cache;
+    PyObject *py_user_data = NULL;
+
+    callback_cache = (PyGICallbackCache *)arg_cache;
+
+    if (callback_cache->user_data_index > 0) {
+        user_data_cache = function_cache->args_cache[callback_cache->user_data_index];
+        if (user_data_cache->py_arg_index < state->n_py_in_args) {
+            py_user_data = PyTuple_GetItem(state->py_in_args, user_data_cache->py_arg_index);
+            if (!py_user_data)
+                return FALSE;
+        } else {
+            py_user_data = Py_None;
+            Py_INCREF(Py_None);
+        }
+    }
+
+    if (py_arg == Py_None && !(py_user_data == Py_None || py_user_data == NULL)) {
+        Py_DECREF(py_user_data);
+        PyErr_Format(PyExc_TypeError,
+                     "When passing None for a callback userdata must also be None");
+
+        return FALSE;
+    }
+
+    if (py_arg == Py_None) {
+        Py_XDECREF(py_user_data);
+        return TRUE;
+    }
+
+    if (!PyCallable_Check(py_arg)) {
+        Py_XDECREF(py_user_data);
+        PyErr_Format(PyExc_TypeError,
+                    "Callback needs to be a function or method not %s",
+                    py_arg->ob_type->tp_name);
+
+        return FALSE;
+    }
+
+    if (callback_cache->destroy_notify_index > 0)
+        destroy_cache = function_cache->args_cache[callback_cache->destroy_notify_index];
+
+    callable_info = (GICallableInfo *)callback_cache->interface_info;
+
+    closure = _pygi_make_native_closure (callable_info, callback_cache->scope, py_arg, py_user_data);
+    arg->v_pointer = closure->closure;
+    if (user_data_cache != NULL) {
+        state->in_args[user_data_cache->c_arg_index].v_pointer = closure;
+    }
+
+    if (destroy_cache) {
+        PyGICClosure *destroy_notify = _pygi_destroy_notify_create();
+        state->in_args[destroy_cache->c_arg_index].v_pointer = destroy_notify->closure;
+    }
+
+    return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_interface_enum (PyGIInvokeState   *state,
+                                 PyGIFunctionCache *function_cache,
+                                 PyGIArgCache      *arg_cache,
+                                 PyObject          *py_arg,
+                                 GIArgument        *arg)
+{
+    PyObject *int_;
+    gint is_instance;
+    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
+
+    is_instance = PyObject_IsInstance(py_arg, iface_cache->py_type);
+
+    int_ = PYGLIB_PyNumber_Long(py_arg);
+    if (int_ == NULL) {
+        PyErr_Clear();
+        goto err;
+    }
+
+    arg->v_long = PYGLIB_PyLong_AsLong(int_);
+    Py_DECREF(int_);
+
+    /* If this is not an instance of the Enum type that we want
+     * we need to check if the value is equivilant to one of the
+     * Enum's memebers */
+    if (!is_instance) {
+        int i;
+        gboolean is_found = FALSE;
+
+        for (i = 0; i < g_enum_info_get_n_values(iface_cache->interface_info); i++) {
+            GIValueInfo *value_info =
+                g_enum_info_get_value(iface_cache->interface_info, i);
+            glong enum_value = g_value_info_get_value(value_info);
+            g_base_info_unref( (GIBaseInfo *)value_info);
+            if (arg->v_long == enum_value) {
+                is_found = TRUE;
+                break;
+            }
+        }
+
+        if (!is_found)
+            goto err;
+    }
+
+    return TRUE;
+
+err:
+    PyErr_Format(PyExc_TypeError, "Expected a %s, but got %s",
+                 iface_cache->type_name, py_arg->ob_type->tp_name);
+    return FALSE;
+}
+
+gboolean
+_pygi_marshal_in_interface_flags (PyGIInvokeState   *state,
+                                  PyGIFunctionCache *function_cache,
+                                  PyGIArgCache      *arg_cache,
+                                  PyObject          *py_arg,
+                                  GIArgument        *arg)
+{
+    PyObject *int_;
+    gint is_instance;
+    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
+
+    is_instance = PyObject_IsInstance(py_arg, iface_cache->py_type);
+
+    int_ = PYGLIB_PyNumber_Long(py_arg);
+    if (int_ == NULL) {
+        PyErr_Clear();
+        goto err;
+    }
+
+    arg->v_long = PYGLIB_PyLong_AsLong(int_);
+    Py_DECREF(int_);
+
+    /* only 0 or argument of type Flag is allowed */
+    if (!is_instance && arg->v_long != 0)
+        goto err;
+
+    return TRUE;
+
+err:
+    PyErr_Format (PyExc_TypeError, "Expected a %s, but got %s",
+                  iface_cache->type_name, py_arg->ob_type->tp_name);
+    return FALSE;
+
+}
+
+gboolean
+_pygi_marshal_in_interface_struct (PyGIInvokeState   *state,
+                                   PyGIFunctionCache *function_cache,
+                                   PyGIArgCache      *arg_cache,
+                                   PyObject          *py_arg,
+                                   GIArgument        *arg)
+{
+    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
+
+    if (py_arg == Py_None) {
+        arg->v_pointer = NULL;
+        return TRUE;
+    }
+
+    /* FIXME: handle this large if statement in the cache
+     *        and set the correct marshaller
+     */
+
+    if (iface_cache->g_type == G_TYPE_CLOSURE) {
+        GClosure *closure;
+        if (!PyCallable_Check(py_arg)) {
+            PyErr_Format(PyExc_TypeError, "Must be callable, not %s",
+                         py_arg->ob_type->tp_name);
+            return FALSE;
+        }
+
+        closure = pyg_closure_new(py_arg, NULL, NULL);
+        if (closure == NULL) {
+            PyErr_SetString(PyExc_RuntimeError, "PyObject conversion to GClosure failed");
+            return FALSE;
+        }
+
+        arg->v_pointer = closure;
+        return TRUE;
+    } else if (iface_cache->g_type == G_TYPE_VALUE) {
+        GValue *value;
+        GType object_type;
+
+        object_type = pyg_type_from_object_strict( (PyObject *) py_arg->ob_type, FALSE);
+        if (object_type == G_TYPE_INVALID) {
+            PyErr_SetString (PyExc_RuntimeError, "unable to retrieve object's GType");
+            return FALSE;
+        }
+
+        value = g_slice_new0 (GValue);
+        g_value_init (value, object_type);
+        if (pyg_value_from_pyobject(value, py_arg) < 0) {
+            g_slice_free (GValue, value);
+            PyErr_SetString (PyExc_RuntimeError, "PyObject conversion to GValue failed");
+            return FALSE;
+        }
+
+        arg->v_pointer = value;
+        return TRUE;
+    } else if (iface_cache->is_foreign) {
+        gboolean success;
+        success = pygi_struct_foreign_convert_to_g_argument(py_arg,
+                                                            iface_cache->interface_info,
+                                                            arg_cache->transfer,
+                                                            arg);
+
+        return success;
+    } else if (!PyObject_IsInstance(py_arg, iface_cache->py_type)) {
+        PyErr_Format (PyExc_TypeError, "Expected %s, but got %s",
+                      iface_cache->type_name,
+                      iface_cache->py_type->ob_type->tp_name);
+        return FALSE;
+    }
+
+    if (g_type_is_a (iface_cache->g_type, G_TYPE_BOXED)) {
+        arg->v_pointer = pyg_boxed_get(py_arg, void);
+        if (arg_cache->transfer == GI_TRANSFER_EVERYTHING) {
+            arg->v_pointer = g_boxed_copy(iface_cache->g_type, arg->v_pointer);
+        }
+    } else if (g_type_is_a (iface_cache->g_type, G_TYPE_POINTER) ||
+               iface_cache->g_type  == G_TYPE_NONE) {
+        arg->v_pointer = pyg_pointer_get(py_arg, void);
+    } else {
+        PyErr_Format (PyExc_NotImplementedError, "structure type '%s' is not supported yet", g_type_name(iface_cache->g_type));
+        return FALSE;
+    }
+    return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_interface_boxed (PyGIInvokeState   *state,
+                                  PyGIFunctionCache *function_cache,
+                                  PyGIArgCache      *arg_cache,
+                                  PyObject          *py_arg,
+                                  GIArgument        *arg)
+{
+    PyErr_Format(PyExc_NotImplementedError,
+                 "Marshalling for this type is not implemented yet");
+    return FALSE;
+}
+
+gboolean
+_pygi_marshal_in_interface_object (PyGIInvokeState   *state,
+                                   PyGIFunctionCache *function_cache,
+                                   PyGIArgCache      *arg_cache,
+                                   PyObject          *py_arg,
+                                   GIArgument        *arg)
+{
+    if (py_arg == Py_None) {
+        arg->v_pointer = NULL;
+        return TRUE;
+    }
+
+    if (!PyObject_IsInstance (py_arg, ((PyGIInterfaceCache *)arg_cache)->py_type)) {
+        PyErr_Format (PyExc_TypeError, "Expected %s, but got %s",
+                      ((PyGIInterfaceCache *)arg_cache)->type_name,
+                      ((PyGIInterfaceCache *)arg_cache)->py_type->ob_type->tp_name);
+        return FALSE;
+    }
+
+    arg->v_pointer = pygobject_get(py_arg);
+    if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
+        g_object_ref(arg->v_pointer);
+
+    return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_interface_union (PyGIInvokeState   *state,
+                                  PyGIFunctionCache *function_cache,
+                                  PyGIArgCache      *arg_cache,
+                                  PyObject          *py_arg,
+                                  GIArgument        *arg)
+{
+    PyErr_Format(PyExc_NotImplementedError,
+                 "Marshalling for this type is not implemented yet");
+    return FALSE;
+}
+
+PyObject *
+_pygi_marshal_out_void (PyGIInvokeState   *state,
+                        PyGIFunctionCache *function_cache,
+                        PyGIArgCache      *arg_cache,
+                        GIArgument        *arg)
+{
+    PyObject *py_obj = NULL;
+    if (arg_cache->is_pointer)
+        py_obj = arg->v_pointer;
+    else
+        py_obj = Py_None;
+
+    Py_XINCREF(py_obj);
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_boolean (PyGIInvokeState   *state,
+                           PyGIFunctionCache *function_cache,
+                           PyGIArgCache      *arg_cache,
+                           GIArgument        *arg)
+{
+    PyObject *py_obj = PyBool_FromLong(arg->v_boolean);
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_int8 (PyGIInvokeState   *state,
+                        PyGIFunctionCache *function_cache,
+                        PyGIArgCache      *arg_cache,
+                        GIArgument        *arg)
+{
+    PyObject *py_obj = PYGLIB_PyLong_FromLong(arg->v_int8);
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_uint8 (PyGIInvokeState   *state,
+                         PyGIFunctionCache *function_cache,
+                         PyGIArgCache      *arg_cache,
+                         GIArgument        *arg)
+{
+    PyObject *py_obj =  PYGLIB_PyLong_FromLong(arg->v_uint8);
+
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_int16 (PyGIInvokeState   *state,
+                         PyGIFunctionCache *function_cache,
+                         PyGIArgCache      *arg_cache,
+                         GIArgument        *arg)
+{
+    PyObject *py_obj =  PYGLIB_PyLong_FromLong(arg->v_int16);
+
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_uint16 (PyGIInvokeState   *state,
+                          PyGIFunctionCache *function_cache,
+                          PyGIArgCache      *arg_cache,
+                          GIArgument        *arg)
+{
+    PyObject *py_obj =  PYGLIB_PyLong_FromLong(arg->v_uint16);
+
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_int32 (PyGIInvokeState   *state,
+                         PyGIFunctionCache *function_cache,
+                         PyGIArgCache      *arg_cache,
+                         GIArgument        *arg)
+{
+    PyObject *py_obj = PYGLIB_PyLong_FromLong(arg->v_int32);
+
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_uint32 (PyGIInvokeState   *state,
+                          PyGIFunctionCache *function_cache,
+                          PyGIArgCache      *arg_cache,
+                          GIArgument        *arg)
+{
+    PyObject *py_obj = PyLong_FromLongLong(arg->v_uint32);
+
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_int64 (PyGIInvokeState   *state,
+                         PyGIFunctionCache *function_cache,
+                         PyGIArgCache      *arg_cache,
+                         GIArgument        *arg)
+{
+    PyObject *py_obj = PyLong_FromLongLong(arg->v_int64);
+
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_uint64 (PyGIInvokeState   *state,
+                          PyGIFunctionCache *function_cache,
+                          PyGIArgCache      *arg_cache,
+                          GIArgument        *arg)
+{
+    PyObject *py_obj = PyLong_FromUnsignedLongLong(arg->v_uint64);
+
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_float (PyGIInvokeState   *state,
+                         PyGIFunctionCache *function_cache,
+                         PyGIArgCache      *arg_cache,
+                         GIArgument        *arg)
+{
+    PyObject *py_obj = PyFloat_FromDouble (arg->v_float);
+
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_double (PyGIInvokeState   *state,
+                          PyGIFunctionCache *function_cache,
+                          PyGIArgCache      *arg_cache,
+                          GIArgument        *arg)
+{
+    PyObject *py_obj = PyFloat_FromDouble (arg->v_double);
+
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_unichar (PyGIInvokeState   *state,
+                           PyGIFunctionCache *function_cache,
+                           PyGIArgCache      *arg_cache,
+                           GIArgument        *arg)
+{
+    PyObject *py_obj = NULL;
+
+    /* Preserve the bidirectional mapping between 0 and "" */
+    if (arg->v_uint32 == 0) {
+        py_obj = PYGLIB_PyUnicode_FromString ("");
+    } else if (g_unichar_validate (arg->v_uint32)) {
+        gchar utf8[6];
+        gint bytes;
+
+        bytes = g_unichar_to_utf8 (arg->v_uint32, utf8);
+        py_obj = PYGLIB_PyUnicode_FromStringAndSize ((char*)utf8, bytes);
+    } else {
+        /* TODO: Convert the error to an exception. */
+        PyErr_Format (PyExc_TypeError,
+                      "Invalid unicode codepoint %" G_GUINT32_FORMAT,
+                      arg->v_uint32);
+    }
+
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_gtype (PyGIInvokeState   *state,
+                         PyGIFunctionCache *function_cache,
+                         PyGIArgCache      *arg_cache,
+                         GIArgument        *arg)
+{
+    PyObject *py_obj = NULL;
+
+    py_obj = pyg_type_wrapper_new( (GType)arg->v_long);
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_utf8 (PyGIInvokeState   *state,
+                        PyGIFunctionCache *function_cache,
+                        PyGIArgCache      *arg_cache,
+                        GIArgument        *arg)
+{
+    PyObject *py_obj = NULL;
+    if (arg->v_string == NULL) {
+        py_obj = Py_None;
+        Py_INCREF (py_obj);
+        return py_obj;
+     }
+
+    py_obj = PYGLIB_PyUnicode_FromString (arg->v_string);
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_filename (PyGIInvokeState   *state,
+                            PyGIFunctionCache *function_cache,
+                            PyGIArgCache      *arg_cache,
+                            GIArgument        *arg)
+{
+    gchar *string;
+    PyObject *py_obj = NULL;
+    GError *error = NULL;
+
+    if (arg->v_string == NULL) {
+        py_obj = Py_None;
+        Py_INCREF (py_obj);
+        return py_obj;
+    }
+
+    string = g_filename_to_utf8 (arg->v_string, -1, NULL, NULL, &error);
+    if (string == NULL) {
+        PyErr_SetString (PyExc_Exception, error->message);
+        /* TODO: Convert the error to an exception. */
+        return NULL;
+    }
+
+    py_obj = PYGLIB_PyUnicode_FromString (string);
+    g_free (string);
+
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_array (PyGIInvokeState   *state,
+                         PyGIFunctionCache *function_cache,
+                         PyGIArgCache      *arg_cache,
+                         GIArgument        *arg)
+{
+    GArray *array_;
+    PyObject *py_obj = NULL;
+    PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
+
+    array_ = arg->v_pointer;
+
+     /* 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 (seq_cache->array_type == GI_ARRAY_TYPE_C) {
+        gsize len;
+        if (seq_cache->fixed_size >= 0) {
+            len = seq_cache->fixed_size;
+        } else if (seq_cache->is_zero_terminated) {
+            len = g_strv_length(arg->v_string);
+        } else {
+            GIArgument *len_arg = state->args[seq_cache->len_arg_index];
+            len = len_arg->v_long;
+        }
+
+        array_ = g_array_new(seq_cache->is_zero_terminated,
+                             FALSE,
+                             seq_cache->item_size);
+        if (array_ == NULL) {
+            PyErr_NoMemory();
+            return NULL;
+        }
+
+        array_->data = arg->v_pointer;
+        array_->len = len;
+    }
+
+    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;
+            gboolean is_struct;
+            gsize item_size;
+            PyGIMarshalOutFunc item_out_marshaller;
+            PyGIArgCache *item_arg_cache;
+
+            py_obj = PyList_New(array_->len);
+            if (py_obj == NULL) {
+                if (seq_cache->array_type == GI_ARRAY_TYPE_C)
+                    g_array_unref(array_);
+
+                return NULL;
+            }
+
+            item_arg_cache = seq_cache->item_cache;
+            item_out_marshaller = item_arg_cache->out_marshaller;
+            is_struct = FALSE;
+            if (item_arg_cache->type_tag == GI_TYPE_TAG_INTERFACE) {
+                PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)item_arg_cache;
+                switch (g_base_info_get_type(iface_cache->interface_info)) {
+                    case GI_INFO_TYPE_STRUCT:
+                        case GI_INFO_TYPE_BOXED:
+                            is_struct = TRUE;
+                        default:
+                            break;
+                }
+            }
+
+            item_size = g_array_get_element_size(array_);
+            for (i = 0; i < array_->len; i++) {
+                GIArgument item_arg;
+                PyObject *py_item;
+
+                if (is_struct) {
+                    item_arg.v_pointer = &_g_array_index(array_, GIArgument, i);
+                } else {
+                    memcpy (&item_arg, &_g_array_index (array_, GIArgument, i), item_size);
+                }
+
+                py_item = item_out_marshaller(state,
+                                              function_cache,
+                                              item_arg_cache,
+                                              &item_arg);
+
+                if (py_item == NULL) {
+                    Py_CLEAR(py_obj);
+
+                    if (seq_cache->array_type == GI_ARRAY_TYPE_C)
+                        g_array_unref(array_);
+
+                    return NULL;
+                }
+                PyList_SET_ITEM(py_obj, i, py_item);
+            }
+        }
+    }
+
+    if (seq_cache->array_type == GI_ARRAY_TYPE_C)
+        g_array_free(array_, FALSE);
+
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_glist (PyGIInvokeState   *state,
+                         PyGIFunctionCache *function_cache,
+                         PyGIArgCache      *arg_cache,
+                         GIArgument        *arg)
+{
+    GList *list_;
+    gsize length;
+    gsize i;
+
+    PyGIMarshalOutFunc item_out_marshaller;
+    PyGIArgCache *item_arg_cache;
+    PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
+
+    PyObject *py_obj = NULL;
+
+    list_ = arg->v_pointer;
+    length = g_list_length(list_);
+
+    py_obj = PyList_New(length);
+    if (py_obj == NULL)
+        return NULL;
+
+    item_arg_cache = seq_cache->item_cache;
+    item_out_marshaller = item_arg_cache->out_marshaller;
+
+    for (i = 0; list_ != NULL; list_ = g_list_next (list_), i++) {
+        GIArgument item_arg;
+        PyObject *py_item;
+
+        item_arg.v_pointer = list_->data;
+        py_item = item_out_marshaller(state,
+                                      function_cache,
+                                      item_arg_cache,
+                                      &item_arg);
+
+        if (py_item == NULL) {
+            Py_CLEAR (py_obj);
+            _PyGI_ERROR_PREFIX ("Item %zu: ", i);
+            return NULL;
+        }
+
+        PyList_SET_ITEM (py_obj, i, py_item);
+    }
+
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_gslist (PyGIInvokeState   *state,
+                          PyGIFunctionCache *function_cache,
+                          PyGIArgCache      *arg_cache,
+                          GIArgument        *arg)
+{
+    GSList *list_;
+    gsize length;
+    gsize i;
+
+    PyGIMarshalOutFunc item_out_marshaller;
+    PyGIArgCache *item_arg_cache;
+    PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
+
+    PyObject *py_obj = NULL;
+
+    list_ = arg->v_pointer;
+    length = g_slist_length(list_);
+
+    py_obj = PyList_New(length);
+    if (py_obj == NULL)
+        return NULL;
+
+    item_arg_cache = seq_cache->item_cache;
+    item_out_marshaller = item_arg_cache->out_marshaller;
+
+    for (i = 0; list_ != NULL; list_ = g_slist_next (list_), i++) {
+        GIArgument item_arg;
+        PyObject *py_item;
+
+        item_arg.v_pointer = list_->data;
+        py_item = item_out_marshaller(state,
+                                      function_cache,
+                                      item_arg_cache,
+                                      &item_arg);
+
+        if (py_item == NULL) {
+            Py_CLEAR (py_obj);
+            _PyGI_ERROR_PREFIX ("Item %zu: ", i);
+            return NULL;
+        }
+
+        PyList_SET_ITEM (py_obj, i, py_item);
+    }
+
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_ghash (PyGIInvokeState   *state,
+                         PyGIFunctionCache *function_cache,
+                         PyGIArgCache      *arg_cache,
+                         GIArgument        *arg)
+{
+    GHashTable *hash_;
+    GHashTableIter hash_table_iter;
+
+    PyGIMarshalOutFunc key_out_marshaller;
+    PyGIMarshalOutFunc value_out_marshaller;
+
+    PyGIArgCache *key_arg_cache;
+    PyGIArgCache *value_arg_cache;
+    PyGIHashCache *hash_cache = (PyGIHashCache *)arg_cache;
+
+    GIArgument key_arg;
+    GIArgument value_arg;
+
+    PyObject *py_obj = NULL;
+
+    hash_ = arg->v_pointer;
+
+    if (hash_ == NULL) {
+        py_obj = Py_None;
+        Py_INCREF (py_obj);
+        return py_obj;
+    }
+
+    py_obj = PyDict_New();
+    if (py_obj == NULL)
+        return NULL;
+
+    key_arg_cache = hash_cache->key_cache;
+    key_out_marshaller = key_arg_cache->out_marshaller;
+
+    value_arg_cache = hash_cache->value_cache;
+    value_out_marshaller = value_arg_cache->out_marshaller;
+
+    g_hash_table_iter_init(&hash_table_iter, hash_);
+    while (g_hash_table_iter_next(&hash_table_iter,
+                                  &key_arg.v_pointer,
+                                  &value_arg.v_pointer)) {
+        PyObject *py_key;
+        PyObject *py_value;
+        int retval;
+
+        py_key = key_out_marshaller(state,
+                                    function_cache,
+                                    key_arg_cache,
+                                    &key_arg);
+
+        if (py_key == NULL) {
+            Py_CLEAR (py_obj);
+            return NULL;
+        }
+
+        py_value = value_out_marshaller(state,
+                                        function_cache,
+                                        value_arg_cache,
+                                        &value_arg);
+
+        if (py_value == NULL) {
+            Py_CLEAR (py_obj);
+            Py_DECREF(py_key);
+            return NULL;
+        }
+
+        retval = PyDict_SetItem (py_obj, py_key, py_value);
+
+        Py_DECREF(py_key);
+        Py_DECREF(py_value);
+
+        if (retval < 0) {
+            Py_CLEAR(py_obj);
+            return NULL;
+        }
+    }
+
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_gerror (PyGIInvokeState   *state,
+                          PyGIFunctionCache *function_cache,
+                          PyGIArgCache      *arg_cache,
+                          GIArgument        *arg)
+{
+    PyObject *py_obj = NULL;
+
+    PyErr_Format(PyExc_NotImplementedError,
+                 "Marshalling for gerror out is not implemented");
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_interface_callback(PyGIInvokeState   *state,
+                                     PyGIFunctionCache *function_cache,
+                                     PyGIArgCache      *arg_cache,
+                                     GIArgument        *arg)
+{
+    PyObject *py_obj = NULL;
+
+    PyErr_Format(PyExc_NotImplementedError,
+                 "Callback out values are not supported");
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_interface_enum (PyGIInvokeState   *state,
+                                  PyGIFunctionCache *function_cache,
+                                  PyGIArgCache      *arg_cache,
+                                  GIArgument        *arg)
+{
+    PyObject *py_obj = NULL;
+    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
+
+    if (iface_cache->g_type == G_TYPE_NONE) {
+        py_obj = PyObject_CallFunction (iface_cache->py_type, "l", arg->v_long);
+    } else {
+        py_obj = pyg_enum_from_gtype(iface_cache->g_type, arg->v_long);
+    }
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_interface_flags (PyGIInvokeState   *state,
+                                   PyGIFunctionCache *function_cache,
+                                   PyGIArgCache      *arg_cache,
+                                   GIArgument        *arg)
+{
+    PyObject *py_obj = NULL;
+    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
+    py_obj = pyg_flags_from_gtype(iface_cache->g_type, arg->v_long);
+
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_interface_struct (PyGIInvokeState   *state,
+                                    PyGIFunctionCache *function_cache,
+                                    PyGIArgCache      *arg_cache,
+                                    GIArgument        *arg)
+{
+    PyObject *py_obj = NULL;
+    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
+    GType type = iface_cache->g_type;
+
+    if (g_type_is_a (type, G_TYPE_VALUE)) {
+        py_obj = pyg_value_as_pyobject (arg->v_pointer, FALSE);
+    } else if (g_type_is_a (type, G_TYPE_BOXED)) {
+        py_obj = _pygi_boxed_new ( (PyTypeObject *)iface_cache->py_type, arg->v_pointer, 
+                                  arg_cache->transfer == GI_TRANSFER_EVERYTHING);
+    } else if (g_type_is_a (type, G_TYPE_POINTER)) {
+        if (iface_cache->py_type == NULL ||
+                !PyType_IsSubtype( (PyTypeObject *)iface_cache->py_type, &PyGIStruct_Type)) {
+            g_warn_if_fail(arg_cache->transfer == GI_TRANSFER_NOTHING);
+            py_obj = pyg_pointer_new(type, arg->v_pointer);
+        } else {
+            py_obj = _pygi_struct_new ( (PyTypeObject *)iface_cache->py_type, arg->v_pointer, 
+                                      arg_cache->transfer == GI_TRANSFER_EVERYTHING);
+        }
+    } else if (type == G_TYPE_NONE && iface_cache->is_foreign) {
+        py_obj = pygi_struct_foreign_convert_from_g_argument (iface_cache->interface_info, arg->v_pointer);
+    } else if (type == G_TYPE_NONE) {
+        py_obj = _pygi_struct_new((PyTypeObject *) iface_cache->py_type, arg->v_pointer, 
+                                  arg_cache->transfer == GI_TRANSFER_EVERYTHING);
+    } else {
+        PyErr_Format (PyExc_NotImplementedError, "structure type '%s' is not supported yet", g_type_name (type));
+    }
+
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_interface_interface (PyGIInvokeState   *state,
+                                       PyGIFunctionCache *function_cache,
+                                       PyGIArgCache      *arg_cache,
+                                       GIArgument        *arg)
+{
+    PyObject *py_obj = NULL;
+
+    PyErr_Format(PyExc_NotImplementedError,
+                 "Marshalling for this type is not implemented yet");
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_interface_boxed (PyGIInvokeState   *state,
+                                   PyGIFunctionCache *function_cache,
+                                   PyGIArgCache      *arg_cache,
+                                   GIArgument        *arg)
+{
+    PyObject *py_obj = NULL;
+
+    PyErr_Format(PyExc_NotImplementedError,
+                 "Marshalling for this type is not implemented yet");
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_interface_object (PyGIInvokeState   *state,
+                                    PyGIFunctionCache *function_cache,
+                                    PyGIArgCache      *arg_cache,
+                                    GIArgument        *arg)
+{
+    PyObject *py_obj = pygobject_new (arg->v_pointer);
+
+    if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
+        g_object_unref (arg->v_pointer);
+    
+    return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_interface_union  (PyGIInvokeState   *state,
+                                    PyGIFunctionCache *function_cache,
+                                    PyGIArgCache      *arg_cache,
+                                    GIArgument        *arg)
+{
+    PyObject *py_obj = NULL;
+
+    PyErr_Format(PyExc_NotImplementedError,
+                 "Marshalling for this type is not implemented yet");
+    return py_obj;
+}
+



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