[pypy-svn] r45029 - in pypy/dist/pypy/rpython/lltypesystem: . test

arigo at codespeak.net arigo at codespeak.net
Fri Jul 13 17:09:26 CEST 2007


Author: arigo
Date: Fri Jul 13 17:09:25 2007
New Revision: 45029

Added:
   pypy/dist/pypy/rpython/lltypesystem/lltype2ctypes.py   (contents, props changed)
   pypy/dist/pypy/rpython/lltypesystem/test/test_lltype2ctypes.py   (contents, props changed)
Modified:
   pypy/dist/pypy/rpython/lltypesystem/lltype.py
Log:
(lac, arigo, pedronis around)

Another approach: can convert _struct in-place to internally use a
ctypes.Structure.



Modified: pypy/dist/pypy/rpython/lltypesystem/lltype.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/lltype.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/lltype.py	Fri Jul 13 17:09:25 2007
@@ -1191,16 +1191,19 @@
                  '_parent_type', '_parent_index', '_keepparent',
                  '_wrparent',
                  '__weakref__',
-                 '_dead')
+                 '_dead',
+                 '_ctypes_storage')
 
     def __init__(self, TYPE):
         self._wrparent = None
         self._TYPE = TYPE
         self._dead = False
+        self._ctypes_storage = None
 
     def _free(self):
         self._check()   # no double-frees
         self._dead = True
+        self._ctypes_storage = None
 
     def _setparentstructure(self, parent, parentindex):
         self._wrparent = weakref.ref(parent)
@@ -1317,7 +1320,18 @@
         if isinstance(r, _uninitialized) and not uninitialized_ok:
             raise UninitializedMemoryAccess("%r.%s"%(self, field_name))
         return r
-    
+
+    def __getattr__(self, field_name):
+        if self._ctypes_storage is not None:
+            return self._ctypes_storage._getattr(field_name)
+        raise AttributeError(field_name)
+
+    def __setattr__(self, field_name, value):
+        if field_name.startswith('_') or self._ctypes_storage is None:
+            _parentable.__setattr__(self, field_name, value)
+        else:
+            self._ctypes_storage._setattr(field_name, value)
+
     # for FixedSizeArray kind of structs:
     
     def getlength(self):

Added: pypy/dist/pypy/rpython/lltypesystem/lltype2ctypes.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/lltypesystem/lltype2ctypes.py	Fri Jul 13 17:09:25 2007
@@ -0,0 +1,108 @@
+import ctypes
+from pypy.rpython.lltypesystem import lltype
+
+
+_ctypes_cache = {
+    lltype.Signed: ctypes.c_long,
+    }
+
+def build_ctypes_struct(S, max_n=None):
+    fields = []
+    for fieldname in S._names:
+        FIELDTYPE = S._flds[fieldname]
+        if max_n is not None and fieldname == S._arrayfld:
+            cls = build_ctypes_array(FIELDTYPE, max_n)
+        else:
+            cls = get_ctypes_type(FIELDTYPE)
+        fields.append((fieldname, cls))
+
+    class CStruct(ctypes.Structure):
+        _fields_ = fields
+
+        def _malloc(cls, n=None):
+            if S._arrayfld is None:
+                if n is not None:
+                    raise TypeError("%r is not variable-sized" % (S,))
+                storage = cls()
+                return storage
+            else:
+                if n is None:
+                    raise TypeError("%r is variable-sized" % (S,))
+                biggercls = build_ctypes_struct(S, n)
+                bigstruct = biggercls()
+                getattr(bigstruct, S._arrayfld).length = n
+                return bigstruct
+        _malloc = classmethod(_malloc)
+
+        def _getattr(self, field_name):
+            cobj = getattr(self, field_name)
+            return ctypes2lltype(cobj)
+
+        def _setattr(self, field_name, value):
+            cobj = lltype2ctypes(value)
+            setattr(self, field_name, cobj)
+
+    CStruct.__name__ = 'ctypes_%s' % (S,)
+    return CStruct
+
+def build_ctypes_array(A, max_n=0):
+    assert max_n >= 0
+    ITEM = A.OF
+    ctypes_item = get_ctypes_type(ITEM)
+
+    class CArray(ctypes.Structure):
+        _fields_ = [('length', ctypes.c_int),
+                    ('items',  max_n * ctypes_item)]
+
+        def _malloc(cls, n=None):
+            if not isinstance(n, int):
+                raise TypeError, "array length must be an int"
+            biggercls = build_ctypes_array(A, n)
+            bigarray = biggercls()
+            bigarray.length = n
+            return bigarray
+        _malloc = classmethod(_malloc)
+
+    CArray.__name__ = 'ctypes_%s*%d' % (A, max_n)
+    return CArray
+
+def get_ctypes_type(T):
+    try:
+        return _ctypes_cache[T]
+    except KeyError:
+        if isinstance(T, lltype.Ptr):
+            cls = ctypes.POINTER(get_ctypes_type(T.TO))
+        elif isinstance(T, lltype.Struct):
+            cls = build_ctypes_struct(T)
+        elif isinstance(T, lltype.Array):
+            cls = build_ctypes_array(T)
+        else:
+            raise NotImplementedError(T)
+        _ctypes_cache[T] = cls
+        return cls
+
+
+def convert_struct(container):
+    STRUCT = container._TYPE
+    cls = get_ctypes_type(STRUCT)
+    cstruct = cls._malloc()
+    container._ctypes_storage = cstruct
+    for field_name in STRUCT._names:
+        field_value = getattr(container, field_name)
+        delattr(container, field_name)
+        setattr(cstruct, field_name, lltype2ctypes(field_value))
+
+def lltype2ctypes(llobj):
+    T = lltype.typeOf(llobj)
+    if isinstance(T, lltype.Ptr):
+        container = llobj._obj
+        if container._ctypes_storage is None:
+            if isinstance(T.TO, lltype.Struct):
+                convert_struct(container)
+            else:
+                raise NotImplementedError(T)
+        return ctypes.pointer(container._ctypes_storage)
+    return llobj
+
+def ctypes2lltype(cobj):
+    return cobj

Added: pypy/dist/pypy/rpython/lltypesystem/test/test_lltype2ctypes.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/lltypesystem/test/test_lltype2ctypes.py	Fri Jul 13 17:09:25 2007
@@ -0,0 +1,21 @@
+import ctypes
+from pypy.rpython.lltypesystem import lltype
+from pypy.rpython.lltypesystem.lltype2ctypes import lltype2ctypes
+
+
+def test_primitive():
+    assert lltype2ctypes(5) == 5
+    assert lltype2ctypes('?') == '?'
+
+def test_simple_struct():
+    S = lltype.Struct('S', ('x', lltype.Signed))
+    s = lltype.malloc(S, flavor='raw')
+    s.x = 123
+    sc = lltype2ctypes(s)
+    assert isinstance(sc.contents, ctypes.Structure)
+    assert sc.contents.x == 123
+    sc.contents.x = 456
+    assert s.x == 456
+    s.x = 789
+    assert sc.contents.x == 789
+    lltype.free(s, flavor='raw')



More information about the Pypy-commit mailing list