Commit 4697a379 authored by Simon Feltman's avatar Simon Feltman

cache refactoring: Move GList/GSList arg setup and marshaling into new file

Move GList and GSList argument caching and marshaling fragments into an
isolated file: pygi-list.c.

https://bugzilla.gnome.org/show_bug.cgi?id=709700
parent c48ddacf
......@@ -105,6 +105,8 @@ _gi_la_SOURCES = \
pygi-marshal-cleanup.h \
pygi-basictype.c \
pygi-basictype.h \
pygi-list.c \
pygi-list.h \
pygi-hashtable.c \
pygi-hashtable.h
_gi_la_CFLAGS = \
......
......@@ -29,6 +29,7 @@
#include "pygi-type.h"
#include "pygi-hashtable.h"
#include "pygi-basictype.h"
#include "pygi-list.h"
PyGIArgCache * _arg_cache_new_for_interface (GIInterfaceInfo *iface_info,
......@@ -459,38 +460,6 @@ _arg_cache_to_py_array_setup (PyGIArgCache *arg_cache,
return TRUE;
}
static void
_arg_cache_from_py_glist_setup (PyGIArgCache *arg_cache,
GITransfer transfer)
{
arg_cache->from_py_marshaller = _pygi_marshal_from_py_glist;
arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_glist;
}
static void
_arg_cache_to_py_glist_setup (PyGIArgCache *arg_cache,
GITransfer transfer)
{
arg_cache->to_py_marshaller = _pygi_marshal_to_py_glist;
arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_glist;
}
static void
_arg_cache_from_py_gslist_setup (PyGIArgCache *arg_cache,
GITransfer transfer)
{
arg_cache->from_py_marshaller = _pygi_marshal_from_py_gslist;
arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_glist;
}
static void
_arg_cache_to_py_gslist_setup (PyGIArgCache *arg_cache,
GITransfer transfer)
{
arg_cache->to_py_marshaller = _pygi_marshal_to_py_gslist;
arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_glist;
}
static void
_arg_cache_from_py_gerror_setup (PyGIArgCache *arg_cache)
{
......@@ -825,21 +794,12 @@ _arg_cache_new (GITypeInfo *type_info,
}
case GI_TYPE_TAG_GLIST:
{
PyGISequenceCache *seq_cache =
pygi_arg_sequence_new (type_info,
arg_info,
transfer,
direction);
arg_cache = (PyGIArgCache *)seq_cache;
arg_cache = pygi_arg_glist_new_from_info (type_info,
arg_info,
transfer,
direction);
if (arg_cache == NULL)
break;
if (direction & PYGI_DIRECTION_FROM_PYTHON)
_arg_cache_from_py_glist_setup (arg_cache, transfer);
if (direction & PYGI_DIRECTION_TO_PYTHON)
_arg_cache_to_py_glist_setup (arg_cache, transfer);
return NULL;
arg_cache->py_arg_index = py_arg_index;
arg_cache->c_arg_index = c_arg_index;
......@@ -847,21 +807,12 @@ _arg_cache_new (GITypeInfo *type_info,
}
case GI_TYPE_TAG_GSLIST:
{
PyGISequenceCache *seq_cache =
pygi_arg_sequence_new (type_info,
arg_info,
transfer,
direction);
arg_cache = (PyGIArgCache *)seq_cache;
arg_cache = pygi_arg_gslist_new_from_info (type_info,
arg_info,
transfer,
direction);
if (arg_cache == NULL)
break;
if (direction & PYGI_DIRECTION_FROM_PYTHON)
_arg_cache_from_py_gslist_setup (arg_cache, transfer);
if (direction & PYGI_DIRECTION_TO_PYTHON)
_arg_cache_to_py_gslist_setup (arg_cache, transfer);
return NULL;
arg_cache->py_arg_index = py_arg_index;
arg_cache->c_arg_index = c_arg_index;
......
/* -*- 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 "pygi-list.h"
#include "pygi-argument.h"
#include "pygi-private.h"
typedef PyGISequenceCache PyGIArgGList;
/*
* GList and GSList from Python
*/
static gboolean
_pygi_marshal_from_py_glist (PyGIInvokeState *state,
PyGICallableCache *callable_cache,
PyGIArgCache *arg_cache,
PyObject *py_arg,
GIArgument *arg,
gpointer *cleanup_data)
{
PyGIMarshalFromPyFunc from_py_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;
from_py_marshaller = sequence_cache->item_cache->from_py_marshaller;
for (i = 0; i < length; i++) {
GIArgument item = {0};
gpointer item_cleanup_data = NULL;
PyObject *py_item = PySequence_GetItem (py_arg, i);
if (py_item == NULL)
goto err;
if (!from_py_marshaller ( state,
callable_cache,
sequence_cache->item_cache,
py_item,
&item,
&item_cleanup_data))
goto err;
Py_DECREF (py_item);
list_ = g_list_prepend (list_, _pygi_arg_to_hash_pointer (&item, sequence_cache->item_cache->type_tag));
continue;
err:
/* FIXME: clean up list
if (sequence_cache->item_cache->from_py_cleanup != NULL) {
PyGIMarshalCleanupFunc cleanup = sequence_cache->item_cache->from_py_cleanup;
}
*/
Py_DECREF (py_item);
g_list_free (list_);
_PyGI_ERROR_PREFIX ("Item %i: ", i);
return FALSE;
}
arg->v_pointer = g_list_reverse (list_);
if (arg_cache->transfer == GI_TRANSFER_NOTHING) {
/* Free everything in cleanup. */
*cleanup_data = arg->v_pointer;
} else if (arg_cache->transfer == GI_TRANSFER_CONTAINER) {
/* Make a shallow copy so we can free the elements later in cleanup
* because it is possible invoke will free the list before our cleanup. */
*cleanup_data = g_list_copy (arg->v_pointer);
} else { /* GI_TRANSFER_EVERYTHING */
/* No cleanup, everything is given to the callee. */
*cleanup_data = NULL;
}
return TRUE;
}
static gboolean
_pygi_marshal_from_py_gslist (PyGIInvokeState *state,
PyGICallableCache *callable_cache,
PyGIArgCache *arg_cache,
PyObject *py_arg,
GIArgument *arg,
gpointer *cleanup_data)
{
PyGIMarshalFromPyFunc from_py_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;
from_py_marshaller = sequence_cache->item_cache->from_py_marshaller;
for (i = 0; i < length; i++) {
GIArgument item = {0};
gpointer item_cleanup_data = NULL;
PyObject *py_item = PySequence_GetItem (py_arg, i);
if (py_item == NULL)
goto err;
if (!from_py_marshaller ( state,
callable_cache,
sequence_cache->item_cache,
py_item,
&item,
&item_cleanup_data))
goto err;
Py_DECREF (py_item);
list_ = g_slist_prepend (list_, _pygi_arg_to_hash_pointer (&item, sequence_cache->item_cache->type_tag));
continue;
err:
/* FIXME: Clean up list
if (sequence_cache->item_cache->from_py_cleanup != NULL) {
PyGIMarshalCleanupFunc cleanup = sequence_cache->item_cache->from_py_cleanup;
}
*/
Py_DECREF (py_item);
g_slist_free (list_);
_PyGI_ERROR_PREFIX ("Item %i: ", i);
return FALSE;
}
arg->v_pointer = g_slist_reverse (list_);
if (arg_cache->transfer == GI_TRANSFER_NOTHING) {
/* Free everything in cleanup. */
*cleanup_data = arg->v_pointer;
} else if (arg_cache->transfer == GI_TRANSFER_CONTAINER) {
/* Make a shallow copy so we can free the elements later in cleanup
* because it is possible invoke will free the list before our cleanup. */
*cleanup_data = g_slist_copy (arg->v_pointer);
} else { /* GI_TRANSFER_EVERYTHING */
/* No cleanup, everything is given to the callee. */
*cleanup_data = NULL;
}
return TRUE;
}
static void
_pygi_marshal_cleanup_from_py_glist (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
PyObject *py_arg,
gpointer data,
gboolean was_processed)
{
if (was_processed) {
GSList *list_;
PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
list_ = (GSList *)data;
/* clean up items first */
if (sequence_cache->item_cache->from_py_cleanup != NULL) {
PyGIMarshalCleanupFunc cleanup_func =
sequence_cache->item_cache->from_py_cleanup;
GSList *node = list_;
gsize i = 0;
while (node != NULL) {
PyObject *py_item = PySequence_GetItem (py_arg, i);
cleanup_func (state,
sequence_cache->item_cache,
py_item,
node->data,
TRUE);
Py_XDECREF (py_item);
node = node->next;
i++;
}
}
if (arg_cache->type_tag == GI_TYPE_TAG_GLIST) {
g_list_free ( (GList *)list_);
} else if (arg_cache->type_tag == GI_TYPE_TAG_GSLIST) {
g_slist_free (list_);
} else {
g_assert_not_reached();
}
}
}
/*
* GList and GSList to Python
*/
static PyObject *
_pygi_marshal_to_py_glist (PyGIInvokeState *state,
PyGICallableCache *callable_cache,
PyGIArgCache *arg_cache,
GIArgument *arg)
{
GList *list_;
gsize length;
gsize i;
PyGIMarshalToPyFunc item_to_py_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_to_py_marshaller = item_arg_cache->to_py_marshaller;
for (i = 0; list_ != NULL; list_ = g_list_next (list_), i++) {
GIArgument item_arg;
PyObject *py_item;
item_arg.v_pointer = list_->data;
_pygi_hash_pointer_to_arg (&item_arg, item_arg_cache->type_tag);
py_item = item_to_py_marshaller (state,
callable_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;
}
static PyObject *
_pygi_marshal_to_py_gslist (PyGIInvokeState *state,
PyGICallableCache *callable_cache,
PyGIArgCache *arg_cache,
GIArgument *arg)
{
GSList *list_;
gsize length;
gsize i;
PyGIMarshalToPyFunc item_to_py_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_to_py_marshaller = item_arg_cache->to_py_marshaller;
for (i = 0; list_ != NULL; list_ = g_slist_next (list_), i++) {
GIArgument item_arg;
PyObject *py_item;
item_arg.v_pointer = list_->data;
_pygi_hash_pointer_to_arg (&item_arg, item_arg_cache->type_tag);
py_item = item_to_py_marshaller (state,
callable_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;
}
static void
_pygi_marshal_cleanup_to_py_glist (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
PyObject *dummy,
gpointer data,
gboolean was_processed)
{
PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
if (arg_cache->transfer == GI_TRANSFER_EVERYTHING ||
arg_cache->transfer == GI_TRANSFER_CONTAINER) {
GSList *list_ = (GSList *)data;
if (sequence_cache->item_cache->to_py_cleanup != NULL) {
PyGIMarshalCleanupFunc cleanup_func =
sequence_cache->item_cache->to_py_cleanup;
GSList *node = list_;
while (node != NULL) {
cleanup_func (state,
sequence_cache->item_cache,
NULL,
node->data,
was_processed);
node = node->next;
}
}
if (arg_cache->type_tag == GI_TYPE_TAG_GLIST) {
g_list_free ( (GList *)list_);
} else if (arg_cache->type_tag == GI_TYPE_TAG_GSLIST) {
g_slist_free (list_);
} else {
g_assert_not_reached();
}
}
}
static void
_arg_cache_from_py_glist_setup (PyGIArgCache *arg_cache,
GITransfer transfer)
{
arg_cache->from_py_marshaller = _pygi_marshal_from_py_glist;
arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_glist;
}
static void
_arg_cache_to_py_glist_setup (PyGIArgCache *arg_cache,
GITransfer transfer)
{
arg_cache->to_py_marshaller = _pygi_marshal_to_py_glist;
arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_glist;
}
static void
_arg_cache_from_py_gslist_setup (PyGIArgCache *arg_cache,
GITransfer transfer)
{
arg_cache->from_py_marshaller = _pygi_marshal_from_py_gslist;
arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_glist;
}
static void
_arg_cache_to_py_gslist_setup (PyGIArgCache *arg_cache,
GITransfer transfer)
{
arg_cache->to_py_marshaller = _pygi_marshal_to_py_gslist;
arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_glist;
}
/*
* GList/GSList Interface
*/
static gboolean
pygi_arg_glist_setup_from_info (PyGIArgCache *arg_cache,
GITypeInfo *type_info,
GIArgInfo *arg_info,
GITransfer transfer,
PyGIDirection direction)
{
GITypeTag type_tag = g_type_info_get_tag (type_info);
if (!pygi_arg_sequence_setup ((PyGISequenceCache *)arg_cache, type_info, arg_info, transfer, direction))
return FALSE;
switch (type_tag) {
case GI_TYPE_TAG_GLIST:
{
if (direction & PYGI_DIRECTION_FROM_PYTHON)
_arg_cache_from_py_glist_setup (arg_cache, transfer);
if (direction & PYGI_DIRECTION_TO_PYTHON)
_arg_cache_to_py_glist_setup (arg_cache, transfer);
break;
}
case GI_TYPE_TAG_GSLIST:
{
if (direction & PYGI_DIRECTION_FROM_PYTHON)
_arg_cache_from_py_gslist_setup (arg_cache, transfer);
if (direction & PYGI_DIRECTION_TO_PYTHON)
_arg_cache_to_py_gslist_setup (arg_cache, transfer);
break;
}
default:
g_assert_not_reached ();
}
return TRUE;
}
PyGIArgCache *
pygi_arg_glist_new_from_info (GITypeInfo *type_info,
GIArgInfo *arg_info,
GITransfer transfer,
PyGIDirection direction)
{
gboolean res = FALSE;
PyGIArgCache *arg_cache = (PyGIArgCache *) g_slice_new0 (PyGIArgGList);
if (arg_cache == NULL)
return NULL;
res = pygi_arg_glist_setup_from_info (arg_cache,
type_info,
arg_info,
transfer,
direction);
if (res) {
return arg_cache;
} else {
_pygi_arg_cache_free (arg_cache);
return NULL;
}
}
/* -*- Mode: C; c-basic-offset: 4 -*-
* vim: tabstop=4 shiftwidth=4 expandtab
*
* Copyright (C) 2014 Simon Feltman <sfeltman@gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __PYGI_LIST_H__
#define __PYGI_LIST_H__
#include <girepository.h>
#include "pygi-cache.h"
G_BEGIN_DECLS
PyGIArgCache *pygi_arg_glist_new_from_info (GITypeInfo *type_info,
GIArgInfo *arg_info, /* may be null */
GITransfer transfer,
PyGIDirection direction);
/* Internally dispatches GList and GSList */
#define pygi_arg_gslist_new_from_info pygi_arg_glist_new_from_info
G_END_DECLS
#endif /*__PYGI_LIST_H__*/
......@@ -444,83 +444,3 @@ _pygi_marshal_cleanup_to_py_array (PyGIInvokeState *state,
g_ptr_array_free (ptr_array_, TRUE);
}
}
void
_pygi_marshal_cleanup_from_py_glist (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
PyObject *py_arg,
gpointer data,
gboolean was_processed)
{
if (was_processed) {
GSList *list_;
PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
list_ = (GSList *)data;