[pygobject] cache refactoring: Move various struct arg setup and marshaling to new file



commit 1d0f120d77582509b4e75d83f500a1ace7ed6421
Author: Simon Feltman <sfeltman src gnome org>
Date:   Sat Oct 12 20:00:12 2013 -0700

    cache refactoring: Move various struct arg setup and marshaling to new file
    
    Move struct (boxed, union, gvalue, gclosure, variant, and pointer) argument
    cache setup and marshaling fragments into isolated file:
    pygi-struct-marshal.c.
    Remove redundant and dead code related to boxed and union marshaling.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=709700

 gi/Makefile.am            |    2 +
 gi/pygi-argument.c        |    1 +
 gi/pygi-array.c           |    3 +
 gi/pygi-cache.c           |   72 +------
 gi/pygi-cache.h           |    1 +
 gi/pygi-marshal-cleanup.c |   48 -----
 gi/pygi-marshal-cleanup.h |   16 --
 gi/pygi-marshal-from-py.c |  288 -------------------------
 gi/pygi-marshal-from-py.h |   33 ---
 gi/pygi-marshal-to-py.c   |  120 -----------
 gi/pygi-marshal-to-py.h   |   27 ---
 gi/pygi-object.c          |    2 +-
 gi/pygi-struct-marshal.c  |  516 +++++++++++++++++++++++++++++++++++++++++++++
 gi/pygi-struct-marshal.h  |   73 +++++++
 14 files changed, 607 insertions(+), 595 deletions(-)
---
diff --git a/gi/Makefile.am b/gi/Makefile.am
index 3d153f4..9c34c03 100644
--- a/gi/Makefile.am
+++ b/gi/Makefile.am
@@ -113,6 +113,8 @@ _gi_la_SOURCES = \
        pygi-error.h \
        pygi-object.c \
        pygi-object.h \
+       pygi-struct-marshal.c \
+       pygi-struct-marshal.h \
        pygi-hashtable.c \
        pygi-hashtable.h
 _gi_la_CFLAGS = \
diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c
index 4624e0f..f88ff62 100644
--- a/gi/pygi-argument.c
+++ b/gi/pygi-argument.c
@@ -35,6 +35,7 @@
 #include "pygi-marshal-to-py.h"
 #include "pygi-basictype.h"
 #include "pygi-object.h"
+#include "pygi-struct-marshal.h"
 
 
 static gboolean
diff --git a/gi/pygi-array.c b/gi/pygi-array.c
index 7b51584..22eea53 100644
--- a/gi/pygi-array.c
+++ b/gi/pygi-array.c
@@ -26,6 +26,9 @@
 #include "pygi-private.h"
 #include "pygi-marshal-cleanup.h"
 
+/* Needed for _pygi_marshal_cleanup_from_py_interface_struct_gvalue hack */
+#include "pygi-struct-marshal.h"
+
 /*
  * GArray to Python
  */
diff --git a/gi/pygi-cache.c b/gi/pygi-cache.c
index f26df8c..aab2534 100644
--- a/gi/pygi-cache.c
+++ b/gi/pygi-cache.c
@@ -2,6 +2,7 @@
  * vim: tabstop=4 shiftwidth=4 expandtab
  *
  * Copyright (C) 2011 John (J5) Palmieri <johnp redhat com>
+ * Copyright (C) 2013 Simon Feltman <sfeltman gnome org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -34,6 +35,7 @@
 #include "pygi-closure.h"
 #include "pygi-error.h"
 #include "pygi-object.h"
+#include "pygi-struct-marshal.h"
 
 
 /* _arg_info_default_value
@@ -251,48 +253,6 @@ _arg_cache_alloc (void)
 }
 
 static void
-_arg_cache_from_py_interface_union_setup (PyGIArgCache *arg_cache,
-                                          GITransfer transfer)
-{
-    arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_struct_cache_adapter;
-}
-
-static void
-_arg_cache_to_py_interface_union_setup (PyGIArgCache *arg_cache,
-                                        GITransfer transfer)
-{
-    arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_struct_cache_adapter;
-}
-
-static void
-_arg_cache_from_py_interface_struct_setup (PyGIArgCache *arg_cache,
-                                           GIInterfaceInfo *iface_info,
-                                           GITransfer transfer)
-{
-    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
-    iface_cache->is_foreign = g_struct_info_is_foreign ( (GIStructInfo*)iface_info);
-    arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_struct_cache_adapter;
-
-    if (iface_cache->g_type == G_TYPE_VALUE)
-        arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_struct_gvalue;
-    else if (iface_cache->is_foreign)
-        arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_struct_foreign;
-}
-
-static void
-_arg_cache_to_py_interface_struct_setup (PyGIArgCache *arg_cache,
-                                         GIInterfaceInfo *iface_info,
-                                         GITransfer transfer)
-{
-    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
-    iface_cache->is_foreign = g_struct_info_is_foreign ( (GIStructInfo*)iface_info);
-    arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_struct_cache_adapter;
-
-    if (iface_cache->is_foreign)
-        arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_interface_struct_foreign;
-}
-
-static void
 _arg_cache_from_py_interface_enum_setup (PyGIArgCache *arg_cache,
                                          GITransfer transfer)
 {
@@ -351,6 +311,14 @@ _arg_cache_new_for_interface (GIInterfaceInfo   *iface_info,
                                                    transfer,
                                                    direction,
                                                    iface_info);
+        case GI_INFO_TYPE_BOXED:
+        case GI_INFO_TYPE_STRUCT:
+        case GI_INFO_TYPE_UNION:
+            return pygi_arg_struct_new_from_info (type_info,
+                                                  arg_info,
+                                                  transfer,
+                                                  direction,
+                                                  iface_info);
         default:
             ;  /* pass through to old model of setup */
     }
@@ -364,26 +332,6 @@ _arg_cache_new_for_interface (GIInterfaceInfo   *iface_info,
         return NULL;
 
     switch (info_type) {
-        case GI_INFO_TYPE_UNION:
-            if (direction & PYGI_DIRECTION_FROM_PYTHON)
-               _arg_cache_from_py_interface_union_setup (arg_cache, transfer);
-
-            if (direction & PYGI_DIRECTION_TO_PYTHON)
-               _arg_cache_to_py_interface_union_setup (arg_cache, transfer);
-
-            break;
-        case GI_INFO_TYPE_BOXED:
-        case GI_INFO_TYPE_STRUCT:
-            if (direction & PYGI_DIRECTION_FROM_PYTHON)
-               _arg_cache_from_py_interface_struct_setup (arg_cache,
-                                                          iface_info,
-                                                          transfer);
-
-            if (direction & PYGI_DIRECTION_TO_PYTHON)
-               _arg_cache_to_py_interface_struct_setup (arg_cache,
-                                                        iface_info,
-                                                        transfer);
-            break;
         case GI_INFO_TYPE_ENUM:
             if (direction & PYGI_DIRECTION_FROM_PYTHON)
                _arg_cache_from_py_interface_enum_setup (arg_cache, transfer);
diff --git a/gi/pygi-cache.h b/gi/pygi-cache.h
index 3cbe2b6..28046f1 100644
--- a/gi/pygi-cache.h
+++ b/gi/pygi-cache.h
@@ -2,6 +2,7 @@
  * vim: tabstop=4 shiftwidth=4 expandtab
  *
  * Copyright (C) 2011 John (J5) Palmieri <johnp redhat com>
+ * Copyright (C) 2013 Simon Feltman <sfeltman gnome org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
diff --git a/gi/pygi-marshal-cleanup.c b/gi/pygi-marshal-cleanup.c
index 0bbfab6..3d82601 100644
--- a/gi/pygi-marshal-cleanup.c
+++ b/gi/pygi-marshal-cleanup.c
@@ -205,51 +205,3 @@ pygi_marshal_cleanup_args_to_py_parameter_fail (PyGIInvokeState   *state,
 {
     state->failed = TRUE;
 }
-
-void 
-_pygi_marshal_cleanup_from_py_interface_struct_gvalue (PyGIInvokeState *state,
-                                                       PyGIArgCache    *arg_cache,
-                                                       PyObject        *py_arg,
-                                                       gpointer         data,
-                                                       gboolean         was_processed)
-{
-    /* Note py_arg can be NULL for hash table which is a bug. */
-    if (was_processed && py_arg != NULL) {
-        GType py_object_type =
-            pyg_type_from_object_strict ( (PyObject *) py_arg->ob_type, FALSE);
-
-        /* When a GValue was not passed, it means the marshalers created a new
-         * one to pass in, clean this up.
-         */
-        if (py_object_type != G_TYPE_VALUE) {
-            g_value_unset ((GValue *) data);
-            g_slice_free (GValue, data);
-        }
-    }
-}
-
-void
-_pygi_marshal_cleanup_from_py_interface_struct_foreign (PyGIInvokeState *state,
-                                                        PyGIArgCache    *arg_cache,
-                                                        PyObject        *py_arg,
-                                                        gpointer         data,
-                                                        gboolean         was_processed)
-{
-    if (state->failed && was_processed)
-        pygi_struct_foreign_release (
-            ( (PyGIInterfaceCache *)arg_cache)->interface_info,
-            data);
-}
-
-void
-_pygi_marshal_cleanup_to_py_interface_struct_foreign (PyGIInvokeState *state,
-                                                      PyGIArgCache    *arg_cache,
-                                                      PyObject        *dummy,
-                                                      gpointer         data,
-                                                      gboolean         was_processed)
-{
-    if (!was_processed && arg_cache->transfer == GI_TRANSFER_EVERYTHING)
-        pygi_struct_foreign_release ( 
-            ( (PyGIInterfaceCache *)arg_cache)->interface_info,
-            data);
-}
diff --git a/gi/pygi-marshal-cleanup.h b/gi/pygi-marshal-cleanup.h
index 2463cab..e895f37 100644
--- a/gi/pygi-marshal-cleanup.h
+++ b/gi/pygi-marshal-cleanup.h
@@ -39,22 +39,6 @@ void pygi_marshal_cleanup_args_return_fail           (PyGIInvokeState   *state,
 void pygi_marshal_cleanup_args_to_py_parameter_fail  (PyGIInvokeState   *state,
                                                       PyGICallableCache *cache,
                                                       gssize failed_to_py_arg_index);
-
-void _pygi_marshal_cleanup_from_py_interface_struct_gvalue   (PyGIInvokeState *state,
-                                                              PyGIArgCache    *arg_cache,
-                                                              PyObject        *py_arg,
-                                                              gpointer         data,
-                                                              gboolean         was_processed);
-void _pygi_marshal_cleanup_from_py_interface_struct_foreign  (PyGIInvokeState *state,
-                                                              PyGIArgCache    *arg_cache,
-                                                              PyObject        *py_arg,
-                                                              gpointer         data,
-                                                              gboolean         was_processed);
-void _pygi_marshal_cleanup_to_py_interface_struct_foreign (PyGIInvokeState *state,
-                                                           PyGIArgCache    *arg_cache,
-                                                           PyObject        *dummy,
-                                                           gpointer         data,
-                                                           gboolean         was_processed);
 G_END_DECLS
 
 #endif /* __PYGI_MARSHAL_CLEANUP_H__ */
diff --git a/gi/pygi-marshal-from-py.c b/gi/pygi-marshal-from-py.c
index ba79859..259f9ea 100644
--- a/gi/pygi-marshal-from-py.c
+++ b/gi/pygi-marshal-from-py.c
@@ -87,59 +87,6 @@ gi_argument_from_c_long (GIArgument *arg_out,
     }
 }
 
-/*
- * _is_union_member - check to see if the py_arg is actually a member of the
- * expected C union
- */
-static gboolean
-_is_union_member (GIInterfaceInfo *interface_info, PyObject *py_arg) {
-    gint i;
-    gint n_fields;
-    GIUnionInfo *union_info;
-    GIInfoType info_type;
-    gboolean is_member = FALSE;
-
-    info_type = g_base_info_get_type (interface_info);
-
-    if (info_type != GI_INFO_TYPE_UNION)
-        return FALSE;
-
-    union_info = (GIUnionInfo *) interface_info;
-    n_fields = g_union_info_get_n_fields (union_info);
-
-    for (i = 0; i < n_fields; i++) {
-        GIFieldInfo *field_info;
-        GITypeInfo *field_type_info;
-
-        field_info = g_union_info_get_field (union_info, i);
-        field_type_info = g_field_info_get_type (field_info);
-
-        /* we can only check if the members are interfaces */
-        if (g_type_info_get_tag (field_type_info) == GI_TYPE_TAG_INTERFACE) {
-            GIInterfaceInfo *field_iface_info;
-            PyObject *py_type;
-
-            field_iface_info = g_type_info_get_interface (field_type_info);
-            py_type = _pygi_type_import_by_gi_info ((GIBaseInfo *) field_iface_info);
-
-            if (py_type != NULL && PyObject_IsInstance (py_arg, py_type)) {
-                is_member = TRUE;
-            }
-
-            Py_XDECREF (py_type);
-            g_base_info_unref ( ( GIBaseInfo *) field_iface_info);
-        }
-
-        g_base_info_unref ( ( GIBaseInfo *) field_type_info);
-        g_base_info_unref ( ( GIBaseInfo *) field_info);
-
-        if (is_member)
-            break;
-    }
-
-    return is_member;
-}
-
 gboolean
 _pygi_marshal_from_py_interface_enum (PyGIInvokeState   *state,
                                       PyGICallableCache *callable_cache,
@@ -257,238 +204,3 @@ err:
 
 }
 
-gboolean
-_pygi_marshal_from_py_interface_struct_cache_adapter (PyGIInvokeState   *state,
-                                                      PyGICallableCache *callable_cache,
-                                                      PyGIArgCache      *arg_cache,
-                                                      PyObject          *py_arg,
-                                                      GIArgument        *arg,
-                                                      gpointer          *cleanup_data)
-{
-    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
-
-    gboolean res =  _pygi_marshal_from_py_interface_struct (py_arg,
-                                                            arg,
-                                                            arg_cache->arg_name,
-                                                            iface_cache->interface_info,
-                                                            iface_cache->g_type,
-                                                            iface_cache->py_type,
-                                                            arg_cache->transfer,
-                                                            TRUE, /*copy_reference*/
-                                                            iface_cache->is_foreign,
-                                                            arg_cache->is_pointer);
-
-    /* Assume struct marshaling is always a pointer and assign cleanup_data
-     * here rather than passing it further down the chain.
-     */
-    *cleanup_data = arg->v_pointer;
-    return res;
-}
-
-gboolean
-_pygi_marshal_from_py_interface_boxed (PyGIInvokeState   *state,
-                                       PyGICallableCache *callable_cache,
-                                       PyGIArgCache      *arg_cache,
-                                       PyObject          *py_arg,
-                                       GIArgument        *arg,
-                                       gpointer          *cleanup_data)
-{
-    PyErr_Format (PyExc_NotImplementedError,
-                  "Marshalling for this type is not implemented yet");
-    return FALSE;
-}
-
-gboolean
-_pygi_marshal_from_py_interface_union (PyGIInvokeState   *state,
-                                       PyGICallableCache *callable_cache,
-                                       PyGIArgCache      *arg_cache,
-                                       PyObject          *py_arg,
-                                       GIArgument        *arg,
-                                       gpointer          *cleanup_data)
-{
-    PyErr_Format(PyExc_NotImplementedError,
-                 "Marshalling for this type is not implemented yet");
-    return FALSE;
-}
-
-
-/* _pygi_marshal_from_py_gvalue:
- * py_arg: (in):
- * arg: (out):
- * transfer:
- * copy_reference: TRUE if arg should use the pointer reference held by py_arg
- *                 when it is already holding a GValue vs. copying the value.
- */
-gboolean
-_pygi_marshal_from_py_gvalue (PyObject *py_arg,
-                              GIArgument *arg,
-                              GITransfer transfer,
-                              gboolean copy_reference) {
-    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;
-    }
-
-    /* if already a gvalue, use that, else marshal into gvalue */
-    if (object_type == G_TYPE_VALUE) {
-        GValue *source_value = pyg_boxed_get (py_arg, GValue);
-        if (copy_reference) {
-            value = source_value;
-        } else {
-            value = g_slice_new0 (GValue);
-            g_value_init (value, G_VALUE_TYPE (source_value));
-            g_value_copy (source_value, value);
-        }
-    } else {
-        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;
-}
-
-/* _pygi_marshal_from_py_gclosure:
- * py_arg: (in):
- * arg: (out):
- */
-gboolean
-_pygi_marshal_from_py_gclosure(PyObject *py_arg,
-                               GIArgument *arg)
-{
-    GClosure *closure;
-    GType object_gtype = pyg_type_from_object_strict (py_arg, FALSE);
-
-    if ( !(PyCallable_Check(py_arg) ||
-           g_type_is_a (object_gtype, G_TYPE_CLOSURE))) {
-        PyErr_Format (PyExc_TypeError, "Must be callable, not %s",
-                      py_arg->ob_type->tp_name);
-        return FALSE;
-    }
-
-    if (g_type_is_a (object_gtype, G_TYPE_CLOSURE))
-        closure = (GClosure *)pyg_boxed_get (py_arg, void);
-    else
-        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;
-}
-
-gboolean
-_pygi_marshal_from_py_interface_struct (PyObject *py_arg,
-                                        GIArgument *arg,
-                                        const gchar *arg_name,
-                                        GIBaseInfo *interface_info,
-                                        GType g_type,
-                                        PyObject *py_type,
-                                        GITransfer transfer,
-                                        gboolean copy_reference,
-                                        gboolean is_foreign,
-                                        gboolean is_pointer)
-{
-    gboolean is_union = FALSE;
-
-    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 (g_type_is_a (g_type, G_TYPE_CLOSURE)) {
-        return _pygi_marshal_from_py_gclosure (py_arg, arg);
-    } else if (g_type_is_a (g_type, G_TYPE_VALUE)) {
-        return _pygi_marshal_from_py_gvalue(py_arg,
-                                            arg,
-                                            transfer,
-                                            copy_reference);
-    } else if (is_foreign) {
-        PyObject *success;
-        success = pygi_struct_foreign_convert_to_g_argument (py_arg,
-                                                             interface_info,
-                                                             transfer,
-                                                             arg);
-
-        return (success == Py_None);
-    } else if (!PyObject_IsInstance (py_arg, py_type)) {
-        /* first check to see if this is a member of the expected union */
-        is_union = _is_union_member (interface_info, py_arg);
-        if (!is_union) {
-            goto type_error;
-        }
-    }
-
-    if (g_type_is_a (g_type, G_TYPE_BOXED)) {
-        /* Additionally use pyg_type_from_object to pull the stashed __gtype__
-         * attribute off of the input argument for type checking. This is needed
-         * to work around type discrepancies in cases with aliased (typedef) types.
-         * e.g. GtkAllocation, GdkRectangle.
-         * See: https://bugzilla.gnomethere are .org/show_bug.cgi?id=707140
-         */
-        if (is_union || pyg_boxed_check (py_arg, g_type) ||
-                g_type_is_a (pyg_type_from_object (py_arg), g_type)) {
-            arg->v_pointer = pyg_boxed_get (py_arg, void);
-            if (transfer == GI_TRANSFER_EVERYTHING) {
-                arg->v_pointer = g_boxed_copy (g_type, arg->v_pointer);
-            }
-        } else {
-            goto type_error;
-        }
-
-    } else if (g_type_is_a (g_type, G_TYPE_POINTER) ||
-               g_type_is_a (g_type, G_TYPE_VARIANT) ||
-               g_type  == G_TYPE_NONE) {
-        g_warn_if_fail (g_type_is_a (g_type, G_TYPE_VARIANT) || !is_pointer || transfer == 
GI_TRANSFER_NOTHING);
-
-        if (g_type_is_a (g_type, G_TYPE_VARIANT) &&
-                pyg_type_from_object (py_arg) != G_TYPE_VARIANT) {
-            PyErr_SetString (PyExc_TypeError, "expected GLib.Variant");
-            return FALSE;
-        }
-        arg->v_pointer = pyg_pointer_get (py_arg, void);
-        if (transfer == GI_TRANSFER_EVERYTHING) {
-            g_variant_ref ((GVariant *)arg->v_pointer);
-        }
-
-    } else {
-        PyErr_Format (PyExc_NotImplementedError,
-                      "structure type '%s' is not supported yet",
-                      g_type_name(g_type));
-        return FALSE;
-    }
-    return TRUE;
-
-type_error:
-    {
-        gchar *type_name = _pygi_g_base_info_get_fullname (interface_info);
-        PyObject *module = PyObject_GetAttrString(py_arg, "__module__");
-
-        PyErr_Format (PyExc_TypeError, "argument %s: Expected %s, but got %s%s%s",
-                      arg_name ? arg_name : "self",
-                      type_name,
-                      module ? PYGLIB_PyUnicode_AsString(module) : "",
-                      module ? "." : "",
-                      py_arg->ob_type->tp_name);
-        if (module)
-            Py_DECREF (module);
-        g_free (type_name);
-        return FALSE;
-    }
-}
diff --git a/gi/pygi-marshal-from-py.h b/gi/pygi-marshal-from-py.h
index 4b59601..2daa381 100644
--- a/gi/pygi-marshal-from-py.h
+++ b/gi/pygi-marshal-from-py.h
@@ -45,18 +45,6 @@ gboolean _pygi_marshal_from_py_interface_flags    (PyGIInvokeState   *state,
                                                    PyObject          *py_arg,
                                                    GIArgument        *arg,
                                                    gpointer          *cleanup_data);
-gboolean _pygi_marshal_from_py_interface_struct_cache_adapter   (PyGIInvokeState   *state,
-                                                                 PyGICallableCache *callable_cache,
-                                                                 PyGIArgCache      *arg_cache,
-                                                                 PyObject          *py_arg,
-                                                                 GIArgument        *arg,
-                                                                 gpointer          *cleanup_data);
-gboolean _pygi_marshal_from_py_interface_boxed    (PyGIInvokeState   *state,
-                                                   PyGICallableCache *callable_cache,
-                                                   PyGIArgCache      *arg_cache,
-                                                   PyObject          *py_arg,
-                                                   GIArgument        *arg,
-                                                   gpointer          *cleanup_data);
 gboolean _pygi_marshal_from_py_interface_union    (PyGIInvokeState   *state,
                                                    PyGICallableCache *callable_cache,
                                                    PyGIArgCache      *arg_cache,
@@ -64,27 +52,6 @@ gboolean _pygi_marshal_from_py_interface_union    (PyGIInvokeState   *state,
                                                    GIArgument        *arg,
                                                    gpointer          *cleanup_data);
 
-/* Simplified marshalers shared between vfunc/closure and direct function calls. */
-
-gboolean _pygi_marshal_from_py_gvalue (PyObject *py_arg, /*in*/
-                                       GIArgument *arg,  /*out*/
-                                       GITransfer transfer,
-                                       gboolean is_allocated);
-
-gboolean _pygi_marshal_from_py_gclosure(PyObject *py_arg, /*in*/
-                                        GIArgument *arg); /*out*/
-
-gboolean _pygi_marshal_from_py_interface_struct (PyObject *py_arg,
-                                                 GIArgument *arg,
-                                                 const gchar *arg_name,
-                                                 GIBaseInfo *interface_info,
-                                                 GType g_type,
-                                                 PyObject *py_type,
-                                                 GITransfer transfer,
-                                                 gboolean is_allocated,
-                                                 gboolean is_foreign,
-                                                 gboolean is_pointer);
-
 G_END_DECLS
 
 #endif /* __PYGI_MARSHAL_from_py_PY__ */
diff --git a/gi/pygi-marshal-to-py.c b/gi/pygi-marshal-to-py.c
index 536193c..8384a42 100644
--- a/gi/pygi-marshal-to-py.c
+++ b/gi/pygi-marshal-to-py.c
@@ -150,123 +150,3 @@ _pygi_marshal_to_py_interface_flags (PyGIInvokeState   *state,
     return py_obj;
 }
 
-PyObject *
-_pygi_marshal_to_py_interface_struct_cache_adapter (PyGIInvokeState   *state,
-                                                    PyGICallableCache *callable_cache,
-                                                    PyGIArgCache      *arg_cache,
-                                                    GIArgument        *arg)
-{
-    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
-
-    return _pygi_marshal_to_py_interface_struct (arg,
-                                                 iface_cache->interface_info,
-                                                 iface_cache->g_type,
-                                                 iface_cache->py_type,
-                                                 arg_cache->transfer,
-                                                 arg_cache->is_caller_allocates,
-                                                 iface_cache->is_foreign);
-}
-
-PyObject *
-_pygi_marshal_to_py_interface_interface (PyGIInvokeState   *state,
-                                         PyGICallableCache *callable_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_to_py_interface_boxed (PyGIInvokeState   *state,
-                                     PyGICallableCache *callable_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_to_py_interface_union  (PyGIInvokeState   *state,
-                                      PyGICallableCache *callable_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_to_py_interface_struct (GIArgument *arg,
-                                      GIInterfaceInfo *interface_info,
-                                      GType g_type,
-                                      PyObject *py_type,
-                                      GITransfer transfer,
-                                      gboolean is_allocated,
-                                      gboolean is_foreign)
-{
-    PyObject *py_obj = NULL;
-
-    if (arg->v_pointer == NULL) {
-        Py_RETURN_NONE;
-    }
-
-    if (g_type_is_a (g_type, G_TYPE_VALUE)) {
-        py_obj = pyg_value_as_pyobject (arg->v_pointer, FALSE);
-    } else if (is_foreign) {
-        py_obj = pygi_struct_foreign_convert_from_g_argument (interface_info,
-                                                              arg->v_pointer);
-    } else if (g_type_is_a (g_type, G_TYPE_BOXED)) {
-        if (py_type) {
-            py_obj = _pygi_boxed_new ((PyTypeObject *) py_type,
-                                      arg->v_pointer,
-                                      transfer == GI_TRANSFER_EVERYTHING || is_allocated,
-                                      is_allocated ?
-                                              g_struct_info_get_size(interface_info) : 0);
-        }
-    } else if (g_type_is_a (g_type, G_TYPE_POINTER)) {
-        if (py_type == NULL ||
-                !PyType_IsSubtype ((PyTypeObject *) py_type, &PyGIStruct_Type)) {
-            g_warn_if_fail (transfer == GI_TRANSFER_NOTHING);
-            py_obj = pyg_pointer_new (g_type, arg->v_pointer);
-        } else {
-            py_obj = _pygi_struct_new ( (PyTypeObject *) py_type,
-                                       arg->v_pointer,
-                                       transfer == GI_TRANSFER_EVERYTHING);
-        }
-    } else if (g_type_is_a (g_type, G_TYPE_VARIANT)) {
-        /* Note: sink the variant (add a ref) only if we are not transfered ownership.
-         * GLib.Variant overrides __del__ which will then call "g_variant_unref" for
-         * cleanup in either case. */
-        if (py_type) {
-            if (transfer == GI_TRANSFER_NOTHING) {
-                g_variant_ref_sink (arg->v_pointer);
-            }
-            py_obj = _pygi_struct_new ((PyTypeObject *) py_type,
-                                       arg->v_pointer,
-                                       FALSE);
-        }
-    } else if (g_type == G_TYPE_NONE) {
-        if (py_type) {
-            py_obj = _pygi_struct_new ((PyTypeObject *) py_type,
-                                       arg->v_pointer,
-                                       transfer == GI_TRANSFER_EVERYTHING);
-        }
-    } else {
-        PyErr_Format (PyExc_NotImplementedError,
-                      "structure type '%s' is not supported yet",
-                      g_type_name (g_type));
-    }
-
-    return py_obj;
-}
diff --git a/gi/pygi-marshal-to-py.h b/gi/pygi-marshal-to-py.h
index aa84503..ad80a3b 100644
--- a/gi/pygi-marshal-to-py.h
+++ b/gi/pygi-marshal-to-py.h
@@ -30,32 +30,5 @@ PyObject *_pygi_marshal_to_py_interface_flags  (PyGIInvokeState   *state,
                                                 PyGICallableCache *callable_cache,
                                                 PyGIArgCache      *arg_cache,
                                                 GIArgument        *arg);
-PyObject *_pygi_marshal_to_py_interface_struct_cache_adapter (PyGIInvokeState   *state,
-                                                              PyGICallableCache *callable_cache,
-                                                              PyGIArgCache      *arg_cache,
-                                                              GIArgument        *arg);
-PyObject *_pygi_marshal_to_py_interface_interface(PyGIInvokeState   *state,
-                                                  PyGICallableCache *callable_cache,
-                                                  PyGIArgCache      *arg_cache,
-                                                  GIArgument        *arg);
-PyObject *_pygi_marshal_to_py_interface_boxed  (PyGIInvokeState   *state,
-                                                PyGICallableCache *callable_cache,
-                                                PyGIArgCache      *arg_cache,
-                                                GIArgument        *arg);
-PyObject *_pygi_marshal_to_py_interface_union  (PyGIInvokeState   *state,
-                                                PyGICallableCache *callable_cache,
-                                                PyGIArgCache      *arg_cache,
-                                                GIArgument        *arg);
-
-/* Simplified marshalers shared between vfunc/closure and direct function calls. */
-PyObject *_pygi_marshal_to_py_interface_struct (GIArgument *arg,
-                                                GIInterfaceInfo *interface_info,
-                                                GType g_type,
-                                                PyObject *py_type,
-                                                GITransfer transfer,
-                                                gboolean is_allocated,
-                                                gboolean is_foreign);
-
-G_END_DECLS
 
 #endif /* __PYGI_MARSHAL_TO_PY_H__ */
diff --git a/gi/pygi-object.c b/gi/pygi-object.c
index 4ad58b1..9abfc6b 100644
--- a/gi/pygi-object.c
+++ b/gi/pygi-object.c
@@ -22,7 +22,7 @@
 #include <Python.h>
 #include <pyglib-python-compat.h>
 
-#include "pygi-arg-gobject.h"
+#include "pygi-object.h"
 #include "pygi-private.h"
 #include "pygparamspec.h"
 
diff --git a/gi/pygi-struct-marshal.c b/gi/pygi-struct-marshal.c
new file mode 100644
index 0000000..a30f03e
--- /dev/null
+++ b/gi/pygi-struct-marshal.c
@@ -0,0 +1,516 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2011 John (J5) Palmieri <johnp redhat com>
+ * Copyright (C) 2014 Simon Feltman <sfeltman gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <Python.h>
+#include <pyglib-python-compat.h>
+
+#include "pygi-struct-marshal.h"
+#include "pygi-private.h"
+
+/*
+ * _is_union_member - check to see if the py_arg is actually a member of the
+ * expected C union
+ */
+static gboolean
+_is_union_member (GIInterfaceInfo *interface_info, PyObject *py_arg) {
+    gint i;
+    gint n_fields;
+    GIUnionInfo *union_info;
+    GIInfoType info_type;
+    gboolean is_member = FALSE;
+
+    info_type = g_base_info_get_type (interface_info);
+
+    if (info_type != GI_INFO_TYPE_UNION)
+        return FALSE;
+
+    union_info = (GIUnionInfo *) interface_info;
+    n_fields = g_union_info_get_n_fields (union_info);
+
+    for (i = 0; i < n_fields; i++) {
+        GIFieldInfo *field_info;
+        GITypeInfo *field_type_info;
+
+        field_info = g_union_info_get_field (union_info, i);
+        field_type_info = g_field_info_get_type (field_info);
+
+        /* we can only check if the members are interfaces */
+        if (g_type_info_get_tag (field_type_info) == GI_TYPE_TAG_INTERFACE) {
+            GIInterfaceInfo *field_iface_info;
+            PyObject *py_type;
+
+            field_iface_info = g_type_info_get_interface (field_type_info);
+            py_type = _pygi_type_import_by_gi_info ((GIBaseInfo *) field_iface_info);
+
+            if (py_type != NULL && PyObject_IsInstance (py_arg, py_type)) {
+                is_member = TRUE;
+            }
+
+            Py_XDECREF (py_type);
+            g_base_info_unref ( ( GIBaseInfo *) field_iface_info);
+        }
+
+        g_base_info_unref ( ( GIBaseInfo *) field_type_info);
+        g_base_info_unref ( ( GIBaseInfo *) field_info);
+
+        if (is_member)
+            break;
+    }
+
+    return is_member;
+}
+
+
+/*
+ * GValue from Python
+ */
+
+/* _pygi_marshal_from_py_gvalue:
+ * py_arg: (in):
+ * arg: (out):
+ * transfer:
+ * copy_reference: TRUE if arg should use the pointer reference held by py_arg
+ *                 when it is already holding a GValue vs. copying the value.
+ */
+gboolean
+_pygi_marshal_from_py_gvalue (PyObject *py_arg,
+                              GIArgument *arg,
+                              GITransfer transfer,
+                              gboolean copy_reference) {
+    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;
+    }
+
+    /* if already a gvalue, use that, else marshal into gvalue */
+    if (object_type == G_TYPE_VALUE) {
+        GValue *source_value = pyg_boxed_get (py_arg, GValue);
+        if (copy_reference) {
+            value = source_value;
+        } else {
+            value = g_slice_new0 (GValue);
+            g_value_init (value, G_VALUE_TYPE (source_value));
+            g_value_copy (source_value, value);
+        }
+    } else {
+        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;
+}
+
+void
+_pygi_marshal_cleanup_from_py_interface_struct_gvalue (PyGIInvokeState *state,
+                                                       PyGIArgCache    *arg_cache,
+                                                       PyObject        *py_arg,
+                                                       gpointer         data,
+                                                       gboolean         was_processed)
+{
+    /* Note py_arg can be NULL for hash table which is a bug. */
+    if (was_processed && py_arg != NULL) {
+        GType py_object_type =
+            pyg_type_from_object_strict ( (PyObject *) py_arg->ob_type, FALSE);
+
+        /* When a GValue was not passed, it means the marshalers created a new
+         * one to pass in, clean this up.
+         */
+        if (py_object_type != G_TYPE_VALUE) {
+            g_value_unset ((GValue *) data);
+            g_slice_free (GValue, data);
+        }
+    }
+}
+
+/* _pygi_marshal_from_py_gclosure:
+ * py_arg: (in):
+ * arg: (out):
+ */
+gboolean
+_pygi_marshal_from_py_gclosure(PyObject *py_arg,
+                               GIArgument *arg)
+{
+    GClosure *closure;
+    GType object_gtype = pyg_type_from_object_strict (py_arg, FALSE);
+
+    if ( !(PyCallable_Check(py_arg) ||
+           g_type_is_a (object_gtype, G_TYPE_CLOSURE))) {
+        PyErr_Format (PyExc_TypeError, "Must be callable, not %s",
+                      py_arg->ob_type->tp_name);
+        return FALSE;
+    }
+
+    if (g_type_is_a (object_gtype, G_TYPE_CLOSURE))
+        closure = (GClosure *)pyg_boxed_get (py_arg, void);
+    else
+        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;
+}
+
+/* _pygi_marshal_from_py_interface_struct:
+ *
+ * Dispatcher to various sub marshalers
+ */
+gboolean
+_pygi_marshal_from_py_interface_struct (PyObject *py_arg,
+                                        GIArgument *arg,
+                                        const gchar *arg_name,
+                                        GIBaseInfo *interface_info,
+                                        GType g_type,
+                                        PyObject *py_type,
+                                        GITransfer transfer,
+                                        gboolean copy_reference,
+                                        gboolean is_foreign,
+                                        gboolean is_pointer)
+{
+    gboolean is_union = FALSE;
+
+    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 (g_type_is_a (g_type, G_TYPE_CLOSURE)) {
+        return _pygi_marshal_from_py_gclosure (py_arg, arg);
+    } else if (g_type_is_a (g_type, G_TYPE_VALUE)) {
+        return _pygi_marshal_from_py_gvalue(py_arg,
+                                            arg,
+                                            transfer,
+                                            copy_reference);
+    } else if (is_foreign) {
+        PyObject *success;
+        success = pygi_struct_foreign_convert_to_g_argument (py_arg,
+                                                             interface_info,
+                                                             transfer,
+                                                             arg);
+
+        return (success == Py_None);
+    } else if (!PyObject_IsInstance (py_arg, py_type)) {
+        /* first check to see if this is a member of the expected union */
+        is_union = _is_union_member (interface_info, py_arg);
+        if (!is_union) {
+            goto type_error;
+        }
+    }
+
+    if (g_type_is_a (g_type, G_TYPE_BOXED)) {
+        /* Additionally use pyg_type_from_object to pull the stashed __gtype__
+         * attribute off of the input argument for type checking. This is needed
+         * to work around type discrepancies in cases with aliased (typedef) types.
+         * e.g. GtkAllocation, GdkRectangle.
+         * See: https://bugzilla.gnomethere are .org/show_bug.cgi?id=707140
+         */
+        if (is_union || pyg_boxed_check (py_arg, g_type) ||
+                g_type_is_a (pyg_type_from_object (py_arg), g_type)) {
+            arg->v_pointer = pyg_boxed_get (py_arg, void);
+            if (transfer == GI_TRANSFER_EVERYTHING) {
+                arg->v_pointer = g_boxed_copy (g_type, arg->v_pointer);
+            }
+        } else {
+            goto type_error;
+        }
+
+    } else if (g_type_is_a (g_type, G_TYPE_POINTER) ||
+               g_type_is_a (g_type, G_TYPE_VARIANT) ||
+               g_type  == G_TYPE_NONE) {
+        g_warn_if_fail (g_type_is_a (g_type, G_TYPE_VARIANT) || !is_pointer || transfer == 
GI_TRANSFER_NOTHING);
+
+        if (g_type_is_a (g_type, G_TYPE_VARIANT) &&
+                pyg_type_from_object (py_arg) != G_TYPE_VARIANT) {
+            PyErr_SetString (PyExc_TypeError, "expected GLib.Variant");
+            return FALSE;
+        }
+        arg->v_pointer = pyg_pointer_get (py_arg, void);
+        if (transfer == GI_TRANSFER_EVERYTHING) {
+            g_variant_ref ((GVariant *)arg->v_pointer);
+        }
+
+    } else {
+        PyErr_Format (PyExc_NotImplementedError,
+                      "structure type '%s' is not supported yet",
+                      g_type_name(g_type));
+        return FALSE;
+    }
+    return TRUE;
+
+type_error:
+    {
+        gchar *type_name = _pygi_g_base_info_get_fullname (interface_info);
+        PyObject *module = PyObject_GetAttrString(py_arg, "__module__");
+
+        PyErr_Format (PyExc_TypeError, "argument %s: Expected %s, but got %s%s%s",
+                      arg_name ? arg_name : "self",
+                      type_name,
+                      module ? PYGLIB_PyUnicode_AsString(module) : "",
+                      module ? "." : "",
+                      py_arg->ob_type->tp_name);
+        if (module)
+            Py_DECREF (module);
+        g_free (type_name);
+        return FALSE;
+    }
+}
+
+static gboolean
+_pygi_marshal_from_py_interface_struct_cache_adapter (PyGIInvokeState   *state,
+                                                      PyGICallableCache *callable_cache,
+                                                      PyGIArgCache      *arg_cache,
+                                                      PyObject          *py_arg,
+                                                      GIArgument        *arg,
+                                                      gpointer          *cleanup_data)
+{
+    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
+
+    gboolean res =  _pygi_marshal_from_py_interface_struct (py_arg,
+                                                            arg,
+                                                            arg_cache->arg_name,
+                                                            iface_cache->interface_info,
+                                                            iface_cache->g_type,
+                                                            iface_cache->py_type,
+                                                            arg_cache->transfer,
+                                                            TRUE, /*copy_reference*/
+                                                            iface_cache->is_foreign,
+                                                            arg_cache->is_pointer);
+
+    /* Assume struct marshaling is always a pointer and assign cleanup_data
+     * here rather than passing it further down the chain.
+     */
+    *cleanup_data = arg->v_pointer;
+    return res;
+}
+
+static void
+_pygi_marshal_cleanup_from_py_interface_struct_foreign (PyGIInvokeState *state,
+                                                        PyGIArgCache    *arg_cache,
+                                                        PyObject        *py_arg,
+                                                        gpointer         data,
+                                                        gboolean         was_processed)
+{
+    if (state->failed && was_processed)
+        pygi_struct_foreign_release (
+            ( (PyGIInterfaceCache *)arg_cache)->interface_info,
+            data);
+}
+
+
+PyObject *
+_pygi_marshal_to_py_interface_struct (GIArgument *arg,
+                                      GIInterfaceInfo *interface_info,
+                                      GType g_type,
+                                      PyObject *py_type,
+                                      GITransfer transfer,
+                                      gboolean is_allocated,
+                                      gboolean is_foreign)
+{
+    PyObject *py_obj = NULL;
+
+    if (arg->v_pointer == NULL) {
+        Py_RETURN_NONE;
+    }
+
+    if (g_type_is_a (g_type, G_TYPE_VALUE)) {
+        py_obj = pyg_value_as_pyobject (arg->v_pointer, FALSE);
+    } else if (is_foreign) {
+        py_obj = pygi_struct_foreign_convert_from_g_argument (interface_info,
+                                                              arg->v_pointer);
+    } else if (g_type_is_a (g_type, G_TYPE_BOXED)) {
+        if (py_type) {
+            py_obj = _pygi_boxed_new ((PyTypeObject *) py_type,
+                                      arg->v_pointer,
+                                      transfer == GI_TRANSFER_EVERYTHING || is_allocated,
+                                      is_allocated ?
+                                              g_struct_info_get_size(interface_info) : 0);
+        }
+    } else if (g_type_is_a (g_type, G_TYPE_POINTER)) {
+        if (py_type == NULL ||
+                !PyType_IsSubtype ((PyTypeObject *) py_type, &PyGIStruct_Type)) {
+            g_warn_if_fail (transfer == GI_TRANSFER_NOTHING);
+            py_obj = pyg_pointer_new (g_type, arg->v_pointer);
+        } else {
+            py_obj = _pygi_struct_new ( (PyTypeObject *) py_type,
+                                       arg->v_pointer,
+                                       transfer == GI_TRANSFER_EVERYTHING);
+        }
+    } else if (g_type_is_a (g_type, G_TYPE_VARIANT)) {
+        /* Note: sink the variant (add a ref) only if we are not transfered ownership.
+         * GLib.Variant overrides __del__ which will then call "g_variant_unref" for
+         * cleanup in either case. */
+        if (py_type) {
+            if (transfer == GI_TRANSFER_NOTHING) {
+                g_variant_ref_sink (arg->v_pointer);
+            }
+            py_obj = _pygi_struct_new ((PyTypeObject *) py_type,
+                                       arg->v_pointer,
+                                       FALSE);
+        }
+    } else if (g_type == G_TYPE_NONE) {
+        if (py_type) {
+            py_obj = _pygi_struct_new ((PyTypeObject *) py_type,
+                                       arg->v_pointer,
+                                       transfer == GI_TRANSFER_EVERYTHING);
+        }
+    } else {
+        PyErr_Format (PyExc_NotImplementedError,
+                      "structure type '%s' is not supported yet",
+                      g_type_name (g_type));
+    }
+
+    return py_obj;
+}
+
+static PyObject *
+_pygi_marshal_to_py_interface_struct_cache_adapter (PyGIInvokeState   *state,
+                                                    PyGICallableCache *callable_cache,
+                                                    PyGIArgCache      *arg_cache,
+                                                    GIArgument        *arg)
+{
+    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
+
+    return _pygi_marshal_to_py_interface_struct (arg,
+                                                 iface_cache->interface_info,
+                                                 iface_cache->g_type,
+                                                 iface_cache->py_type,
+                                                 arg_cache->transfer,
+                                                 arg_cache->is_caller_allocates,
+                                                 iface_cache->is_foreign);
+}
+
+static void
+_pygi_marshal_cleanup_to_py_interface_struct_foreign (PyGIInvokeState *state,
+                                                      PyGIArgCache    *arg_cache,
+                                                      PyObject        *dummy,
+                                                      gpointer         data,
+                                                      gboolean         was_processed)
+{
+    if (!was_processed && arg_cache->transfer == GI_TRANSFER_EVERYTHING)
+        pygi_struct_foreign_release (
+            ( (PyGIInterfaceCache *)arg_cache)->interface_info,
+            data);
+}
+
+
+static void
+_arg_cache_from_py_interface_struct_setup (PyGIArgCache *arg_cache,
+                                           GIInterfaceInfo *iface_info,
+                                           GITransfer transfer)
+{
+    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
+    iface_cache->is_foreign = g_struct_info_is_foreign ( (GIStructInfo*)iface_info);
+    arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_struct_cache_adapter;
+
+    if (iface_cache->g_type == G_TYPE_VALUE)
+        arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_struct_gvalue;
+    else if (iface_cache->is_foreign)
+        arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_struct_foreign;
+}
+
+static void
+_arg_cache_to_py_interface_struct_setup (PyGIArgCache *arg_cache,
+                                         GIInterfaceInfo *iface_info,
+                                         GITransfer transfer)
+{
+    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
+    iface_cache->is_foreign = g_struct_info_is_foreign ( (GIStructInfo*)iface_info);
+    arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_struct_cache_adapter;
+
+    if (iface_cache->is_foreign)
+        arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_interface_struct_foreign;
+}
+
+static gboolean
+pygi_arg_struct_setup_from_info (PyGIArgCache    *arg_cache,
+                                 GITypeInfo      *type_info,
+                                 GIArgInfo       *arg_info,
+                                 GITransfer       transfer,
+                                 PyGIDirection    direction,
+                                 GIInterfaceInfo *iface_info)
+{
+    /* NOTE: usage of pygi_arg_interface_new_from_info already calls
+     * pygi_arg_interface_setup so no need to do it here.
+     */
+
+    if (direction & PYGI_DIRECTION_FROM_PYTHON) {
+        _arg_cache_from_py_interface_struct_setup (arg_cache,
+                                                   iface_info,
+                                                   transfer);
+    }
+
+    if (direction & PYGI_DIRECTION_TO_PYTHON) {
+        _arg_cache_to_py_interface_struct_setup (arg_cache,
+                                                 iface_info,
+                                                 transfer);
+    }
+
+    return TRUE;
+}
+
+PyGIArgCache *
+pygi_arg_struct_new_from_info (GITypeInfo      *type_info,
+                               GIArgInfo       *arg_info,
+                               GITransfer       transfer,
+                               PyGIDirection    direction,
+                               GIInterfaceInfo *iface_info)
+{
+    gboolean res = FALSE;
+    PyGIArgCache *cache = NULL;
+
+    cache = pygi_arg_interface_new_from_info (type_info,
+                                              arg_info,
+                                              transfer,
+                                              direction,
+                                              iface_info);
+    if (cache == NULL)
+        return NULL;
+
+    res = pygi_arg_struct_setup_from_info (cache,
+                                           type_info,
+                                           arg_info,
+                                           transfer,
+                                           direction,
+                                           iface_info);
+    if (res) {
+        return cache;
+    } else {
+        _pygi_arg_cache_free (cache);
+        return NULL;
+    }
+}
diff --git a/gi/pygi-struct-marshal.h b/gi/pygi-struct-marshal.h
new file mode 100644
index 0000000..66e3ecf
--- /dev/null
+++ b/gi/pygi-struct-marshal.h
@@ -0,0 +1,73 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2011 John (J5) Palmieri <johnp redhat com>
+ * Copyright (C) 2014 Simon Feltman <sfeltman gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __PYGI_STRUCT_MARSHAL_H__
+#define __PYGI_STRUCT_MARSHAL_H__
+
+#include <girepository.h>
+#include "pygi-cache.h"
+
+G_BEGIN_DECLS
+
+PyGIArgCache *pygi_arg_struct_new_from_info  (GITypeInfo      *type_info,
+                                              GIArgInfo       *arg_info,   /* may be null */
+                                              GITransfer       transfer,
+                                              PyGIDirection    direction,
+                                              GIInterfaceInfo *iface_info);
+
+
+gboolean _pygi_marshal_from_py_gvalue (PyObject *py_arg, /*in*/
+                                       GIArgument *arg,  /*out*/
+                                       GITransfer transfer,
+                                       gboolean is_allocated);
+
+
+gboolean _pygi_marshal_from_py_gclosure(PyObject *py_arg, /*in*/
+                                        GIArgument *arg); /*out*/
+
+gboolean _pygi_marshal_from_py_interface_struct (PyObject *py_arg,
+                                                 GIArgument *arg,
+                                                 const gchar *arg_name,
+                                                 GIBaseInfo *interface_info,
+                                                 GType g_type,
+                                                 PyObject *py_type,
+                                                 GITransfer transfer,
+                                                 gboolean is_allocated,
+                                                 gboolean is_foreign,
+                                                 gboolean is_pointer);
+
+PyObject *_pygi_marshal_to_py_interface_struct (GIArgument *arg,
+                                                GIInterfaceInfo *interface_info,
+                                                GType g_type,
+                                                PyObject *py_type,
+                                                GITransfer transfer,
+                                                gboolean is_allocated,
+                                                gboolean is_foreign);
+
+/* Needed for hack in pygi-arg-garray.c */
+void _pygi_marshal_cleanup_from_py_interface_struct_gvalue   (PyGIInvokeState *state,
+                                                              PyGIArgCache    *arg_cache,
+                                                              PyObject        *py_arg,
+                                                              gpointer         data,
+                                                              gboolean         was_processed);
+
+G_END_DECLS
+
+#endif /*__PYGI_STRUCT_MARSHAL_H__*/


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