Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r556:0ed9b03dd40d Date: 2012-06-28 21:38 +0200 http://bitbucket.org/cffi/cffi/changeset/0ed9b03dd40d/
Log: Support the baseline case of functions returning structs. diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -1749,10 +1749,26 @@ /************************************************************/ +static CDataObject *allocate_owning_object(Py_ssize_t dataoffset, + Py_ssize_t datasize, + CTypeDescrObject *ct) +{ + CDataObject_own_base *cdb; + cdb = (CDataObject_own_base *)PyObject_Malloc(dataoffset + datasize); + if (PyObject_Init((PyObject *)cdb, &CDataOwning_Type) == NULL) + return NULL; + + Py_INCREF(ct); + cdb->head.c_type = ct; + cdb->head.c_data = ((char *)cdb) + dataoffset; + cdb->weakreflist = NULL; + return &cdb->head; +} + static PyObject *b_newp(PyObject *self, PyObject *args) { CTypeDescrObject *ct, *ctitem; - CDataObject_own_base *cdb; + CDataObject *cd; PyObject *init = Py_None; Py_ssize_t dataoffset, datasize, explicitlength; if (!PyArg_ParseTuple(args, "O!|O:newp", &CTypeDescr_Type, &ct, &init)) @@ -1809,26 +1825,21 @@ return NULL; } - cdb = (CDataObject_own_base *)PyObject_Malloc(dataoffset + datasize); - if (PyObject_Init((PyObject *)cdb, &CDataOwning_Type) == NULL) + cd = allocate_owning_object(dataoffset, datasize, ct); + if (cd == NULL) return NULL; - - Py_INCREF(ct); - cdb->head.c_type = ct; - cdb->head.c_data = ((char *)cdb) + dataoffset; - cdb->weakreflist = NULL; if (explicitlength >= 0) - ((CDataObject_own_length*)cdb)->length = explicitlength; - - memset(cdb->head.c_data, 0, datasize); + ((CDataObject_own_length*)cd)->length = explicitlength; + + memset(cd->c_data, 0, datasize); if (init != Py_None) { - if (convert_from_object(cdb->head.c_data, + if (convert_from_object(cd->c_data, (ct->ct_flags & CT_POINTER) ? ct->ct_itemdescr : ct, init) < 0) { - Py_DECREF(cdb); + Py_DECREF(cd); return NULL; } } - return (PyObject *)cdb; + return (PyObject *)cd; } static CDataObject *_new_casted_primitive(CTypeDescrObject *ct) @@ -3566,6 +3577,25 @@ 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, @@ -3590,6 +3620,7 @@ _cffi_from_c_char, convert_to_object, convert_from_object, + _cffi_from_c_struct, }; /************************************************************/ diff --git a/cffi/verifier.py b/cffi/verifier.py --- a/cffi/verifier.py +++ b/cffi/verifier.py @@ -184,6 +184,9 @@ elif isinstance(tp, model.ArrayType): return '_cffi_from_c_deref((char *)%s, _cffi_type(%d))' % ( var, self.gettypenum(tp)) + elif isinstance(tp, model.StructType): + return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % ( + var, self.gettypenum(tp)) else: raise NotImplementedError(tp) @@ -614,7 +617,9 @@ ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[16]) #define _cffi_to_c \ ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[17]) -#define _CFFI_NUM_EXPORTS 18 +#define _cffi_from_c_struct \ + ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[18]) +#define _CFFI_NUM_EXPORTS 19 #if SIZEOF_LONG < SIZEOF_LONG_LONG # define _cffi_to_c_long_long PyLong_AsLongLong diff --git a/testing/test_verify.py b/testing/test_verify.py --- a/testing/test_verify.py +++ b/testing/test_verify.py @@ -576,3 +576,27 @@ """) msg = 'cannot pass as a argument a struct that was completed with verify()' assert msg in str(e.value) + +def test_func_returns_struct(): + # only supported via verify(), when GCC is the compiler; and only for + # regular functions. + ffi = FFI() + ffi.cdef(""" + struct foo_s { int aa, bb; }; + struct foo_s foo(int a, int b); + """) + lib = ffi.verify(""" + struct foo_s { int aa, bb; }; + struct foo_s foo(int a, int b) { + struct foo_s r; + r.aa = a*a; + r.bb = b*b; + return r; + } + """) + s = lib.foo(6, 7) + # It's the only way to have a 'struct foo_s' that owns its memory. + # With ffi.new() we always get a 'struct foo_s *' that owns the memory. + assert repr(s) == "<cdata 'struct foo_s' owning 8 bytes>" + assert s.aa == 36 + assert s.bb == 49 _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit