[pypy-commit] pypy ffi-backend: Refactoring: split ctypeobj.py.

arigo noreply at buildbot.pypy.org
Tue Jun 26 16:57:08 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: ffi-backend
Changeset: r55833:953c16a08cfc
Date: 2012-06-26 16:56 +0200
http://bitbucket.org/pypy/pypy/changeset/953c16a08cfc/

Log:	Refactoring: split ctypeobj.py.

diff --git a/pypy/module/_ffi_backend/cdataobj.py b/pypy/module/_ffi_backend/cdataobj.py
--- a/pypy/module/_ffi_backend/cdataobj.py
+++ b/pypy/module/_ffi_backend/cdataobj.py
@@ -15,9 +15,9 @@
     cdata = lltype.nullptr(rffi.CCHARP.TO)
 
     def __init__(self, space, cdata, ctype):
-        from pypy.module._ffi_backend import ctypeobj
+        from pypy.module._ffi_backend import ctypeprim
         assert lltype.typeOf(cdata) == rffi.CCHARP
-        assert isinstance(ctype, ctypeobj.W_CType)
+        assert isinstance(ctype, ctypeprim.W_CType)
         self.space = space
         self._cdata = cdata    # don't forget keepalive_until_here!
         self.ctype = ctype
@@ -48,9 +48,9 @@
         return w_result
 
     def len(self):
-        from pypy.module._ffi_backend import ctypeobj
+        from pypy.module._ffi_backend import ctypearray
         space = self.space
-        if isinstance(self.ctype, ctypeobj.W_CTypeArray):
+        if isinstance(self.ctype, ctypearray.W_CTypeArray):
             return space.wrap(self.get_array_length())
         raise operationerrfmt(space.w_TypeError,
                               "cdata of type '%s' has no len()",
@@ -110,13 +110,13 @@
         space = self.space
         ob = space.interpclass_w(w_other)
         if isinstance(ob, W_CData):
-            from pypy.module._ffi_backend import ctypeobj
+            from pypy.module._ffi_backend import ctypeptr, ctypearray
             ct = ob.ctype
-            if isinstance(ct, ctypeobj.W_CTypeArray):
+            if isinstance(ct, ctypearray.W_CTypeArray):
                 ct = ct.ctptr
             #
             if (ct is not self.ctype or
-                   not isinstance(ct, ctypeobj.W_CTypePointer) or
+                   not isinstance(ct, ctypeptr.W_CTypePointer) or
                    ct.ctitem.size <= 0):
                 raise operationerrfmt(space.w_TypeError,
                     "cannot subtract cdata '%s' and cdata '%s'",
@@ -129,13 +129,13 @@
         return self._add_or_sub(w_other, -1)
 
     def getcfield(self, w_attr):
-        from pypy.module._ffi_backend import ctypeobj
+        from pypy.module._ffi_backend import ctypeptr, ctypestruct
         space = self.space
         ctype = self.ctype
         attr = space.str_w(w_attr)
-        if isinstance(ctype, ctypeobj.W_CTypePointer):
+        if isinstance(ctype, ctypeptr.W_CTypePointer):
             ctype = ctype.ctitem
-        if (isinstance(ctype, ctypeobj.W_CTypeStructOrUnion) and
+        if (isinstance(ctype, ctypestruct.W_CTypeStructOrUnion) and
                 ctype.fields_dict is not None):
             try:
                 return ctype.fields_dict[attr]
@@ -183,9 +183,9 @@
         return w_obj
 
     def get_array_length(self):
-        from pypy.module._ffi_backend import ctypeobj
+        from pypy.module._ffi_backend import ctypearray
         ctype = self.ctype
-        assert isinstance(ctype, ctypeobj.W_CTypeArray)
+        assert isinstance(ctype, ctypearray.W_CTypeArray)
         length = ctype.length
         assert length >= 0
         return length
diff --git a/pypy/module/_ffi_backend/ctypearray.py b/pypy/module/_ffi_backend/ctypearray.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi_backend/ctypearray.py
@@ -0,0 +1,116 @@
+"""
+Arrays.
+"""
+
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.rpython.lltypesystem import rffi
+from pypy.rlib.objectmodel import keepalive_until_here
+from pypy.rlib.rarithmetic import ovfcheck
+
+from pypy.module._ffi_backend.ctypeobj import W_CType
+from pypy.module._ffi_backend.ctypeprim import W_CTypePrimitiveChar
+from pypy.module._ffi_backend.ctypeptr import W_CTypePtrOrArray
+from pypy.module._ffi_backend import cdataobj
+
+
+class W_CTypeArray(W_CTypePtrOrArray):
+
+    def __init__(self, space, ctptr, length, arraysize, extra):
+        W_CTypePtrOrArray.__init__(self, space, arraysize, extra, 0,
+                                   ctptr.ctitem)
+        self.length = length
+        self.ctptr = ctptr
+
+    def str(self, cdataobj):
+        if isinstance(self.ctitem, W_CTypePrimitiveChar):
+            s = rffi.charp2strn(cdataobj._cdata, cdataobj.get_array_length())
+            keepalive_until_here(cdataobj)
+            return self.space.wrap(s)
+        return W_CTypePtrOrArray.str(self, cdataobj)
+
+    def _alignof(self):
+        return self.ctitem.alignof()
+
+    def newp(self, w_init):
+        space = self.space
+        datasize = self.size
+        #
+        if datasize < 0:
+            if (space.isinstance_w(w_init, space.w_list) or
+                space.isinstance_w(w_init, space.w_tuple)):
+                length = space.int_w(space.len(w_init))
+            elif space.isinstance_w(w_init, space.w_str):
+                # from a string, we add the null terminator
+                length = space.int_w(space.len(w_init)) + 1
+            else:
+                length = space.getindex_w(w_init, space.w_OverflowError)
+                if length < 0:
+                    raise OperationError(space.w_ValueError,
+                                         space.wrap("negative array length"))
+                w_init = space.w_None
+            #
+            try:
+                datasize = ovfcheck(length * self.ctitem.size)
+            except OverflowError:
+                raise OperationError(space.w_OverflowError,
+                    space.wrap("array size would overflow a ssize_t"))
+            #
+            cdata = cdataobj.W_CDataOwnLength(space, datasize, self, length)
+        #
+        else:
+            cdata = cdataobj.W_CDataOwn(space, datasize, self)
+        #
+        if not space.is_w(w_init, space.w_None):
+            self.convert_from_object(cdata._cdata, w_init)
+            keepalive_until_here(cdata)
+        return cdata
+
+    def _check_subscript_index(self, w_cdata, i):
+        space = self.space
+        if i < 0:
+            raise OperationError(space.w_IndexError,
+                                 space.wrap("negative index not supported"))
+        if i >= w_cdata.get_array_length():
+            raise operationerrfmt(space.w_IndexError,
+                "index too large for cdata '%s' (expected %d < %d)",
+                self.name, i, w_cdata.get_array_length())
+
+    def convert_from_object(self, cdata, w_ob):
+        space = self.space
+        if (space.isinstance_w(w_ob, space.w_list) or
+            space.isinstance_w(w_ob, space.w_tuple)):
+            lst_w = space.listview(w_ob)
+            if self.length >= 0 and len(lst_w) > self.length:
+                raise operationerrfmt(space.w_IndexError,
+                    "too many initializers for '%s' (got %d)",
+                                      self.name, len(lst_w))
+            ctitem = self.ctitem
+            for i in range(len(lst_w)):
+                ctitem.convert_from_object(cdata, lst_w[i])
+                cdata = rffi.ptradd(cdata, ctitem.size)
+        elif isinstance(self.ctitem, W_CTypePrimitiveChar):
+            try:
+                s = space.str_w(w_ob)
+            except OperationError, e:
+                if not e.match(space, space.w_TypeError):
+                    raise
+                raise self._convert_error("str or list or tuple", w_ob)
+            n = len(s)
+            if self.length >= 0 and n > self.length:
+                raise operationerrfmt(space.w_IndexError,
+                                      "initializer string is too long for '%s'"
+                                      " (got %d characters)",
+                                      self.name, n)
+            for i in range(n):
+                cdata[i] = s[i]
+            if n != self.length:
+                cdata[n] = '\x00'
+        else:
+            raise self._convert_error("list or tuple", w_ob)
+
+    def convert_to_object(self, cdata):
+        return cdataobj.W_CData(self.space, cdata, self)
+
+    def add(self, cdata, i):
+        p = rffi.ptradd(cdata, i * self.ctitem.size)
+        return cdataobj.W_CData(self.space, p, self.ctptr)
diff --git a/pypy/module/_ffi_backend/ctypeenum.py b/pypy/module/_ffi_backend/ctypeenum.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi_backend/ctypeenum.py
@@ -0,0 +1,83 @@
+"""
+Enums.
+"""
+
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.rlib.objectmodel import keepalive_until_here
+
+from pypy.module._ffi_backend.ctypeprim import W_CTypePrimitiveSigned
+from pypy.module._ffi_backend import misc
+
+
+class W_CTypeEnum(W_CTypePrimitiveSigned):
+
+    def __init__(self, space, name, enumerators, enumvalues):
+        from pypy.module._ffi_backend.newtype import alignment
+        name = "enum " + name
+        size = rffi.sizeof(rffi.INT)
+        align = alignment(rffi.INT)
+        W_CTypePrimitiveSigned.__init__(self, space, size,
+                                        name, len(name), align)
+        self.enumerators2values = {}   # str -> int
+        self.enumvalues2erators = {}   # int -> str
+        for i in range(len(enumerators)):
+            self.enumerators2values[enumerators[i]] = enumvalues[i]
+            self.enumvalues2erators[enumvalues[i]] = enumerators[i]
+
+    def _getfields(self):
+        space = self.space
+        lst = []
+        for enumerator in self.enumerators2values:
+            enumvalue = self.enumerators2values[enumerator]
+            lst.append(space.newtuple([space.wrap(enumvalue),
+                                       space.wrap(enumerator)]))
+        w_lst = space.newlist(lst)
+        space.call_method(w_lst, 'sort')
+        return w_lst
+
+    def str(self, cdataobj):
+        w_res = self.convert_to_object(cdataobj._cdata)
+        keepalive_until_here(cdataobj)
+        return w_res
+
+    def convert_to_object(self, cdata):
+        value = intmask(misc.read_raw_signed_data(cdata, self.size))
+        try:
+            enumerator = self.enumvalues2erators[value]
+        except KeyError:
+            enumerator = '#%d' % (value,)
+        return self.space.wrap(enumerator)
+
+    def convert_from_object(self, cdata, w_ob):
+        space = self.space
+        try:
+            return W_CTypePrimitiveSigned.convert_from_object(self, cdata,
+                                                              w_ob)
+        except OperationError, e:
+            if not e.match(space, space.w_TypeError):
+                raise
+        if space.isinstance_w(w_ob, space.w_str):
+            value = self.convert_enum_string_to_int(space.str_w(w_ob))
+            misc.write_raw_integer_data(cdata, value, self.size)
+        else:
+            raise self._convert_error("str or int", w_ob)
+
+    def cast_str(self, w_ob):
+        space = self.space
+        return self.convert_enum_string_to_int(space.str_w(w_ob))
+
+    def convert_enum_string_to_int(self, s):
+        space = self.space
+        if s.startswith('#'):
+            try:
+                return int(s[1:])     # xxx is it RPython?
+            except ValueError:
+                raise OperationError(space.w_ValueError,
+                                     space.wrap("invalid literal after '#'"))
+        else:
+            try:
+                return self.enumerators2values[s]
+            except KeyError:
+                raise operationerrfmt(space.w_ValueError,
+                                      "'%s' is not an enumerator for %s",
+                                      s, self.name)
diff --git a/pypy/module/_ffi_backend/ctypeobj.py b/pypy/module/_ffi_backend/ctypeobj.py
--- a/pypy/module/_ffi_backend/ctypeobj.py
+++ b/pypy/module/_ffi_backend/ctypeobj.py
@@ -1,13 +1,12 @@
 from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.interpreter.baseobjspace import Wrappable
-from pypy.interpreter.gateway import interp2app, unwrap_spec
-from pypy.interpreter.typedef import TypeDef, interp_attrproperty
+from pypy.interpreter.gateway import interp2app
+from pypy.interpreter.typedef import TypeDef
 from pypy.interpreter.typedef import make_weakref_descr
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi
-from pypy.rlib.rarithmetic import intmask, ovfcheck, r_ulonglong
-from pypy.rlib.objectmodel import keepalive_until_here, we_are_translated
+from pypy.rlib.objectmodel import we_are_translated
 
-from pypy.module._ffi_backend import cdataobj, misc
+from pypy.module._ffi_backend import cdataobj
 
 
 class W_CType(Wrappable):
@@ -115,606 +114,9 @@
         return None
 
 
-class W_CTypePtrOrArray(W_CType):
-
-    def __init__(self, space, size, extra, extra_position, ctitem):
-        name, name_position = ctitem.insert_name(extra, extra_position)
-        W_CType.__init__(self, space, size, name, name_position)
-        self.ctitem = ctitem
-
-
-class W_CTypePointer(W_CTypePtrOrArray):
-
-    def __init__(self, space, ctitem):
-        size = rffi.sizeof(rffi.VOIDP)
-        if isinstance(ctitem, W_CTypeArray):
-            extra = "(*)"    # obscure case: see test_array_add
-        else:
-            extra = " *"
-        W_CTypePtrOrArray.__init__(self, space, size, extra, 2, ctitem)
-
-    def str(self, cdataobj):
-        if isinstance(self.ctitem, W_CTypePrimitiveChar):
-            if not cdataobj._cdata:
-                space = self.space
-                raise operationerrfmt(space.w_RuntimeError,
-                                      "cannot use str() on %s",
-                                      space.str_w(cdataobj.repr()))
-            s = rffi.charp2str(cdataobj._cdata)
-            keepalive_until_here(cdataobj)
-            return self.space.wrap(s)
-        return W_CTypePtrOrArray.str(self, cdataobj)
-
-    def cast(self, w_ob):
-        space = self.space
-        ob = space.interpclass_w(w_ob)
-        if (isinstance(ob, cdataobj.W_CData) and
-                isinstance(ob.ctype, W_CTypePtrOrArray)):
-            value = ob._cdata
-        else:
-            value = misc.as_unsigned_long_long(space, w_ob, strict=False)
-            value = rffi.cast(rffi.CCHARP, value)
-        return cdataobj.W_CData(space, value, self)
-
-    def newp(self, w_init):
-        space = self.space
-        ctitem = self.ctitem
-        datasize = ctitem.size
-        if datasize < 0:
-            raise operationerrfmt(space.w_TypeError,
-                "cannot instantiate ctype '%s' of unknown size",
-                                  self.name)
-        if isinstance(ctitem, W_CTypePrimitiveChar):
-            datasize *= 2       # forcefully add a null character
-        cdata = cdataobj.W_CDataOwn(space, datasize, self)
-        if not space.is_w(w_init, space.w_None):
-            ctitem.convert_from_object(cdata._cdata, w_init)
-            keepalive_until_here(cdata)
-        return cdata
-
-    def _check_subscript_index(self, w_cdata, i):
-        if isinstance(w_cdata, cdataobj.W_CDataOwn) and i != 0:
-            space = self.space
-            raise operationerrfmt(space.w_IndexError,
-                                  "cdata '%s' can only be indexed by 0",
-                                  self.name)
-
-    def add(self, cdata, i):
-        space = self.space
-        ctitem = self.ctitem
-        if ctitem.size < 0:
-            raise operationerrfmt(space.w_TypeError,
-                                  "ctype '%s' points to items of unknown size",
-                                  self.name)
-        p = rffi.ptradd(cdata, i * self.ctitem.size)
-        return cdataobj.W_CData(space, p, self)
-
-    def _alignof(self):
-        from pypy.module._ffi_backend import newtype
-        return newtype.alignment_of_pointer
-
-    def convert_to_object(self, cdata):
-        ptrdata = rffi.cast(rffi.CCHARPP, cdata)[0]
-        return cdataobj.W_CData(self.space, ptrdata, self)
-
-    def convert_from_object(self, cdata, w_ob):
-        space = self.space
-        ob = space.interpclass_w(w_ob)
-        if not isinstance(ob, cdataobj.W_CData):
-            raise self._convert_error("compatible pointer", w_ob)
-        otherctype = ob.ctype
-        if (isinstance(otherctype, W_CTypePtrOrArray) and
-            (self.ctitem.cast_anything or
-             otherctype.ctitem.cast_anything or
-             self.ctitem is otherctype.ctitem)):
-            pass    # compatible types
-        else:
-            raise self._convert_error("compatible pointer", w_ob)
-
-        rffi.cast(rffi.CCHARPP, cdata)[0] = ob._cdata
-
-
-class W_CTypeArray(W_CTypePtrOrArray):
-
-    def __init__(self, space, ctptr, length, arraysize, extra):
-        W_CTypePtrOrArray.__init__(self, space, arraysize, extra, 0,
-                                   ctptr.ctitem)
-        self.length = length
-        self.ctptr = ctptr
-
-    def str(self, cdataobj):
-        if isinstance(self.ctitem, W_CTypePrimitiveChar):
-            s = rffi.charp2strn(cdataobj._cdata, cdataobj.get_array_length())
-            keepalive_until_here(cdataobj)
-            return self.space.wrap(s)
-        return W_CTypePtrOrArray.str(self, cdataobj)
-
-    def _alignof(self):
-        return self.ctitem.alignof()
-
-    def newp(self, w_init):
-        space = self.space
-        datasize = self.size
-        #
-        if datasize < 0:
-            if (space.isinstance_w(w_init, space.w_list) or
-                space.isinstance_w(w_init, space.w_tuple)):
-                length = space.int_w(space.len(w_init))
-            elif space.isinstance_w(w_init, space.w_str):
-                # from a string, we add the null terminator
-                length = space.int_w(space.len(w_init)) + 1
-            else:
-                length = space.getindex_w(w_init, space.w_OverflowError)
-                if length < 0:
-                    raise OperationError(space.w_ValueError,
-                                         space.wrap("negative array length"))
-                w_init = space.w_None
-            #
-            try:
-                datasize = ovfcheck(length * self.ctitem.size)
-            except OverflowError:
-                raise OperationError(space.w_OverflowError,
-                    space.wrap("array size would overflow a ssize_t"))
-            #
-            cdata = cdataobj.W_CDataOwnLength(space, datasize, self, length)
-        #
-        else:
-            cdata = cdataobj.W_CDataOwn(space, datasize, self)
-        #
-        if not space.is_w(w_init, space.w_None):
-            self.convert_from_object(cdata._cdata, w_init)
-            keepalive_until_here(cdata)
-        return cdata
-
-    def _check_subscript_index(self, w_cdata, i):
-        space = self.space
-        if i < 0:
-            raise OperationError(space.w_IndexError,
-                                 space.wrap("negative index not supported"))
-        if i >= w_cdata.get_array_length():
-            raise operationerrfmt(space.w_IndexError,
-                "index too large for cdata '%s' (expected %d < %d)",
-                self.name, i, w_cdata.get_array_length())
-
-    def convert_from_object(self, cdata, w_ob):
-        space = self.space
-        if (space.isinstance_w(w_ob, space.w_list) or
-            space.isinstance_w(w_ob, space.w_tuple)):
-            lst_w = space.listview(w_ob)
-            if self.length >= 0 and len(lst_w) > self.length:
-                raise operationerrfmt(space.w_IndexError,
-                    "too many initializers for '%s' (got %d)",
-                                      self.name, len(lst_w))
-            ctitem = self.ctitem
-            for i in range(len(lst_w)):
-                ctitem.convert_from_object(cdata, lst_w[i])
-                cdata = rffi.ptradd(cdata, ctitem.size)
-        elif isinstance(self.ctitem, W_CTypePrimitiveChar):
-            try:
-                s = space.str_w(w_ob)
-            except OperationError, e:
-                if not e.match(space, space.w_TypeError):
-                    raise
-                raise self._convert_error("str or list or tuple", w_ob)
-            n = len(s)
-            if self.length >= 0 and n > self.length:
-                raise operationerrfmt(space.w_IndexError,
-                                      "initializer string is too long for '%s'"
-                                      " (got %d characters)",
-                                      self.name, n)
-            for i in range(n):
-                cdata[i] = s[i]
-            if n != self.length:
-                cdata[n] = '\x00'
-        else:
-            raise self._convert_error("list or tuple", w_ob)
-
-    def convert_to_object(self, cdata):
-        return cdataobj.W_CData(self.space, cdata, self)
-
-    def add(self, cdata, i):
-        p = rffi.ptradd(cdata, i * self.ctitem.size)
-        return cdataobj.W_CData(self.space, p, self.ctptr)
-
-
-class W_CTypePrimitive(W_CType):
-
-    def __init__(self, space, size, name, name_position, align):
-        W_CType.__init__(self, space, size, name, name_position)
-        self.align = align
-
-    def extra_repr(self, cdata):
-        w_ob = self.convert_to_object(cdata)
-        return self.space.str_w(self.space.repr(w_ob))
-
-    def _alignof(self):
-        return self.align
-
-    def cast_str(self, w_ob):
-        space = self.space
-        s = space.str_w(w_ob)
-        if len(s) != 1:
-            raise operationerrfmt(space.w_TypeError,
-                              "cannot cast string of length %d to ctype '%s'",
-                                  len(s), self.name)
-        return ord(s[0])
-
-    def cast(self, w_ob):
-        space = self.space
-        ob = space.interpclass_w(w_ob)
-        if (isinstance(ob, cdataobj.W_CData) and
-               isinstance(ob.ctype, W_CTypePtrOrArray)):
-            value = rffi.cast(lltype.Signed, ob._cdata)
-        elif space.isinstance_w(w_ob, space.w_str):
-            value = self.cast_str(w_ob)
-        else:
-            value = misc.as_unsigned_long_long(space, w_ob, strict=False)
-        w_cdata = cdataobj.W_CDataOwnFromCasted(space, self.size, self)
-        w_cdata.write_raw_integer_data(value)
-        return w_cdata
-
-    def _overflow(self, w_ob):
-        space = self.space
-        s = space.str_w(space.str(w_ob))
-        raise operationerrfmt(space.w_OverflowError,
-                              "integer %s does not fit '%s'", s, self.name)
-
-
-class W_CTypePrimitiveChar(W_CTypePrimitive):
-    cast_anything = True
-
-    def int(self, cdata):
-        return self.space.wrap(ord(cdata[0]))
-
-    def convert_to_object(self, cdata):
-        return self.space.wrap(cdata[0])
-
-    def str(self, cdataobj):
-        w_res = self.convert_to_object(cdataobj._cdata)
-        keepalive_until_here(cdataobj)
-        return w_res
-
-    def _convert_to_char(self, w_ob):
-        space = self.space
-        if space.isinstance_w(w_ob, space.w_str):
-            s = space.str_w(w_ob)
-            if len(s) == 1:
-                return s[0]
-        ob = space.interpclass_w(w_ob)
-        if (isinstance(ob, cdataobj.W_CData) and
-               isinstance(ob.ctype, W_CTypePrimitiveChar)):
-            return ob._cdata[0]
-        raise self._convert_error("string of length 1", w_ob)
-
-    def convert_from_object(self, cdata, w_ob):
-        value = self._convert_to_char(w_ob)
-        cdata[0] = value
-
-
-class W_CTypePrimitiveSigned(W_CTypePrimitive):
-
-    def __init__(self, *args):
-        W_CTypePrimitive.__init__(self, *args)
-        self.value_fits_long = self.size <= rffi.sizeof(lltype.Signed)
-        if self.size < rffi.sizeof(lltype.SignedLongLong):
-            sh = self.size * 8
-            self.vmin = r_ulonglong(-1) << (sh - 1)
-            self.vrangemax = (r_ulonglong(1) << sh) - 1
-
-    def int(self, cdata):
-        if self.value_fits_long:
-            # this case is to handle enums, but also serves as a slight
-            # performance improvement for some other primitive types
-            value = intmask(misc.read_raw_signed_data(cdata, self.size))
-            return self.space.wrap(value)
-        else:
-            return self.convert_to_object(cdata)
-
-    def convert_to_object(self, cdata):
-        value = misc.read_raw_signed_data(cdata, self.size)
-        if self.value_fits_long:
-            return self.space.wrap(intmask(value))
-        else:
-            return self.space.wrap(value)    # r_longlong => on 32-bit, 'long'
-
-    def convert_from_object(self, cdata, w_ob):
-        value = misc.as_long_long(self.space, w_ob)
-        if self.size < rffi.sizeof(lltype.SignedLongLong):
-            if r_ulonglong(value) - self.vmin > self.vrangemax:
-                self._overflow(w_ob)
-        misc.write_raw_integer_data(cdata, value, self.size)
-
-
-class W_CTypePrimitiveUnsigned(W_CTypePrimitive):
-
-    def __init__(self, *args):
-        W_CTypePrimitive.__init__(self, *args)
-        self.value_fits_long = self.size < rffi.sizeof(lltype.Signed)
-        if self.size < rffi.sizeof(lltype.SignedLongLong):
-            sh = self.size * 8
-            self.vrangemax = (r_ulonglong(1) << sh) - 1
-
-    def int(self, cdata):
-        return self.convert_to_object(cdata)
-
-    def convert_from_object(self, cdata, w_ob):
-        value = misc.as_unsigned_long_long(self.space, w_ob, strict=True)
-        if self.size < rffi.sizeof(lltype.SignedLongLong):
-            if value > self.vrangemax:
-                self._overflow(w_ob)
-        misc.write_raw_integer_data(cdata, value, self.size)
-
-    def convert_to_object(self, cdata):
-        value = misc.read_raw_unsigned_data(cdata, self.size)
-        if self.value_fits_long:
-            return self.space.wrap(intmask(value))
-        else:
-            return self.space.wrap(value)    # r_ulonglong => 'long' object
-
-
-class W_CTypePrimitiveFloat(W_CTypePrimitive):
-
-    def cast(self, w_ob):
-        space = self.space
-        ob = space.interpclass_w(w_ob)
-        if isinstance(ob, cdataobj.W_CData):
-            if not isinstance(ob.ctype, W_CTypePrimitive):
-                raise operationerrfmt(space.w_TypeError,
-                                      "cannot cast ctype '%s' to ctype '%s'",
-                                      ob.ctype.name, self.name)
-            w_ob = ob.convert_to_object()
-        #
-        if space.isinstance_w(w_ob, space.w_str):
-            value = self.cast_str(w_ob)
-        else:
-            value = space.float_w(w_ob)
-        w_cdata = cdataobj.W_CDataOwnFromCasted(space, self.size, self)
-        w_cdata.write_raw_float_data(value)
-        return w_cdata
-
-    def int(self, cdata):
-        w_value = self.float(cdata)
-        return self.space.int(w_value)
-
-    def float(self, cdata):
-        return self.convert_to_object(cdata)
-
-    def convert_to_object(self, cdata):
-        value = misc.read_raw_float_data(cdata, self.size)
-        return self.space.wrap(value)
-
-    def convert_from_object(self, cdata, w_ob):
-        space = self.space
-        value = space.float_w(space.float(w_ob))
-        misc.write_raw_float_data(cdata, value, self.size)
-
-
-class W_CTypeEnum(W_CTypePrimitiveSigned):
-
-    def __init__(self, space, name, enumerators, enumvalues):
-        from pypy.module._ffi_backend.newtype import alignment
-        name = "enum " + name
-        size = rffi.sizeof(rffi.INT)
-        align = alignment(rffi.INT)
-        W_CTypePrimitiveSigned.__init__(self, space, size,
-                                        name, len(name), align)
-        self.enumerators2values = {}   # str -> int
-        self.enumvalues2erators = {}   # int -> str
-        for i in range(len(enumerators)):
-            self.enumerators2values[enumerators[i]] = enumvalues[i]
-            self.enumvalues2erators[enumvalues[i]] = enumerators[i]
-
-    def _getfields(self):
-        space = self.space
-        lst = []
-        for enumerator in self.enumerators2values:
-            enumvalue = self.enumerators2values[enumerator]
-            lst.append(space.newtuple([space.wrap(enumvalue),
-                                       space.wrap(enumerator)]))
-        w_lst = space.newlist(lst)
-        space.call_method(w_lst, 'sort')
-        return w_lst
-
-    def str(self, cdataobj):
-        w_res = self.convert_to_object(cdataobj._cdata)
-        keepalive_until_here(cdataobj)
-        return w_res
-
-    def convert_to_object(self, cdata):
-        value = intmask(misc.read_raw_signed_data(cdata, self.size))
-        try:
-            enumerator = self.enumvalues2erators[value]
-        except KeyError:
-            enumerator = '#%d' % (value,)
-        return self.space.wrap(enumerator)
-
-    def convert_from_object(self, cdata, w_ob):
-        space = self.space
-        try:
-            return W_CTypePrimitiveSigned.convert_from_object(self, cdata,
-                                                              w_ob)
-        except OperationError, e:
-            if not e.match(space, space.w_TypeError):
-                raise
-        if space.isinstance_w(w_ob, space.w_str):
-            value = self.convert_enum_string_to_int(space.str_w(w_ob))
-            misc.write_raw_integer_data(cdata, value, self.size)
-        else:
-            raise self._convert_error("str or int", w_ob)
-
-    def cast_str(self, w_ob):
-        space = self.space
-        return self.convert_enum_string_to_int(space.str_w(w_ob))
-
-    def convert_enum_string_to_int(self, s):
-        space = self.space
-        if s.startswith('#'):
-            try:
-                return int(s[1:])     # xxx is it RPython?
-            except ValueError:
-                raise OperationError(space.w_ValueError,
-                                     space.wrap("invalid literal after '#'"))
-        else:
-            try:
-                return self.enumerators2values[s]
-            except KeyError:
-                raise operationerrfmt(space.w_ValueError,
-                                      "'%s' is not an enumerator for %s",
-                                      s, self.name)
-
-
-class W_CTypeStructOrUnion(W_CType):
-    # fields added by complete_struct_or_union():
-    alignment = -1
-    fields_list = None
-    fields_dict = None
-
-    def __init__(self, space, name):
-        name = '%s %s' % (self.kind, name)
-        W_CType.__init__(self, space, -1, name, len(name))
-
-    def check_complete(self):
-        if self.fields_dict is None:
-            space = self.space
-            raise operationerrfmt(space.w_TypeError,
-                                  "'%s' is not completed yet", self.name)
-
-    def _alignof(self):
-        self.check_complete()
-        return self.alignment
-
-    def _getfields(self):
-        if self.size < 0:
-            return None
-        space = self.space
-        result = [None] * len(self.fields_list)
-        for fname, field in self.fields_dict.iteritems():
-            i = self.fields_list.index(field)
-            result[i] = space.newtuple([space.wrap(fname),
-                                        space.wrap(field)])
-        return space.newlist(result)
-
-    def convert_to_object(self, cdata):
-        space = self.space
-        self.check_complete()
-        return cdataobj.W_CData(space, cdata, self)
-
-    def offsetof(self, fieldname):
-        self.check_complete()
-        try:
-            cfield = self.fields_dict[fieldname]
-        except KeyError:
-            space = self.space
-            raise OperationError(space.w_KeyError, space.wrap(fieldname))
-        return cfield.offset
-
-    def _copy_from_same(self, cdata, w_ob):
-        space = self.space
-        ob = space.interpclass_w(w_ob)
-        if isinstance(ob, cdataobj.W_CData):
-            if ob.ctype is self and self.size >= 0:
-                # push push push at the llmemory interface (with hacks that
-                # are all removed after translation)
-                zero = llmemory.itemoffsetof(rffi.CCHARP.TO, 0)
-                llmemory.raw_memcopy(
-                    llmemory.cast_ptr_to_adr(ob._cdata) + zero,
-                    llmemory.cast_ptr_to_adr(cdata) + zero,
-                    self.size * llmemory.sizeof(lltype.Char))
-                keepalive_until_here(ob)
-                return True
-        return False
-
-
-class W_CTypeStruct(W_CTypeStructOrUnion):
-    kind = "struct"
-
-    def convert_from_object(self, cdata, w_ob):
-        space = self.space
-        if self._copy_from_same(cdata, w_ob):
-            return
-
-        if (space.isinstance_w(w_ob, space.w_list) or
-            space.isinstance_w(w_ob, space.w_tuple)):
-            lst_w = space.listview(w_ob)
-            if len(lst_w) > len(self.fields_list):
-                raise operationerrfmt(space.w_ValueError,
-                        "too many initializers for '%s' (got %d)",
-                                      self.name, len(lst_w))
-            for i in range(len(lst_w)):
-                self.fields_list[i].write(cdata, lst_w[i])
-
-        elif space.isinstance_w(w_ob, space.w_dict):
-            lst_w = space.fixedview(w_ob)
-            for i in range(len(lst_w)):
-                w_key = lst_w[i]
-                key = space.str_w(w_key)
-                try:
-                    cf = self.fields_dict[key]
-                except KeyError:
-                    space.raise_key_error(w_key)
-                    assert 0
-                cf.write(cdata, space.getitem(w_ob, w_key))
-
-        else:
-            raise self._convert_error("list or tuple or dict or struct-cdata",
-                                      w_ob)
-
-
-class W_CTypeUnion(W_CTypeStructOrUnion):
-    kind = "union"
-
-    def convert_from_object(self, cdata, w_ob):
-        space = self.space
-        if self._copy_from_same(cdata, w_ob):
-            return
-        if not self.fields_list:
-            raise OperationError(space.w_ValueError,
-                                 space.wrap("empty union"))
-        self.fields_list[0].write(cdata, w_ob)
-
-
-class W_CTypeVoid(W_CType):
-    cast_anything = True
-
-    def __init__(self, space):
-        W_CType.__init__(self, space, -1, "void", len("void"))
-
-
-class W_CField(Wrappable):
-    _immutable_ = True
-    def __init__(self, ctype, offset, bitshift, bitsize):
-        self.ctype = ctype
-        self.offset = offset
-        self.bitshift = bitshift
-        self.bitsize = bitsize
-
-    def read(self, cdata):
-        cdata = rffi.ptradd(cdata, self.offset)
-        if self.bitshift >= 0:
-            xxx
-        else:
-            return self.ctype.convert_to_object(cdata)
-
-    def write(self, cdata, w_ob):
-        cdata = rffi.ptradd(cdata, self.offset)
-        if self.bitshift >= 0:
-            xxx
-        else:
-            self.ctype.convert_from_object(cdata, w_ob)
-
-
 W_CType.typedef = TypeDef(
     '_ffi_backend.CTypeDescr',
     __repr__ = interp2app(W_CType.repr),
     __weakref__ = make_weakref_descr(W_CType),
     )
 W_CType.typedef.acceptable_as_base_class = False
-
-W_CField.typedef = TypeDef(
-    '_ffi_backend.CField',
-    type = interp_attrproperty('ctype', W_CField),
-    offset = interp_attrproperty('offset', W_CField),
-    bitshift = interp_attrproperty('bitshift', W_CField),
-    bitsize = interp_attrproperty('bitsize', W_CField),
-    )
-W_CField.typedef.acceptable_as_base_class = False
diff --git a/pypy/module/_ffi_backend/ctypeprim.py b/pypy/module/_ffi_backend/ctypeprim.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi_backend/ctypeprim.py
@@ -0,0 +1,184 @@
+"""
+Primitives.
+"""
+
+from pypy.interpreter.error import operationerrfmt
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rlib.rarithmetic import intmask, r_ulonglong
+from pypy.rlib.objectmodel import keepalive_until_here
+
+from pypy.module._ffi_backend.ctypeobj import W_CType
+from pypy.module._ffi_backend import cdataobj, misc
+
+
+class W_CTypePrimitive(W_CType):
+
+    def __init__(self, space, size, name, name_position, align):
+        W_CType.__init__(self, space, size, name, name_position)
+        self.align = align
+
+    def extra_repr(self, cdata):
+        w_ob = self.convert_to_object(cdata)
+        return self.space.str_w(self.space.repr(w_ob))
+
+    def _alignof(self):
+        return self.align
+
+    def cast_str(self, w_ob):
+        space = self.space
+        s = space.str_w(w_ob)
+        if len(s) != 1:
+            raise operationerrfmt(space.w_TypeError,
+                              "cannot cast string of length %d to ctype '%s'",
+                                  len(s), self.name)
+        return ord(s[0])
+
+    def cast(self, w_ob):
+        from pypy.module._ffi_backend import ctypeptr
+        space = self.space
+        ob = space.interpclass_w(w_ob)
+        if (isinstance(ob, cdataobj.W_CData) and
+               isinstance(ob.ctype, ctypeptr.W_CTypePtrOrArray)):
+            value = rffi.cast(lltype.Signed, ob._cdata)
+        elif space.isinstance_w(w_ob, space.w_str):
+            value = self.cast_str(w_ob)
+        else:
+            value = misc.as_unsigned_long_long(space, w_ob, strict=False)
+        w_cdata = cdataobj.W_CDataOwnFromCasted(space, self.size, self)
+        w_cdata.write_raw_integer_data(value)
+        return w_cdata
+
+    def _overflow(self, w_ob):
+        space = self.space
+        s = space.str_w(space.str(w_ob))
+        raise operationerrfmt(space.w_OverflowError,
+                              "integer %s does not fit '%s'", s, self.name)
+
+
+class W_CTypePrimitiveChar(W_CTypePrimitive):
+    cast_anything = True
+
+    def int(self, cdata):
+        return self.space.wrap(ord(cdata[0]))
+
+    def convert_to_object(self, cdata):
+        return self.space.wrap(cdata[0])
+
+    def str(self, cdataobj):
+        w_res = self.convert_to_object(cdataobj._cdata)
+        keepalive_until_here(cdataobj)
+        return w_res
+
+    def _convert_to_char(self, w_ob):
+        space = self.space
+        if space.isinstance_w(w_ob, space.w_str):
+            s = space.str_w(w_ob)
+            if len(s) == 1:
+                return s[0]
+        ob = space.interpclass_w(w_ob)
+        if (isinstance(ob, cdataobj.W_CData) and
+               isinstance(ob.ctype, W_CTypePrimitiveChar)):
+            return ob._cdata[0]
+        raise self._convert_error("string of length 1", w_ob)
+
+    def convert_from_object(self, cdata, w_ob):
+        value = self._convert_to_char(w_ob)
+        cdata[0] = value
+
+
+class W_CTypePrimitiveSigned(W_CTypePrimitive):
+
+    def __init__(self, *args):
+        W_CTypePrimitive.__init__(self, *args)
+        self.value_fits_long = self.size <= rffi.sizeof(lltype.Signed)
+        if self.size < rffi.sizeof(lltype.SignedLongLong):
+            sh = self.size * 8
+            self.vmin = r_ulonglong(-1) << (sh - 1)
+            self.vrangemax = (r_ulonglong(1) << sh) - 1
+
+    def int(self, cdata):
+        if self.value_fits_long:
+            # this case is to handle enums, but also serves as a slight
+            # performance improvement for some other primitive types
+            value = intmask(misc.read_raw_signed_data(cdata, self.size))
+            return self.space.wrap(value)
+        else:
+            return self.convert_to_object(cdata)
+
+    def convert_to_object(self, cdata):
+        value = misc.read_raw_signed_data(cdata, self.size)
+        if self.value_fits_long:
+            return self.space.wrap(intmask(value))
+        else:
+            return self.space.wrap(value)    # r_longlong => on 32-bit, 'long'
+
+    def convert_from_object(self, cdata, w_ob):
+        value = misc.as_long_long(self.space, w_ob)
+        if self.size < rffi.sizeof(lltype.SignedLongLong):
+            if r_ulonglong(value) - self.vmin > self.vrangemax:
+                self._overflow(w_ob)
+        misc.write_raw_integer_data(cdata, value, self.size)
+
+
+class W_CTypePrimitiveUnsigned(W_CTypePrimitive):
+
+    def __init__(self, *args):
+        W_CTypePrimitive.__init__(self, *args)
+        self.value_fits_long = self.size < rffi.sizeof(lltype.Signed)
+        if self.size < rffi.sizeof(lltype.SignedLongLong):
+            sh = self.size * 8
+            self.vrangemax = (r_ulonglong(1) << sh) - 1
+
+    def int(self, cdata):
+        return self.convert_to_object(cdata)
+
+    def convert_from_object(self, cdata, w_ob):
+        value = misc.as_unsigned_long_long(self.space, w_ob, strict=True)
+        if self.size < rffi.sizeof(lltype.SignedLongLong):
+            if value > self.vrangemax:
+                self._overflow(w_ob)
+        misc.write_raw_integer_data(cdata, value, self.size)
+
+    def convert_to_object(self, cdata):
+        value = misc.read_raw_unsigned_data(cdata, self.size)
+        if self.value_fits_long:
+            return self.space.wrap(intmask(value))
+        else:
+            return self.space.wrap(value)    # r_ulonglong => 'long' object
+
+
+class W_CTypePrimitiveFloat(W_CTypePrimitive):
+
+    def cast(self, w_ob):
+        space = self.space
+        ob = space.interpclass_w(w_ob)
+        if isinstance(ob, cdataobj.W_CData):
+            if not isinstance(ob.ctype, W_CTypePrimitive):
+                raise operationerrfmt(space.w_TypeError,
+                                      "cannot cast ctype '%s' to ctype '%s'",
+                                      ob.ctype.name, self.name)
+            w_ob = ob.convert_to_object()
+        #
+        if space.isinstance_w(w_ob, space.w_str):
+            value = self.cast_str(w_ob)
+        else:
+            value = space.float_w(w_ob)
+        w_cdata = cdataobj.W_CDataOwnFromCasted(space, self.size, self)
+        w_cdata.write_raw_float_data(value)
+        return w_cdata
+
+    def int(self, cdata):
+        w_value = self.float(cdata)
+        return self.space.int(w_value)
+
+    def float(self, cdata):
+        return self.convert_to_object(cdata)
+
+    def convert_to_object(self, cdata):
+        value = misc.read_raw_float_data(cdata, self.size)
+        return self.space.wrap(value)
+
+    def convert_from_object(self, cdata, w_ob):
+        space = self.space
+        value = space.float_w(space.float(w_ob))
+        misc.write_raw_float_data(cdata, value, self.size)
diff --git a/pypy/module/_ffi_backend/ctypeptr.py b/pypy/module/_ffi_backend/ctypeptr.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi_backend/ctypeptr.py
@@ -0,0 +1,112 @@
+"""
+Pointers.
+"""
+
+from pypy.interpreter.error import operationerrfmt
+from pypy.rpython.lltypesystem import rffi
+from pypy.rlib.objectmodel import keepalive_until_here
+
+from pypy.module._ffi_backend.ctypeobj import W_CType
+from pypy.module._ffi_backend.ctypeprim import W_CTypePrimitiveChar
+from pypy.module._ffi_backend import cdataobj, misc
+
+
+class W_CTypePtrOrArray(W_CType):
+
+    def __init__(self, space, size, extra, extra_position, ctitem):
+        name, name_position = ctitem.insert_name(extra, extra_position)
+        W_CType.__init__(self, space, size, name, name_position)
+        self.ctitem = ctitem
+
+
+class W_CTypePointer(W_CTypePtrOrArray):
+
+    def __init__(self, space, ctitem):
+        size = rffi.sizeof(rffi.VOIDP)
+        from pypy.module._ffi_backend import ctypearray
+        if isinstance(ctitem, ctypearray.W_CTypeArray):
+            extra = "(*)"    # obscure case: see test_array_add
+        else:
+            extra = " *"
+        W_CTypePtrOrArray.__init__(self, space, size, extra, 2, ctitem)
+
+    def str(self, cdataobj):
+        if isinstance(self.ctitem, W_CTypePrimitiveChar):
+            if not cdataobj._cdata:
+                space = self.space
+                raise operationerrfmt(space.w_RuntimeError,
+                                      "cannot use str() on %s",
+                                      space.str_w(cdataobj.repr()))
+            s = rffi.charp2str(cdataobj._cdata)
+            keepalive_until_here(cdataobj)
+            return self.space.wrap(s)
+        return W_CTypePtrOrArray.str(self, cdataobj)
+
+    def cast(self, w_ob):
+        space = self.space
+        ob = space.interpclass_w(w_ob)
+        if (isinstance(ob, cdataobj.W_CData) and
+                isinstance(ob.ctype, W_CTypePtrOrArray)):
+            value = ob._cdata
+        else:
+            value = misc.as_unsigned_long_long(space, w_ob, strict=False)
+            value = rffi.cast(rffi.CCHARP, value)
+        return cdataobj.W_CData(space, value, self)
+
+    def newp(self, w_init):
+        from pypy.module._ffi_backend import ctypeprim
+        space = self.space
+        ctitem = self.ctitem
+        datasize = ctitem.size
+        if datasize < 0:
+            raise operationerrfmt(space.w_TypeError,
+                "cannot instantiate ctype '%s' of unknown size",
+                                  self.name)
+        if isinstance(ctitem, W_CTypePrimitiveChar):
+            datasize *= 2       # forcefully add a null character
+        cdata = cdataobj.W_CDataOwn(space, datasize, self)
+        if not space.is_w(w_init, space.w_None):
+            ctitem.convert_from_object(cdata._cdata, w_init)
+            keepalive_until_here(cdata)
+        return cdata
+
+    def _check_subscript_index(self, w_cdata, i):
+        if isinstance(w_cdata, cdataobj.W_CDataOwn) and i != 0:
+            space = self.space
+            raise operationerrfmt(space.w_IndexError,
+                                  "cdata '%s' can only be indexed by 0",
+                                  self.name)
+
+    def add(self, cdata, i):
+        space = self.space
+        ctitem = self.ctitem
+        if ctitem.size < 0:
+            raise operationerrfmt(space.w_TypeError,
+                                  "ctype '%s' points to items of unknown size",
+                                  self.name)
+        p = rffi.ptradd(cdata, i * self.ctitem.size)
+        return cdataobj.W_CData(space, p, self)
+
+    def _alignof(self):
+        from pypy.module._ffi_backend import newtype
+        return newtype.alignment_of_pointer
+
+    def convert_to_object(self, cdata):
+        ptrdata = rffi.cast(rffi.CCHARPP, cdata)[0]
+        return cdataobj.W_CData(self.space, ptrdata, self)
+
+    def convert_from_object(self, cdata, w_ob):
+        space = self.space
+        ob = space.interpclass_w(w_ob)
+        if not isinstance(ob, cdataobj.W_CData):
+            raise self._convert_error("compatible pointer", w_ob)
+        otherctype = ob.ctype
+        if (isinstance(otherctype, W_CTypePtrOrArray) and
+            (self.ctitem.cast_anything or
+             otherctype.ctitem.cast_anything or
+             self.ctitem is otherctype.ctitem)):
+            pass    # compatible types
+        else:
+            raise self._convert_error("compatible pointer", w_ob)
+
+        rffi.cast(rffi.CCHARPP, cdata)[0] = ob._cdata
diff --git a/pypy/module/_ffi_backend/ctypestruct.py b/pypy/module/_ffi_backend/ctypestruct.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi_backend/ctypestruct.py
@@ -0,0 +1,157 @@
+"""
+Struct and unions.
+"""
+
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.typedef import TypeDef, interp_attrproperty
+from pypy.rlib.objectmodel import keepalive_until_here
+
+from pypy.module._ffi_backend.ctypeobj import W_CType
+from pypy.module._ffi_backend import cdataobj
+
+
+class W_CTypeStructOrUnion(W_CType):
+    # fields added by complete_struct_or_union():
+    alignment = -1
+    fields_list = None
+    fields_dict = None
+
+    def __init__(self, space, name):
+        name = '%s %s' % (self.kind, name)
+        W_CType.__init__(self, space, -1, name, len(name))
+
+    def check_complete(self):
+        if self.fields_dict is None:
+            space = self.space
+            raise operationerrfmt(space.w_TypeError,
+                                  "'%s' is not completed yet", self.name)
+
+    def _alignof(self):
+        self.check_complete()
+        return self.alignment
+
+    def _getfields(self):
+        if self.size < 0:
+            return None
+        space = self.space
+        result = [None] * len(self.fields_list)
+        for fname, field in self.fields_dict.iteritems():
+            i = self.fields_list.index(field)
+            result[i] = space.newtuple([space.wrap(fname),
+                                        space.wrap(field)])
+        return space.newlist(result)
+
+    def convert_to_object(self, cdata):
+        space = self.space
+        self.check_complete()
+        return cdataobj.W_CData(space, cdata, self)
+
+    def offsetof(self, fieldname):
+        self.check_complete()
+        try:
+            cfield = self.fields_dict[fieldname]
+        except KeyError:
+            space = self.space
+            raise OperationError(space.w_KeyError, space.wrap(fieldname))
+        return cfield.offset
+
+    def _copy_from_same(self, cdata, w_ob):
+        space = self.space
+        ob = space.interpclass_w(w_ob)
+        if isinstance(ob, cdataobj.W_CData):
+            if ob.ctype is self and self.size >= 0:
+                # push push push at the llmemory interface (with hacks that
+                # are all removed after translation)
+                zero = llmemory.itemoffsetof(rffi.CCHARP.TO, 0)
+                llmemory.raw_memcopy(
+                    llmemory.cast_ptr_to_adr(ob._cdata) + zero,
+                    llmemory.cast_ptr_to_adr(cdata) + zero,
+                    self.size * llmemory.sizeof(lltype.Char))
+                keepalive_until_here(ob)
+                return True
+        return False
+
+
+class W_CTypeStruct(W_CTypeStructOrUnion):
+    kind = "struct"
+
+    def convert_from_object(self, cdata, w_ob):
+        space = self.space
+        if self._copy_from_same(cdata, w_ob):
+            return
+
+        if (space.isinstance_w(w_ob, space.w_list) or
+            space.isinstance_w(w_ob, space.w_tuple)):
+            lst_w = space.listview(w_ob)
+            if len(lst_w) > len(self.fields_list):
+                raise operationerrfmt(space.w_ValueError,
+                        "too many initializers for '%s' (got %d)",
+                                      self.name, len(lst_w))
+            for i in range(len(lst_w)):
+                self.fields_list[i].write(cdata, lst_w[i])
+
+        elif space.isinstance_w(w_ob, space.w_dict):
+            lst_w = space.fixedview(w_ob)
+            for i in range(len(lst_w)):
+                w_key = lst_w[i]
+                key = space.str_w(w_key)
+                try:
+                    cf = self.fields_dict[key]
+                except KeyError:
+                    space.raise_key_error(w_key)
+                    assert 0
+                cf.write(cdata, space.getitem(w_ob, w_key))
+
+        else:
+            raise self._convert_error("list or tuple or dict or struct-cdata",
+                                      w_ob)
+
+
+class W_CTypeUnion(W_CTypeStructOrUnion):
+    kind = "union"
+
+    def convert_from_object(self, cdata, w_ob):
+        space = self.space
+        if self._copy_from_same(cdata, w_ob):
+            return
+        if not self.fields_list:
+            raise OperationError(space.w_ValueError,
+                                 space.wrap("empty union"))
+        self.fields_list[0].write(cdata, w_ob)
+
+
+
+class W_CField(Wrappable):
+    _immutable_ = True
+    def __init__(self, ctype, offset, bitshift, bitsize):
+        self.ctype = ctype
+        self.offset = offset
+        self.bitshift = bitshift
+        self.bitsize = bitsize
+
+    def read(self, cdata):
+        cdata = rffi.ptradd(cdata, self.offset)
+        if self.bitshift >= 0:
+            xxx
+        else:
+            return self.ctype.convert_to_object(cdata)
+
+    def write(self, cdata, w_ob):
+        cdata = rffi.ptradd(cdata, self.offset)
+        if self.bitshift >= 0:
+            xxx
+        else:
+            self.ctype.convert_from_object(cdata, w_ob)
+
+
+
+W_CField.typedef = TypeDef(
+    '_ffi_backend.CField',
+    type = interp_attrproperty('ctype', W_CField),
+    offset = interp_attrproperty('offset', W_CField),
+    bitshift = interp_attrproperty('bitshift', W_CField),
+    bitsize = interp_attrproperty('bitsize', W_CField),
+    )
+W_CField.typedef.acceptable_as_base_class = False
diff --git a/pypy/module/_ffi_backend/ctypevoid.py b/pypy/module/_ffi_backend/ctypevoid.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi_backend/ctypevoid.py
@@ -0,0 +1,12 @@
+"""
+Void.
+"""
+
+from pypy.module._ffi_backend.ctypeobj import W_CType
+
+
+class W_CTypeVoid(W_CType):
+    cast_anything = True
+
+    def __init__(self, space):
+        W_CType.__init__(self, space, -1, "void", len("void"))
diff --git a/pypy/module/_ffi_backend/newtype.py b/pypy/module/_ffi_backend/newtype.py
--- a/pypy/module/_ffi_backend/newtype.py
+++ b/pypy/module/_ffi_backend/newtype.py
@@ -3,7 +3,8 @@
 from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.rlib.rarithmetic import ovfcheck
 
-from pypy.module._ffi_backend import ctypeobj
+from pypy.module._ffi_backend import ctypeobj, ctypeprim, ctypeptr, ctypearray
+from pypy.module._ffi_backend import ctypestruct, ctypevoid, ctypeenum
 
 
 def alignment(TYPE):
@@ -20,19 +21,19 @@
 def eptype(name, TYPE, ctypecls):
     PRIMITIVE_TYPES[name] = ctypecls, rffi.sizeof(TYPE), alignment(TYPE)
 
-eptype("char",        lltype.Char,     ctypeobj.W_CTypePrimitiveChar)
-eptype("signed char", rffi.SIGNEDCHAR, ctypeobj.W_CTypePrimitiveSigned)
-eptype("short",       rffi.SHORT,      ctypeobj.W_CTypePrimitiveSigned)
-eptype("int",         rffi.INT,        ctypeobj.W_CTypePrimitiveSigned)
-eptype("long",        rffi.LONG,       ctypeobj.W_CTypePrimitiveSigned)
-eptype("long long",   rffi.LONGLONG,   ctypeobj.W_CTypePrimitiveSigned)
-eptype("unsigned char",      rffi.UCHAR,    ctypeobj.W_CTypePrimitiveUnsigned)
-eptype("unsigned short",     rffi.SHORT,    ctypeobj.W_CTypePrimitiveUnsigned)
-eptype("unsigned int",       rffi.INT,      ctypeobj.W_CTypePrimitiveUnsigned)
-eptype("unsigned long",      rffi.LONG,     ctypeobj.W_CTypePrimitiveUnsigned)
-eptype("unsigned long long", rffi.LONGLONG, ctypeobj.W_CTypePrimitiveUnsigned)
-eptype("float",  rffi.FLOAT,  ctypeobj.W_CTypePrimitiveFloat)
-eptype("double", rffi.DOUBLE, ctypeobj.W_CTypePrimitiveFloat)
+eptype("char",        lltype.Char,     ctypeprim.W_CTypePrimitiveChar)
+eptype("signed char", rffi.SIGNEDCHAR, ctypeprim.W_CTypePrimitiveSigned)
+eptype("short",       rffi.SHORT,      ctypeprim.W_CTypePrimitiveSigned)
+eptype("int",         rffi.INT,        ctypeprim.W_CTypePrimitiveSigned)
+eptype("long",        rffi.LONG,       ctypeprim.W_CTypePrimitiveSigned)
+eptype("long long",   rffi.LONGLONG,   ctypeprim.W_CTypePrimitiveSigned)
+eptype("unsigned char",      rffi.UCHAR,    ctypeprim.W_CTypePrimitiveUnsigned)
+eptype("unsigned short",     rffi.SHORT,    ctypeprim.W_CTypePrimitiveUnsigned)
+eptype("unsigned int",       rffi.INT,      ctypeprim.W_CTypePrimitiveUnsigned)
+eptype("unsigned long",      rffi.LONG,     ctypeprim.W_CTypePrimitiveUnsigned)
+eptype("unsigned long long", rffi.LONGLONG, ctypeprim.W_CTypePrimitiveUnsigned)
+eptype("float",  rffi.FLOAT,  ctypeprim.W_CTypePrimitiveFloat)
+eptype("double", rffi.DOUBLE, ctypeprim.W_CTypePrimitiveFloat)
 
 @unwrap_spec(name=str)
 def new_primitive_type(space, name):
@@ -47,14 +48,14 @@
 
 @unwrap_spec(ctype=ctypeobj.W_CType)
 def new_pointer_type(space, ctype):
-    ctypeptr = ctypeobj.W_CTypePointer(space, ctype)
-    return ctypeptr
+    ctypepointer = ctypeptr.W_CTypePointer(space, ctype)
+    return ctypepointer
 
 # ____________________________________________________________
 
 @unwrap_spec(ctptr=ctypeobj.W_CType)
 def new_array_type(space, ctptr, w_length):
-    if not isinstance(ctptr, ctypeobj.W_CTypePointer):
+    if not isinstance(ctptr, ctypeptr.W_CTypePointer):
         raise OperationError(space.w_TypeError,
                              space.wrap("first arg must be a pointer ctype"))
     ctitem = ctptr.ctitem
@@ -78,29 +79,29 @@
                 space.wrap("array size would overflow a ssize_t"))
         extra = '[%d]' % length
     #
-    ctypeptr = ctypeobj.W_CTypeArray(space, ctptr, length, arraysize, extra)
-    return ctypeptr
+    ctype = ctypearray.W_CTypeArray(space, ctptr, length, arraysize, extra)
+    return ctype
 
 # ____________________________________________________________
 
 @unwrap_spec(name=str)
 def new_struct_type(space, name):
-    return ctypeobj.W_CTypeStruct(space, name)
+    return ctypestruct.W_CTypeStruct(space, name)
 
 @unwrap_spec(name=str)
 def new_union_type(space, name):
-    return ctypeobj.W_CTypeUnion(space, name)
+    return ctypestruct.W_CTypeUnion(space, name)
 
 @unwrap_spec(ctype=ctypeobj.W_CType, totalsize=int, totalalignment=int)
 def complete_struct_or_union(space, ctype, w_fields, w_ignored=None,
                              totalsize=-1, totalalignment=-1):
-    if (not isinstance(ctype, ctypeobj.W_CTypeStructOrUnion)
+    if (not isinstance(ctype, ctypestruct.W_CTypeStructOrUnion)
             or ctype.size >= 0):
         raise OperationError(space.w_TypeError,
                              space.wrap("first arg must be a non-initialized"
                                         " struct or union ctype"))
 
-    is_union = isinstance(ctype, ctypeobj.W_CTypeUnion)
+    is_union = isinstance(ctype, ctypestruct.W_CTypeUnion)
     maxsize = 1
     alignment = 1
     offset = 0
@@ -149,7 +150,7 @@
         else:
             xxx
         #
-        fld = ctypeobj.W_CField(ftype, offset, bitshift, fbitsize)
+        fld = ctypestruct.W_CField(ftype, offset, bitshift, fbitsize)
         fields_list.append(fld)
         fields_dict[fname] = fld
         #
@@ -183,7 +184,7 @@
 # ____________________________________________________________
 
 def new_void_type(space):
-    ctype = ctypeobj.W_CTypeVoid(space)
+    ctype = ctypevoid.W_CTypeVoid(space)
     return ctype
 
 # ____________________________________________________________
@@ -197,5 +198,5 @@
                              space.wrap("tuple args must have the same size"))
     enumerators = [space.str_w(w) for w in enumerators_w]
     enumvalues  = [space.int_w(w) for w in enumvalues_w]
-    ctype = ctypeobj.W_CTypeEnum(space, name, enumerators, enumvalues)
+    ctype = ctypeenum.W_CTypeEnum(space, name, enumerators, enumvalues)
     return ctype


More information about the pypy-commit mailing list