Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r3151:abb60e05d3bf Date: 2018-08-30 11:36 +0200 http://bitbucket.org/cffi/cffi/changeset/abb60e05d3bf/
Log: Issue #379 Accept ``ffi.new("int[4]", p)`` if p is itself another cdata ``int[4]``. diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -1228,17 +1228,17 @@ return (cffi_char32_t)-1; } -static int _convert_error(PyObject *init, const char *ct_name, +static int _convert_error(PyObject *init, CTypeDescrObject *ct, const char *expected) { if (CData_Check(init)) { - const char *ct_name_2 = ((CDataObject *)init)->c_type->ct_name; - if (strcmp(ct_name, ct_name_2) != 0) + CTypeDescrObject *ct2 = ((CDataObject *)init)->c_type; + if (strcmp(ct->ct_name, ct2->ct_name) != 0) PyErr_Format(PyExc_TypeError, "initializer for ctype '%s' must be a %s, " "not cdata '%s'", - ct_name, expected, ct_name_2); - else { + ct->ct_name, expected, ct2->ct_name); + else if (ct != ct2) { /* in case we'd give the error message "initializer for ctype 'A' must be a pointer to same type, not cdata 'B'", but with A=B, then give instead a different error @@ -1247,14 +1247,21 @@ "initializer for ctype '%s' appears indeed to be '%s'," " but the types are different (check that you are not" " e.g. mixing up different ffi instances)", - ct_name, ct_name_2); + ct->ct_name, ct2->ct_name); + } + else + { + PyErr_Format(PyExc_SystemError, + "initializer for ctype '%s' is correct, but we get " + "an internal mismatch--please report a bug", + ct->ct_name); } } else PyErr_Format(PyExc_TypeError, "initializer for ctype '%s' must be a %s, " "not %.200s", - ct_name, expected, Py_TYPE(init)->tp_name); + ct->ct_name, expected, Py_TYPE(init)->tp_name); return -1; } @@ -1368,6 +1375,15 @@ return 0; } +static Py_ssize_t +get_array_length(CDataObject *cd) +{ + if (cd->c_type->ct_length < 0) + return ((CDataObject_own_length *)cd)->length; + else + return cd->c_type->ct_length; +} + static int convert_array_from_object(char *data, CTypeDescrObject *ct, PyObject *init) { @@ -1453,13 +1469,24 @@ } cannot_convert: - return _convert_error(init, ct->ct_name, expected); + if (CData_Check(init)) + { + CDataObject *cd = (CDataObject *)init; + if (cd->c_type == ct) + { + Py_ssize_t n = get_array_length(cd); + memmove(data, cd->c_data, n * ctitem->ct_size); + return 0; + } + } + return _convert_error(init, ct, expected); } static int convert_struct_from_object(char *data, CTypeDescrObject *ct, PyObject *init, Py_ssize_t *optvarsize) { + /* does not accept 'init' being already a CData */ const char *expected; if (force_lazy_struct(ct) <= 0) { @@ -1506,7 +1533,7 @@ } expected = optvarsize == NULL ? "list or tuple or dict or struct-cdata" : "list or tuple or dict"; - return _convert_error(init, ct->ct_name, expected); + return _convert_error(init, ct, expected); } #ifdef __GNUC__ @@ -1682,7 +1709,7 @@ return _convert_overflow(init, ct->ct_name); cannot_convert: - return _convert_error(init, ct->ct_name, expected); + return _convert_error(init, ct, expected); } static int @@ -1742,15 +1769,6 @@ return 0; } -static Py_ssize_t -get_array_length(CDataObject *cd) -{ - if (cd->c_type->ct_length < 0) - return ((CDataObject_own_length *)cd)->length; - else - return cd->c_type->ct_length; -} - static int get_alignment(CTypeDescrObject *ct) { diff --git a/c/test_c.py b/c/test_c.py --- a/c/test_c.py +++ b/c/test_c.py @@ -1873,7 +1873,7 @@ def test_newp_copying(): """Test that we can do newp(<type>, <cdata of the given type>) for most - types, with the exception of arrays, like in C. + types, including same-type arrays. """ BInt = new_primitive_type("int") p = newp(new_pointer_type(BInt), cast(BInt, 42)) @@ -1902,8 +1902,9 @@ a1 = newp(BArray, [1, 2, 3, 4]) py.test.raises(TypeError, newp, BArray, a1) BArray6 = new_array_type(new_pointer_type(BInt), 6) - a1 = newp(BArray6, None) - py.test.raises(TypeError, newp, BArray6, a1) + a1 = newp(BArray6, [10, 20, 30]) + a2 = newp(BArray6, a1) + assert list(a2) == [10, 20, 30, 0, 0, 0] # s1 = newp(BStructPtr, [42]) s2 = newp(BStructPtr, s1[0]) diff --git a/cffi/backend_ctypes.py b/cffi/backend_ctypes.py --- a/cffi/backend_ctypes.py +++ b/cffi/backend_ctypes.py @@ -636,6 +636,10 @@ if isinstance(init, bytes): init = [init[i:i+1] for i in range(len(init))] else: + if isinstance(init, CTypesGenericArray): + if (len(init) != len(blob) or + not isinstance(init, CTypesArray)): + raise TypeError("length/type mismatch: %s" % (init,)) init = tuple(init) if len(init) > len(blob): raise IndexError("too many initializers") diff --git a/testing/cffi0/backend_tests.py b/testing/cffi0/backend_tests.py --- a/testing/cffi0/backend_tests.py +++ b/testing/cffi0/backend_tests.py @@ -1972,3 +1972,18 @@ assert seen[1] == 101 assert seen[2] == 202 assert seen[3] == 303 + + def test_ffi_array_as_init(self): + ffi = FFI(backend=self.Backend()) + p = ffi.new("int[4]", [10, 20, 30, 400]) + q = ffi.new("int[4]", p) + assert list(q) == [10, 20, 30, 400] + py.test.raises(TypeError, ffi.new, "int[3]", p) + py.test.raises(TypeError, ffi.new, "int[5]", p) + py.test.raises(TypeError, ffi.new, "int16_t[4]", p) + s = ffi.new("struct {int i[4];}*", {'i': p}) + assert list(s.i) == [10, 20, 30, 400] + + def test_too_many_initializers(self): + ffi = FFI(backend=self.Backend()) + py.test.raises(IndexError, ffi.new, "int[4]", [10, 20, 30, 40, 50]) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit