[pypy-commit] cffi default: Support more generally struct-returning functions
arigo
noreply at buildbot.pypy.org
Thu Jun 28 22:13:44 CEST 2012
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r557:f0cdef5768b5
Date: 2012-06-28 22:13 +0200
http://bitbucket.org/cffi/cffi/changeset/f0cdef5768b5/
Log: Support more generally struct-returning functions (but not callbacks
yet).
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -22,6 +22,11 @@
# define USE__THREAD
#endif
+/* Define CAN_RETURN_STRUCTS if the C compiler supports returning structs */
+#if !defined(MS_WIN32)
+# define CAN_RETURN_STRUCTS
+#endif
+
/************************************************************/
/* base type flag: exactly one of the following: */
@@ -1420,6 +1425,9 @@
return PyObject_GenericSetAttr((PyObject *)cd, attr, value);
}
+static PyObject *
+convert_struct_to_owning_object(char *data, CTypeDescrObject *ct); /*forward*/
+
static cif_description_t *
fb_prepare_cif(PyObject *fargs, CTypeDescrObject *fresult); /* forward */
@@ -1542,6 +1550,9 @@
res = Py_None;
Py_INCREF(res);
}
+ else if (fresult->ct_flags & CT_STRUCT) {
+ res = convert_struct_to_owning_object(resultdata, fresult);
+ }
else {
res = convert_to_object(resultdata, fresult);
}
@@ -1765,6 +1776,26 @@
return &cdb->head;
}
+static PyObject *
+convert_struct_to_owning_object(char *data, CTypeDescrObject *ct)
+{
+ CDataObject *cd;
+ Py_ssize_t dataoffset = offsetof(CDataObject_own_nolength, alignment);
+ Py_ssize_t datasize = ct->ct_size;
+
+ if ((ct->ct_flags & (CT_STRUCT|CT_IS_OPAQUE)) != CT_STRUCT) {
+ PyErr_SetString(PyExc_TypeError,
+ "return type is not a struct or is opaque");
+ return NULL;
+ }
+ cd = allocate_owning_object(dataoffset, datasize, ct);
+ if (cd == NULL)
+ return NULL;
+
+ memcpy(cd->c_data, data, datasize);
+ return (PyObject *)cd;
+}
+
static PyObject *b_newp(PyObject *self, PyObject *args)
{
CTypeDescrObject *ct, *ctitem;
@@ -2754,11 +2785,14 @@
if (PyErr_Occurred())
return -1;
if (cif_descr != NULL) {
+#ifndef CAN_RETURN_STRUCTS
if (fb->rtype->type == FFI_TYPE_STRUCT) {
PyErr_SetString(PyExc_NotImplementedError,
- "functions returning structs are not supported");
+ "functions returning structs are not supported "
+ "on this platform");
return -1;
}
+#endif
/* exchange data size */
/* first, enough room for an array of 'nargs' pointers */
exchange_offset = nargs * sizeof(void*);
@@ -2956,9 +2990,9 @@
&ellipsis))
return NULL;
- if (fresult->ct_flags & (CT_STRUCT|CT_UNION)) {
+ if (fresult->ct_flags & CT_UNION) {
PyErr_SetString(PyExc_NotImplementedError,
- "functions returning a struct or a union");
+ "functions returning a union");
return NULL;
}
if ((fresult->ct_size < 0 && !(fresult->ct_flags & CT_VOID)) ||
@@ -3431,6 +3465,16 @@
return total;
}
+#ifdef CAN_RETURN_STRUCTS
+static struct _testfunc7_s _testfunc10(int n)
+{
+ struct _testfunc7_s result;
+ result.a1 = n;
+ result.a2 = n * n;
+ return result;
+}
+#endif
+
static PyObject *b__testfunc(PyObject *self, PyObject *args)
{
/* for testing only */
@@ -3449,6 +3493,9 @@
case 7: f = &_testfunc7; break;
case 8: f = stderr; break;
case 9: f = &_testfunc9; break;
+#ifdef CAN_RETURN_STRUCTS
+ case 10: f = &_testfunc10; break;
+#endif
default:
PyErr_SetNone(PyExc_ValueError);
return NULL;
@@ -3577,25 +3624,6 @@
return PyString_FromStringAndSize(&x, 1);
}
-static PyObject *_cffi_from_c_struct(char *data, CTypeDescrObject *ct)
-{
- CDataObject *cd;
- Py_ssize_t dataoffset = offsetof(CDataObject_own_nolength, alignment);
- Py_ssize_t datasize = ct->ct_size;
-
- if ((ct->ct_flags & (CT_STRUCT|CT_IS_OPAQUE)) != CT_STRUCT) {
- PyErr_SetString(PyExc_TypeError,
- "return type is not a struct or is opaque");
- return NULL;
- }
- cd = allocate_owning_object(dataoffset, datasize, ct);
- if (cd == NULL)
- return NULL;
-
- memcpy(cd->c_data, data, datasize);
- return (PyObject *)cd;
-}
-
static void *cffi_exports[] = {
_cffi_to_c_char_p,
_cffi_to_c_signed_char,
@@ -3620,7 +3648,7 @@
_cffi_from_c_char,
convert_to_object,
convert_from_object,
- _cffi_from_c_struct,
+ convert_struct_to_owning_object,
};
/************************************************************/
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -1140,18 +1140,31 @@
p.a1 = ['x', 'y']
assert str(p.a1) == 'xyo'
-def test_no_struct_return_in_func():
+def test_struct_return_in_func():
BFunc = new_function_type((), new_void_type())
BArray = new_array_type(new_pointer_type(BFunc), 5) # works
new_function_type((), BFunc) # works
new_function_type((), new_primitive_type("int"))
new_function_type((), new_pointer_type(BFunc))
- py.test.raises(NotImplementedError, new_function_type, (),
- new_struct_type("foo_s"))
- py.test.raises(NotImplementedError, new_function_type, (),
- new_union_type("foo_u"))
+ py.test.raises(NotImplementedError, new_function_type,
+ (), new_union_type("foo_u"))
py.test.raises(TypeError, new_function_type, (), BArray)
+ if sys.platform == 'win32':
+ py.test.skip("function returning struct")
+ BChar = new_primitive_type("char")
+ BShort = new_primitive_type("short")
+ BInt = new_primitive_type("int")
+ BStruct = new_struct_type("foo_s")
+ complete_struct_or_union(BStruct, [('a1', BChar, -1),
+ ('a2', BShort, -1)])
+ BFunc10 = new_function_type((BInt,), BStruct)
+ f = cast(BFunc10, _testfunc(10))
+ s = f(40)
+ assert repr(s) == "<cdata 'struct foo_s' owning 4 bytes>"
+ assert s.a1 == chr(40)
+ assert s.a2 == 40 * 40
+
def test_cast_with_functionptr():
BFunc = new_function_type((), new_void_type())
BFunc2 = new_function_type((), new_primitive_type("short"))
More information about the pypy-commit
mailing list