Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r83691:556303cdfd09 Date: 2016-04-15 19:29 +0200 http://bitbucket.org/pypy/pypy/changeset/556303cdfd09/
Log: Add ffi.rawstring() diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py --- a/pypy/module/_cffi_backend/__init__.py +++ b/pypy/module/_cffi_backend/__init__.py @@ -48,6 +48,7 @@ 'from_buffer': 'func.from_buffer', 'string': 'func.string', + 'rawstring': 'func.rawstring', 'buffer': 'cbuffer.buffer', 'memmove': 'func.memmove', diff --git a/pypy/module/_cffi_backend/ctypearray.py b/pypy/module/_cffi_backend/ctypearray.py --- a/pypy/module/_cffi_backend/ctypearray.py +++ b/pypy/module/_cffi_backend/ctypearray.py @@ -7,11 +7,12 @@ from pypy.interpreter.gateway import interp2app from pypy.interpreter.typedef import TypeDef -from rpython.rtyper.lltypesystem import rffi +from rpython.rtyper.lltypesystem import lltype, rffi from rpython.rlib.rarithmetic import ovfcheck from pypy.module._cffi_backend import cdataobj from pypy.module._cffi_backend.ctypeptr import W_CTypePtrOrArray +from pypy.module._cffi_backend import ctypeprim class W_CTypeArray(W_CTypePtrOrArray): @@ -108,6 +109,21 @@ def typeoffsetof_index(self, index): return self.ctptr.typeoffsetof_index(index) + def rawstring(self, w_cdata): + if isinstance(self.ctitem, ctypeprim.W_CTypePrimitive): + space = self.space + length = w_cdata.get_array_length() + if self.ctitem.size == rffi.sizeof(lltype.Char): + with w_cdata as ptr: + s = rffi.charpsize2str(ptr, length) + return space.wrapbytes(s) + elif self.is_unichar_ptr_or_array(): + with w_cdata as ptr: + cdata = rffi.cast(rffi.CWCHARP, ptr) + u = rffi.wcharpsize2unicode(cdata, length) + return space.wrap(u) + return W_CTypePtrOrArray.rawstring(self, w_cdata) + class W_CDataIter(W_Root): _immutable_fields_ = ['ctitem', 'cdata', '_stop'] # but not '_next' diff --git a/pypy/module/_cffi_backend/ctypeobj.py b/pypy/module/_cffi_backend/ctypeobj.py --- a/pypy/module/_cffi_backend/ctypeobj.py +++ b/pypy/module/_cffi_backend/ctypeobj.py @@ -127,6 +127,12 @@ raise oefmt(space.w_TypeError, "string(): unexpected cdata '%s' argument", self.name) + def rawstring(self, cdataobj): + space = self.space + raise oefmt(space.w_TypeError, + "expected a 'char[]' or 'uint8_t[]' or 'int8_t[]' " + "or 'wchar_t[]', got '%s'", self.name) + def add(self, cdata, i): space = self.space raise oefmt(space.w_TypeError, "cannot add a cdata '%s' and a number", diff --git a/pypy/module/_cffi_backend/ffi_obj.py b/pypy/module/_cffi_backend/ffi_obj.py --- a/pypy/module/_cffi_backend/ffi_obj.py +++ b/pypy/module/_cffi_backend/ffi_obj.py @@ -542,6 +542,21 @@ return w_cdata.ctype.string(w_cdata, maxlen) + @unwrap_spec(w_cdata=W_CData) + def descr_rawstring(self, w_cdata): + """\ +Convert a cdata that is an array of 'char' or 'wchar_t' to +a byte or unicode string. Unlike ffi.string(), it does not stop +at the first null. + +Note that if you have a pointer and an explicit length, you +can use 'p[0:length]' to make an array view. This is similar to +the construct 'list(p[0:length])', which returns a list of chars/ +unichars/ints/floats.""" + # + return w_cdata.ctype.rawstring(w_cdata) + + def descr_sizeof(self, w_arg): """\ Return the size in bytes of the argument. @@ -736,6 +751,7 @@ new_allocator = interp2app(W_FFIObject.descr_new_allocator), new_handle = interp2app(W_FFIObject.descr_new_handle), offsetof = interp2app(W_FFIObject.descr_offsetof), + rawstring = interp2app(W_FFIObject.descr_rawstring), sizeof = interp2app(W_FFIObject.descr_sizeof), string = interp2app(W_FFIObject.descr_string), typeof = interp2app(W_FFIObject.descr_typeof), diff --git a/pypy/module/_cffi_backend/func.py b/pypy/module/_cffi_backend/func.py --- a/pypy/module/_cffi_backend/func.py +++ b/pypy/module/_cffi_backend/func.py @@ -78,6 +78,12 @@ # ____________________________________________________________ +@unwrap_spec(w_cdata=cdataobj.W_CData) +def rawstring(space, w_cdata): + return w_cdata.ctype.rawstring(w_cdata) + +# ____________________________________________________________ + def _get_types(space): return space.newtuple([space.gettypefor(cdataobj.W_CData), space.gettypefor(ctypeobj.W_CType)]) diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py --- a/pypy/module/_cffi_backend/test/_backend_test_c.py +++ b/pypy/module/_cffi_backend/test/_backend_test_c.py @@ -3514,3 +3514,22 @@ d = {} _get_common_types(d) assert d['bool'] == '_Bool' + +def test_rawstring(): + BChar = new_primitive_type("char") + BArray = new_array_type(new_pointer_type(BChar), 10) # char[10] + p = newp(BArray, "abc\x00def") + assert rawstring(p) == "abc\x00def\x00\x00\x00" + assert rawstring(p[1:6]) == "bc\x00de" + BWChar = new_primitive_type("wchar_t") + BArray = new_array_type(new_pointer_type(BWChar), 10) # wchar_t[10] + p = newp(BArray, u"abc\x00def") + assert rawstring(p) == u"abc\x00def\x00\x00\x00" + assert rawstring(p[1:6]) == u"bc\x00de" + BChar = new_primitive_type("uint8_t") + BArray = new_array_type(new_pointer_type(BChar), 10) # uint8_t[10] + p = newp(BArray, [65 + i for i in range(10)]) + assert rawstring(p) == "ABCDEFGHIJ" + # + py.test.raises(TypeError, rawstring, "foobar") + py.test.raises(TypeError, rawstring, p + 1) diff --git a/pypy/module/_cffi_backend/test/test_ffi_obj.py b/pypy/module/_cffi_backend/test/test_ffi_obj.py --- a/pypy/module/_cffi_backend/test/test_ffi_obj.py +++ b/pypy/module/_cffi_backend/test/test_ffi_obj.py @@ -476,3 +476,16 @@ for i in range(5): raises(ValueError, ffi.init_once, do_init, "tag") assert seen == [1] * (i + 1) + + def test_rawstring(self): + import _cffi_backend as _cffi1_backend + ffi = _cffi1_backend.FFI() + p = ffi.new("char[]", "abc\x00def") + assert ffi.rawstring(p) == "abc\x00def\x00" + assert ffi.rawstring(p[1:6]) == "bc\x00de" + p = ffi.new("wchar_t[]", u"abc\x00def") + assert ffi.rawstring(p) == u"abc\x00def\x00" + assert ffi.rawstring(p[1:6]) == u"bc\x00de" + # + raises(TypeError, ffi.rawstring, "foobar") + raises(TypeError, ffi.rawstring, p + 1) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit