Author: Armin Rigo <ar...@tunes.org>
Branch: 
Changeset: r75195:9bdd174fb4e1
Date: 2015-01-01 18:47 +0100
http://bitbucket.org/pypy/pypy/changeset/9bdd174fb4e1/

Log:    Implement ffi.from_buffer(). Not really tested with memoryviews,
        only buffers, just like in CPython for the same reasons.

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
@@ -34,6 +34,7 @@
         'newp_handle': 'handle.newp_handle',
         'from_handle': 'handle.from_handle',
         '_get_types': 'func._get_types',
+        'from_buffer': 'func.from_buffer',
 
         'string': 'func.string',
         'buffer': 'cbuffer.buffer',
diff --git a/pypy/module/_cffi_backend/cdataobj.py 
b/pypy/module/_cffi_backend/cdataobj.py
--- a/pypy/module/_cffi_backend/cdataobj.py
+++ b/pypy/module/_cffi_backend/cdataobj.py
@@ -440,6 +440,25 @@
         return "handle to %s" % (self.space.str_w(w_repr),)
 
 
+class W_CDataFromBuffer(W_CData):
+    _attrs_ = ['buf', 'length', 'w_keepalive']
+    _immutable_fields_ = ['buf', 'length', 'w_keepalive']
+
+    def __init__(self, space, cdata, ctype, buf, w_object):
+        W_CData.__init__(self, space, cdata, ctype)
+        self.buf = buf
+        self.length = buf.getlength()
+        self.w_keepalive = w_object
+
+    def get_array_length(self):
+        return self.length
+
+    def _repr_extra(self):
+        w_repr = self.space.repr(self.w_keepalive)
+        return "buffer len %d from '%s' object" % (
+            self.length, self.space.type(self.w_keepalive).name)
+
+
 W_CData.typedef = TypeDef(
     '_cffi_backend.CData',
     __module__ = '_cffi_backend',
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
@@ -76,3 +76,32 @@
 def _get_types(space):
     return space.newtuple([space.gettypefor(cdataobj.W_CData),
                            space.gettypefor(ctypeobj.W_CType)])
+
+# ____________________________________________________________
+
+@unwrap_spec(w_ctype=ctypeobj.W_CType)
+def from_buffer(space, w_ctype, w_x):
+    from pypy.module._cffi_backend import ctypearray, ctypeprim
+    #
+    if (not isinstance(w_ctype, ctypearray.W_CTypeArray) or
+        not isinstance(w_ctype.ctptr.ctitem, ctypeprim.W_CTypePrimitiveChar)):
+        raise oefmt(space.w_TypeError,
+                    "needs 'char[]', got '%s'", w_ctype.name)
+    #
+    # xxx do we really need to implement the same mess as in CPython 2.7
+    # w.r.t. buffers and memoryviews??
+    try:
+        buf = space.readbuf_w(w_x)
+    except OperationError, e:
+        if not e.match(space, space.w_TypeError):
+            raise
+        buf = space.buffer_w(w_x, space.BUF_SIMPLE)
+    try:
+        _cdata = buf.get_raw_address()
+    except ValueError:
+        raise oefmt(space.w_TypeError,
+                    "from_buffer() got a '%T' object, which supports the "
+                    "buffer interface but cannot be rendered as a plain "
+                    "raw address on PyPy", w_x)
+    #
+    return cdataobj.W_CDataFromBuffer(space, _cdata, w_ctype, buf, w_x)
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
@@ -3195,6 +3195,20 @@
                              ('a2', BChar, 5)],
                    None, -1, -1, SF_PACKED)
 
+def test_from_buffer():
+    import array
+    a = array.array('H', [10000, 20000, 30000])
+    BChar = new_primitive_type("char")
+    BCharP = new_pointer_type(BChar)
+    BCharA = new_array_type(BCharP, None)
+    c = from_buffer(BCharA, a)
+    assert typeof(c) is BCharA
+    assert len(c) == 6
+    assert repr(c) == "<cdata 'char[]' buffer len 6 from 'array.array' object>"
+    p = new_pointer_type(new_primitive_type("unsigned short"))
+    cast(p, c)[1] += 500
+    assert list(a) == [10000, 20500, 30000]
+
 def test_version():
     # this test is here mostly for PyPy
     assert __version__ == "0.8.6"
diff --git a/pypy/module/_cffi_backend/test/test_c.py 
b/pypy/module/_cffi_backend/test/test_c.py
--- a/pypy/module/_cffi_backend/test/test_c.py
+++ b/pypy/module/_cffi_backend/test/test_c.py
@@ -30,7 +30,7 @@
 class AppTestC(object):
     """Populated below, hack hack hack."""
 
-    spaceconfig = dict(usemodules=('_cffi_backend', 'cStringIO'))
+    spaceconfig = dict(usemodules=('_cffi_backend', 'cStringIO', 'array'))
 
     def setup_class(cls):
         testfuncs_w = []
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to