[pygobject] Unify Python object to GValue GI marshaling code



commit 9e47afe459df942d9ffc4f71b39f1443976293df
Author: Simon Feltman <sfeltman src gnome org>
Date:   Fri Feb 15 20:56:12 2013 -0800

    Unify Python object to GValue GI marshaling code
    
    Add pygi_marshal_from_py_g_value which can be used for direct gi method
    call args and vfunc out args. The new method also adds an "is_allocated"
    parameter that will be used to fix leaks in the future.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=693405

 gi/pygi-argument.c        |   43 ++++++--------------------
 gi/pygi-marshal-from-py.c |   74 ++++++++++++++++++++++++++++++--------------
 gi/pygi-marshal-from-py.h |    5 +++
 3 files changed, 65 insertions(+), 57 deletions(-)
---
diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c
index 6d0c0d4..81e2ee7 100644
--- a/gi/pygi-argument.c
+++ b/gi/pygi-argument.c
@@ -1239,41 +1239,18 @@ array_success:
 
                     /* 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);
+                        /* This will currently leak the GValue that is allocated and
+                         * stashed in arg.v_pointer. Out argument marshaling for caller
+                         * allocated GValues already pass in memory for the GValue.
+                         * Further re-factoring is needed to fix this leak.
+                         * See: https://bugzilla.gnome.org/show_bug.cgi?id=693405
+                         */
+                        pygi_marshal_from_py_gvalue (object,
+                                                     &arg,
+                                                     transfer,
+                                                     FALSE /*is_allocated*/);
 
-                        value = g_slice_new0 (GValue);
-
-                        /* 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;
 
diff --git a/gi/pygi-marshal-from-py.c b/gi/pygi-marshal-from-py.c
index 381d656..0f1284e 100644
--- a/gi/pygi-marshal-from-py.c
+++ b/gi/pygi-marshal-from-py.c
@@ -1652,30 +1652,9 @@ _pygi_marshal_from_py_interface_struct (PyGIInvokeState   *state,
         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;
-        }
-
-        /* if already a gvalue, use that, else marshal into gvalue */
-        if (object_type == G_TYPE_VALUE) {
-            value = (GValue *)( (PyGObject *)py_arg)->obj;
-        } 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;
+        return pygi_marshal_from_py_gvalue(py_arg, arg,
+                                           arg_cache->transfer,
+                                           arg_cache->is_caller_allocates);
     } else if (iface_cache->is_foreign) {
         PyObject *success;
         success = pygi_struct_foreign_convert_to_g_argument (py_arg,
@@ -1910,3 +1889,50 @@ pygi_marshal_from_py_gobject (PyObject *py_arg, /*in*/
     arg->v_pointer = gobj;
     return TRUE;
 }
+
+/* pygi_marshal_from_py_gvalue:
+ * py_arg: (in):
+ * arg: (out):
+ * transfer:
+ * is_allocated: TRUE if arg->v_pointer is an already allocated GValue
+ */
+gboolean
+pygi_marshal_from_py_gvalue (PyObject *py_arg,
+                             GIArgument *arg,
+                             GITransfer transfer,
+                             gboolean is_allocated) {
+    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 (is_allocated)
+        value = (GValue *)arg->v_pointer;
+    else
+        value = g_slice_new0 (GValue);
+
+    /* 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 (G_VALUE_TYPE (value) == G_TYPE_INVALID)
+            g_value_init (value, G_VALUE_TYPE (source_value));
+        g_value_copy (source_value, value);
+    } else {
+        if (G_VALUE_TYPE (value) == G_TYPE_INVALID)
+            g_value_init (value, object_type);
+
+        if (pyg_value_from_pyobject (value, py_arg) < 0) {
+            if (!is_allocated)
+                g_slice_free (GValue, value);
+            PyErr_SetString (PyExc_RuntimeError, "PyObject conversion to GValue failed");
+            return FALSE;
+        }
+    }
+
+    arg->v_pointer = value;
+    return TRUE;
+}
diff --git a/gi/pygi-marshal-from-py.h b/gi/pygi-marshal-from-py.h
index 06ba9a4..11a21c9 100644
--- a/gi/pygi-marshal-from-py.h
+++ b/gi/pygi-marshal-from-py.h
@@ -190,6 +190,11 @@ gboolean pygi_marshal_from_py_gobject (PyObject *py_arg, /*in*/
                                        GIArgument *arg,  /*out*/
                                        GITransfer transfer);
 
+gboolean pygi_marshal_from_py_gvalue (PyObject *py_arg, /*in*/
+                                      GIArgument *arg,  /*out*/
+                                      GITransfer transfer,
+                                      gboolean is_allocated);
+
 G_END_DECLS
 
 #endif /* __PYGI_MARSHAL_from_py_PY__ */


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