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

Reply via email to