diff options
Diffstat (limited to 'gi/pygi-enum-marshal.c')
-rw-r--r-- | gi/pygi-enum-marshal.c | 408 |
1 files changed, 408 insertions, 0 deletions
diff --git a/gi/pygi-enum-marshal.c b/gi/pygi-enum-marshal.c new file mode 100644 index 00000000..0a8e7e44 --- /dev/null +++ b/gi/pygi-enum-marshal.c @@ -0,0 +1,408 @@ +/* -*- 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-enum-marshal.h" +#include "pygi-private.h" + +#ifdef _WIN32 +#ifdef _MSC_VER +#include <math.h> + +#ifndef NAN +static const unsigned long __nan[2] = {0xffffffff, 0x7fffffff}; +#define NAN (*(const float *) __nan) +#endif + +#ifndef INFINITY +#define INFINITY HUGE_VAL +#endif + +#endif +#endif + +static gboolean +gi_argument_from_c_long (GIArgument *arg_out, + long c_long_in, + GITypeTag type_tag) +{ + switch (type_tag) { + case GI_TYPE_TAG_INT8: + arg_out->v_int8 = c_long_in; + return TRUE; + case GI_TYPE_TAG_UINT8: + arg_out->v_uint8 = c_long_in; + return TRUE; + case GI_TYPE_TAG_INT16: + arg_out->v_int16 = c_long_in; + return TRUE; + case GI_TYPE_TAG_UINT16: + arg_out->v_uint16 = c_long_in; + return TRUE; + case GI_TYPE_TAG_INT32: + arg_out->v_int32 = c_long_in; + return TRUE; + case GI_TYPE_TAG_UINT32: + arg_out->v_uint32 = c_long_in; + return TRUE; + case GI_TYPE_TAG_INT64: + arg_out->v_int64 = c_long_in; + return TRUE; + case GI_TYPE_TAG_UINT64: + arg_out->v_uint64 = c_long_in; + return TRUE; + default: + PyErr_Format (PyExc_TypeError, + "Unable to marshal C long %ld to %s", + c_long_in, + g_type_tag_to_string (type_tag)); + return FALSE; + } +} + +static gboolean +gi_argument_to_c_long (GIArgument *arg_in, + long *c_long_out, + GITypeTag type_tag) +{ + switch (type_tag) { + case GI_TYPE_TAG_INT8: + *c_long_out = arg_in->v_int8; + return TRUE; + case GI_TYPE_TAG_UINT8: + *c_long_out = arg_in->v_uint8; + return TRUE; + case GI_TYPE_TAG_INT16: + *c_long_out = arg_in->v_int16; + return TRUE; + case GI_TYPE_TAG_UINT16: + *c_long_out = arg_in->v_uint16; + return TRUE; + case GI_TYPE_TAG_INT32: + *c_long_out = arg_in->v_int32; + return TRUE; + case GI_TYPE_TAG_UINT32: + *c_long_out = arg_in->v_uint32; + return TRUE; + case GI_TYPE_TAG_INT64: + *c_long_out = arg_in->v_int64; + return TRUE; + case GI_TYPE_TAG_UINT64: + *c_long_out = arg_in->v_uint64; + return TRUE; + default: + PyErr_Format (PyExc_TypeError, + "Unable to marshal %s to C long", + g_type_tag_to_string (type_tag)); + return FALSE; + } +} + +static gboolean +_pygi_marshal_from_py_interface_enum (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + PyObject *py_arg, + GIArgument *arg, + gpointer *cleanup_data) +{ + PyObject *py_long; + long c_long; + gint is_instance; + PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; + GIBaseInfo *interface = NULL; + + is_instance = PyObject_IsInstance (py_arg, iface_cache->py_type); + + py_long = PYGLIB_PyNumber_Long (py_arg); + if (py_long == NULL) { + PyErr_Clear(); + goto err; + } + + c_long = PYGLIB_PyLong_AsLong (py_long); + Py_DECREF (py_long); + + /* Write c_long into arg */ + interface = g_type_info_get_interface (arg_cache->type_info); + assert(g_base_info_get_type (interface) == GI_INFO_TYPE_ENUM); + if (!gi_argument_from_c_long(arg, + c_long, + g_enum_info_get_storage_type ((GIEnumInfo *)interface))) { + g_assert_not_reached(); + g_base_info_unref (interface); + return FALSE; + } + + /* If this is not an instance of the Enum type that we want + * we need to check if the value is equivilant to one of the + * Enum's memebers */ + if (!is_instance) { + int i; + gboolean is_found = FALSE; + + for (i = 0; i < g_enum_info_get_n_values (iface_cache->interface_info); i++) { + GIValueInfo *value_info = + g_enum_info_get_value (iface_cache->interface_info, i); + glong enum_value = g_value_info_get_value (value_info); + g_base_info_unref ( (GIBaseInfo *)value_info); + if (c_long == enum_value) { + is_found = TRUE; + break; + } + } + + if (!is_found) + goto err; + } + + g_base_info_unref (interface); + return TRUE; + +err: + if (interface) + g_base_info_unref (interface); + PyErr_Format (PyExc_TypeError, "Expected a %s, but got %s", + iface_cache->type_name, py_arg->ob_type->tp_name); + return FALSE; +} + +static gboolean +_pygi_marshal_from_py_interface_flags (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + PyObject *py_arg, + GIArgument *arg, + gpointer *cleanup_data) +{ + PyObject *py_long; + long c_long; + gint is_instance; + PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; + GIBaseInfo *interface; + + is_instance = PyObject_IsInstance (py_arg, iface_cache->py_type); + + py_long = PYGLIB_PyNumber_Long (py_arg); + if (py_long == NULL) { + PyErr_Clear (); + goto err; + } + + c_long = PYGLIB_PyLong_AsLong (py_long); + Py_DECREF (py_long); + + /* only 0 or argument of type Flag is allowed */ + if (!is_instance && c_long != 0) + goto err; + + /* Write c_long into arg */ + interface = g_type_info_get_interface (arg_cache->type_info); + g_assert (g_base_info_get_type (interface) == GI_INFO_TYPE_FLAGS); + if (!gi_argument_from_c_long(arg, c_long, + g_enum_info_get_storage_type ((GIEnumInfo *)interface))) { + g_base_info_unref (interface); + return FALSE; + } + + g_base_info_unref (interface); + return TRUE; + +err: + PyErr_Format (PyExc_TypeError, "Expected a %s, but got %s", + iface_cache->type_name, py_arg->ob_type->tp_name); + return FALSE; + +} + +static PyObject * +_pygi_marshal_to_py_interface_enum (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + GIArgument *arg) +{ + PyObject *py_obj = NULL; + PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; + GIBaseInfo *interface; + long c_long; + + interface = g_type_info_get_interface (arg_cache->type_info); + g_assert (g_base_info_get_type (interface) == GI_INFO_TYPE_ENUM); + + if (!gi_argument_to_c_long(arg, &c_long, + g_enum_info_get_storage_type ((GIEnumInfo *)interface))) { + return NULL; + } + + if (iface_cache->g_type == G_TYPE_NONE) { + py_obj = PyObject_CallFunction (iface_cache->py_type, "l", c_long); + } else { + py_obj = pyg_enum_from_gtype (iface_cache->g_type, c_long); + } + g_base_info_unref (interface); + return py_obj; +} + +static PyObject * +_pygi_marshal_to_py_interface_flags (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + GIArgument *arg) +{ + PyObject *py_obj = NULL; + PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; + GIBaseInfo *interface; + long c_long; + + interface = g_type_info_get_interface (arg_cache->type_info); + g_assert (g_base_info_get_type (interface) == GI_INFO_TYPE_FLAGS); + + if (!gi_argument_to_c_long(arg, &c_long, + g_enum_info_get_storage_type ((GIEnumInfo *)interface))) { + g_base_info_unref (interface); + return NULL; + } + + g_base_info_unref (interface); + if (iface_cache->g_type == G_TYPE_NONE) { + /* An enum with a GType of None is an enum without GType */ + + PyObject *py_type = _pygi_type_import_by_gi_info (iface_cache->interface_info); + PyObject *py_args = NULL; + + if (!py_type) + return NULL; + + py_args = PyTuple_New (1); + if (PyTuple_SetItem (py_args, 0, PyLong_FromLong (c_long)) != 0) { + Py_DECREF (py_args); + Py_DECREF (py_type); + return NULL; + } + + py_obj = PyObject_CallFunction (py_type, "l", c_long); + + Py_DECREF (py_args); + Py_DECREF (py_type); + } else { + py_obj = pyg_flags_from_gtype (iface_cache->g_type, c_long); + } + + return py_obj; +} + +static gboolean +pygi_arg_enum_setup_from_info (PyGIArgCache *arg_cache, + GITypeInfo *type_info, + GIArgInfo *arg_info, + GITransfer transfer, + PyGIDirection direction) +{ + if (direction & PYGI_DIRECTION_FROM_PYTHON) + arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_enum; + + if (direction & PYGI_DIRECTION_TO_PYTHON) + arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_enum; + + return TRUE; +} + + +PyGIArgCache * +pygi_arg_enum_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_enum_setup_from_info (cache, + type_info, + arg_info, + transfer, + direction); + if (res) { + return cache; + } else { + _pygi_arg_cache_free (cache); + return NULL; + } +} + +static gboolean +pygi_arg_flags_setup_from_info (PyGIArgCache *arg_cache, + GITypeInfo *type_info, + GIArgInfo *arg_info, + GITransfer transfer, + PyGIDirection direction) +{ + if (direction & PYGI_DIRECTION_FROM_PYTHON) + arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_flags; + + if (direction & PYGI_DIRECTION_TO_PYTHON) + arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_flags; + + return TRUE; +} + + +PyGIArgCache * +pygi_arg_flags_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_flags_setup_from_info (cache, + type_info, + arg_info, + transfer, + direction); + if (res) { + return cache; + } else { + _pygi_arg_cache_free (cache); + return NULL; + } +} |