Commit 1d0f120d authored by Simon Feltman's avatar Simon Feltman

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
parent 4dcaa2b9
......@@ -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 = \
......
......@@ -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
......
......@@ -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
*/
......
......@@ -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
......@@ -250,48 +252,6 @@ _arg_cache_alloc (void)
return g_slice_new0 (PyGIArgCache);
}
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);
......
......@@ -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
......
......@@ -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);
}
......@@ -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__ */
......@@ -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;
}
}
......@@ -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__ */
......@@ -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;