[pypy-commit] creflect default: copy loads of code from _cffi_backend.c

arigo noreply at buildbot.pypy.org
Fri Dec 5 12:24:41 CET 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r158:64bc5e56d01a
Date: 2014-12-05 12:24 +0100
http://bitbucket.org/cffi/creflect/changeset/64bc5e56d01a/

Log:	copy loads of code from _cffi_backend.c

diff --git a/zeffir/builder.c b/zeffir/builder.c
--- a/zeffir/builder.c
+++ b/zeffir/builder.c
@@ -288,9 +288,12 @@
     return ct;
 }
 
-static _crx_type_t *zef_get_array_type(_crx_builder_t *cb, _crx_type_t *ctitem,
-                                       size_t len)
+static _crx_type_t *_zef_array_type(_crx_builder_t *cb, _crx_type_t *ctitem,
+                                    size_t len, CTypeDescrObject *ctptr)
 {
+    /* this function is called with different sets of non-NULL arguments
+       from various functions (just afterwards)
+    */
     if (PyErr_Occurred())
         return NULL;
 
@@ -315,9 +318,11 @@
     if (name_obj == NULL)
         return NULL;
 
-    ct = get_cached_type(cb, name_obj);
-    if (ct && (ct->ct_flags & CT_ARRAY))
-        goto done;
+    if (cb != NULL) {
+        ct = get_cached_type(cb, name_obj);
+        if (ct && (ct->ct_flags & CT_ARRAY))
+            goto done;
+    }
 
     if (length < 0) {
         arraysize = -1;
@@ -331,6 +336,12 @@
         }
     }
 
+    if (ctptr == NULL) {
+        ctptr = zef_get_pointer_type(cb, ctitem, 0);
+        if (PyErr_Occurred())
+            goto done;
+    }
+
     ct = ctypedescr_new(name_obj, ctitem->ct_name_position);
     if (ct == NULL)
         goto done;
@@ -338,18 +349,43 @@
     ct->ct_size = arraysize;
     ct->ct_length = length;
     ct->ct_flags = CT_ARRAY;
+    Py_INCREF(ctptr);
+    ct->ct_stuff = (PyObject *)ctptr;
 
-    put_cached_type(cb, name_obj, ct);
+    if (cb != NULL) {
+        if (length < 0 && ctptr->ct_stuff == NULL) {
+            Py_INCREF(ct);
+            ctptr->ct_stuff = (PyObject *)ct;
+        }
+        put_cached_type(cb, name_obj, ct);
+    }
+    else {
+        assert(length < 0);
+        assert(ctptr->ct_stuff == NULL);
+        ctptr->ct_stuff = (PyObject *)ct;
+    }
 
  done:
     Py_DECREF(name_obj);
     return ct;
 }
 
+static int fill_array_type(CTypeDescrObject *ctptr)
+{
+    _zef_array_type(NULL, ctptr->ct_itemdescr, (size_t)-1, ctptr);
+    return PyErr_Occurred() ? -1 : 0;
+}
+
+static _crx_type_t *zef_get_array_type(_crx_builder_t *cb, _crx_type_t *ctitem,
+                                       size_t len)
+{
+    return _zef_array_type(cb, ctitem, len, NULL);
+}
+
 static _crx_type_t *zef_get_incomplete_array_type(_crx_builder_t *cb,
                                                   _crx_type_t *ctitem)
 {
-    return zef_get_array_type(cb, ctitem, (size_t)-1);
+    return _zef_array_type(cb, ctitem, (size_t)-1, NULL);
 }
 
 static _crx_type_t *zef_get_struct_type(_crx_builder_t *cb, const char *name)
diff --git a/zeffir/cdata.c b/zeffir/cdata.c
--- a/zeffir/cdata.c
+++ b/zeffir/cdata.c
@@ -6,6 +6,17 @@
     PyObject *c_weakreflist;
 } CDataObject;
 
+struct cfieldobject_s {
+    PyObject_HEAD
+    CTypeDescrObject *cf_type;
+    Py_ssize_t cf_offset;
+    short cf_bitshift;   /* >= 0: bitshift; or BS_REGULAR or BS_EMPTY_ARRAY */
+    short cf_bitsize;
+    struct cfieldobject_s *cf_next;
+};
+#define BS_REGULAR     (-1)      /* a regular field, not with bitshift */
+#define BS_EMPTY_ARRAY (-2)      /* a field which is an array 'type[0]' */
+
 typedef union {
     unsigned char m_char;
     unsigned short m_short;
@@ -39,7 +50,763 @@
 #define CDataOwn_Check(ob)    (Py_TYPE(ob) == &CDataOwning_Type ||      \
                                Py_TYPE(ob) == &CDataOwningGC_Type)
 
+/************************************************************/
 
+static int
+CDataObject_Or_PyFloat_Check(PyObject *ob)
+{
+    return (PyFloat_Check(ob) ||
+            (CData_Check(ob) &&
+             (((CDataObject *)ob)->c_type->ct_flags & CT_PRIMITIVE_FLOAT)));
+}
+
+static PY_LONG_LONG
+_my_PyLong_AsLongLong(PyObject *ob)
+{
+    /* (possibly) convert and cast a Python object to a long long.
+       Like PyLong_AsLongLong(), this version accepts a Python int too, and
+       does convertions from other types of objects.  The difference is that
+       this version refuses floats. */
+#if PY_MAJOR_VERSION < 3
+    if (PyInt_Check(ob)) {
+        return PyInt_AS_LONG(ob);
+    }
+    else 
+#endif
+    if (PyLong_Check(ob)) {
+        return PyLong_AsLongLong(ob);
+    }
+    else {
+        PyObject *io;
+        PY_LONG_LONG res;
+        PyNumberMethods *nb = ob->ob_type->tp_as_number;
+
+        if (CDataObject_Or_PyFloat_Check(ob) ||
+                nb == NULL || nb->nb_int == NULL) {
+            PyErr_SetString(PyExc_TypeError, "an integer is required");
+            return -1;
+        }
+        io = (*nb->nb_int) (ob);
+        if (io == NULL)
+            return -1;
+
+        if (PyIntOrLong_Check(io)) {
+            res = _my_PyLong_AsLongLong(io);
+        }
+        else {
+            PyErr_SetString(PyExc_TypeError, "integer conversion failed");
+            res = -1;
+        }
+        Py_DECREF(io);
+        return res;
+    }
+}
+
+static unsigned PY_LONG_LONG
+_my_PyLong_AsUnsignedLongLong(PyObject *ob, int strict)
+{
+    /* (possibly) convert and cast a Python object to an unsigned long long.
+       Like PyLong_AsLongLong(), this version accepts a Python int too, and
+       does convertions from other types of objects.  If 'strict', complains
+       with OverflowError and refuses floats.  If '!strict', rounds floats
+       and masks the result. */
+#if PY_MAJOR_VERSION < 3
+    if (PyInt_Check(ob)) {
+        long value1 = PyInt_AS_LONG(ob);
+        if (strict && value1 < 0)
+            goto negative;
+        return (unsigned PY_LONG_LONG)(PY_LONG_LONG)value1;
+    }
+    else
+#endif
+    if (PyLong_Check(ob)) {
+        if (strict) {
+            if (_PyLong_Sign(ob) < 0)
+                goto negative;
+            return PyLong_AsUnsignedLongLong(ob);
+        }
+        else {
+            return PyLong_AsUnsignedLongLongMask(ob);
+        }
+    }
+    else {
+        PyObject *io;
+        unsigned PY_LONG_LONG res;
+        PyNumberMethods *nb = ob->ob_type->tp_as_number;
+
+        if ((strict && CDataObject_Or_PyFloat_Check(ob)) ||
+                nb == NULL || nb->nb_int == NULL) {
+            PyErr_SetString(PyExc_TypeError, "an integer is required");
+            return (unsigned PY_LONG_LONG)-1;
+        }
+        io = (*nb->nb_int) (ob);
+        if (io == NULL)
+            return (unsigned PY_LONG_LONG)-1;
+
+        if (PyIntOrLong_Check(io)) {
+            res = _my_PyLong_AsUnsignedLongLong(io, strict);
+        }
+        else {
+            PyErr_SetString(PyExc_TypeError, "integer conversion failed");
+            res = (unsigned PY_LONG_LONG)-1;
+        }
+        Py_DECREF(io);
+        return res;
+    }
+
+ negative:
+    PyErr_SetString(PyExc_OverflowError,
+                    "can't convert negative number to unsigned");
+    return (unsigned PY_LONG_LONG)-1;
+}
+
+#define _read_raw_data(type)                    \
+    do {                                        \
+        if (size == sizeof(type)) {             \
+            type r;                             \
+            memcpy(&r, target, sizeof(type));   \
+            return r;                           \
+        }                                       \
+    } while(0)
+
+static PY_LONG_LONG
+read_raw_signed_data(char *target, int size)
+{
+    _read_raw_data(signed char);
+    _read_raw_data(short);
+    _read_raw_data(int);
+    _read_raw_data(long);
+    _read_raw_data(PY_LONG_LONG);
+    Py_FatalError("read_raw_signed_data: bad integer size");
+    return 0;
+}
+
+static unsigned PY_LONG_LONG
+read_raw_unsigned_data(char *target, int size)
+{
+    _read_raw_data(unsigned char);
+    _read_raw_data(unsigned short);
+    _read_raw_data(unsigned int);
+    _read_raw_data(unsigned long);
+    _read_raw_data(unsigned PY_LONG_LONG);
+    Py_FatalError("read_raw_unsigned_data: bad integer size");
+    return 0;
+}
+
+#define _write_raw_data(type)                           \
+    do {                                                \
+        if (size == sizeof(type)) {                     \
+            type r = (type)source;                      \
+            memcpy(target, &r, sizeof(type));           \
+            return;                                     \
+        }                                               \
+    } while(0)
+
+static void
+write_raw_integer_data(char *target, unsigned PY_LONG_LONG source, int size)
+{
+    _write_raw_data(unsigned char);
+    _write_raw_data(unsigned short);
+    _write_raw_data(unsigned int);
+    _write_raw_data(unsigned long);
+    _write_raw_data(unsigned PY_LONG_LONG);
+    Py_FatalError("write_raw_integer_data: bad integer size");
+}
+
+static double
+read_raw_float_data(char *target, int size)
+{
+    _read_raw_data(float);
+    _read_raw_data(double);
+    Py_FatalError("read_raw_float_data: bad float size");
+    return 0;
+}
+
+static long double
+read_raw_longdouble_data(char *target)
+{
+    int size = sizeof(long double);
+    _read_raw_data(long double);
+    Py_FatalError("read_raw_longdouble_data: bad long double size");
+    return 0;
+}
+
+static void
+write_raw_float_data(char *target, double source, int size)
+{
+    _write_raw_data(float);
+    _write_raw_data(double);
+    Py_FatalError("write_raw_float_data: bad float size");
+}
+
+static void
+write_raw_longdouble_data(char *target, long double source)
+{
+    int size = sizeof(long double);
+    _write_raw_data(long double);
+}
+
+static PyObject *
+new_simple_cdata(char *data, CTypeDescrObject *ct)
+{
+    CDataObject *cd = PyObject_New(CDataObject, &CData_Type);
+    if (cd == NULL)
+        return NULL;
+    Py_INCREF(ct);
+    cd->c_data = data;
+    cd->c_type = ct;
+    cd->c_weakreflist = NULL;
+    return (PyObject *)cd;
+}
+
+static CDataObject *_new_casted_primitive(CTypeDescrObject *ct)
+{
+    int dataoffset = offsetof(CDataObject_casted_primitive, alignment);
+    CDataObject *cd = (CDataObject *)PyObject_Malloc(dataoffset + ct->ct_size);
+    if (PyObject_Init((PyObject *)cd, &CData_Type) == NULL)
+        return NULL;
+    Py_INCREF(ct);
+    cd->c_type = ct;
+    cd->c_data = ((char*)cd) + dataoffset;
+    cd->c_weakreflist = NULL;
+    return cd;
+}
+
+//845
+static PyObject *convert_to_object(char *data, CTypeDescrObject *ct)
+{
+    if (!(ct->ct_flags & CT_PRIMITIVE_ANY)) {
+        /* non-primitive types (check done just for performance) */
+        if (ct->ct_flags & CT_POINTER) {
+            char *ptrdata = *(char **)data;
+            /*READ(data, sizeof(char *))*/
+            return new_simple_cdata(ptrdata, ct);
+        }
+        else if (ct->ct_flags & CT_ARRAY) {
+            if (ct->ct_length < 0) {
+                /* we can't return a <cdata 'int[]'> here, because we don't
+                   know the length to give it.  As a compromize, returns
+                   <cdata 'int *'> in this case. */
+                ct = (CTypeDescrObject *)ct->ct_stuff;
+            }
+            return new_simple_cdata(data, ct);
+        }
+        else if (ct->ct_size < 0) {
+            PyErr_Format(PyExc_TypeError, "cdata '%s' is opaque",
+                         ct->ct_name);
+            return NULL;
+        }
+        else if (ct->ct_flags & (CT_STRUCT|CT_UNION)) {
+            return new_simple_cdata(data, ct);
+        }
+    }
+    else if (ct->ct_flags & CT_PRIMITIVE_SIGNED) {
+        PY_LONG_LONG value;
+        /*READ(data, ct->ct_size)*/
+        value = read_raw_signed_data(data, ct->ct_size);
+        if (ct->ct_flags & CT_PRIMITIVE_FITS_LONG)
+            return PyInt_FromLong((long)value);
+        else
+            return PyLong_FromLongLong(value);
+    }
+    else if (ct->ct_flags & CT_PRIMITIVE_UNSIGNED) {
+        unsigned PY_LONG_LONG value;
+        /*READ(data, ct->ct_size)*/
+        value = read_raw_unsigned_data(data, ct->ct_size);
+
+        if (ct->ct_flags & CT_PRIMITIVE_FITS_LONG)
+            return PyInt_FromLong((long)value);
+        else
+            return PyLong_FromUnsignedLongLong(value);
+    }
+    else if (ct->ct_flags & CT_PRIMITIVE_FLOAT) {
+        /*READ(data, ct->ct_size)*/
+        if (!(ct->ct_flags & CT_IS_LONGDOUBLE)) {
+            double value = read_raw_float_data(data, ct->ct_size);
+            return PyFloat_FromDouble(value);
+        }
+        else {
+            long double value = read_raw_longdouble_data(data);
+            CDataObject *cd = _new_casted_primitive(ct);
+            if (cd != NULL)
+                write_raw_longdouble_data(cd->c_data, value);
+            return (PyObject *)cd;
+        }
+    }
+    else if (ct->ct_flags & CT_PRIMITIVE_CHAR) {
+        /*READ(data, ct->ct_size)*/
+        return PyBytes_FromStringAndSize(data, 1);
+    }
+
+    PyErr_Format(PyExc_SystemError,
+                 "convert_to_object: '%s'", ct->ct_name);
+    return NULL;
+}
+
+#if 0
+static PyObject *
+convert_to_object_bitfield(char *data, CFieldObject *cf)
+{
+    CTypeDescrObject *ct = cf->cf_type;
+    /*READ(data, ct->ct_size)*/
+
+    if (ct->ct_flags & CT_PRIMITIVE_SIGNED) {
+        unsigned PY_LONG_LONG value, valuemask, shiftforsign;
+        PY_LONG_LONG result;
+
+        value = (unsigned PY_LONG_LONG)read_raw_signed_data(data, ct->ct_size);
+        valuemask = (1ULL << cf->cf_bitsize) - 1ULL;
+        shiftforsign = 1ULL << (cf->cf_bitsize - 1);
+        value = ((value >> cf->cf_bitshift) + shiftforsign) & valuemask;
+        result = ((PY_LONG_LONG)value) - (PY_LONG_LONG)shiftforsign;
+
+        if (ct->ct_flags & CT_PRIMITIVE_FITS_LONG)
+            return PyInt_FromLong((long)result);
+        else
+            return PyLong_FromLongLong(result);
+    }
+    else {
+        unsigned PY_LONG_LONG value, valuemask;
+
+        value = read_raw_unsigned_data(data, ct->ct_size);
+        valuemask = (1ULL << cf->cf_bitsize) - 1ULL;
+        value = (value >> cf->cf_bitshift) & valuemask;
+
+        if (ct->ct_flags & CT_PRIMITIVE_FITS_LONG)
+            return PyInt_FromLong((long)value);
+        else
+            return PyLong_FromUnsignedLongLong(value);
+    }
+}
+#endif
+
+static int _convert_overflow(PyObject *init, const char *ct_name)
+{
+    PyObject *s;
+    if (PyErr_Occurred())   /* already an exception pending */
+        return -1;
+    s = PyObject_Str(init);
+    if (s == NULL)
+        return -1;
+    PyErr_Format(PyExc_OverflowError, "integer %s does not fit '%s'",
+                 PyText_AS_UTF8(s), ct_name);
+    Py_DECREF(s);
+    return -1;
+}
+
+static int _convert_to_char(PyObject *init)
+{
+    if (PyBytes_Check(init) && PyBytes_GET_SIZE(init) == 1) {
+        return (unsigned char)(PyBytes_AS_STRING(init)[0]);
+    }
+    if (CData_Check(init) &&
+           (((CDataObject *)init)->c_type->ct_flags & CT_PRIMITIVE_CHAR)) {
+        char *data = ((CDataObject *)init)->c_data;
+        /*READ(data, 1)*/
+        return *(unsigned char *)data;
+    }
+    PyErr_Format(PyExc_TypeError,
+                 "initializer for ctype 'char' must be a "STR_OR_BYTES
+                 " of length 1, not %.200s", Py_TYPE(init)->tp_name);
+    return -1;
+}
+
+//1009
+static int _convert_error(PyObject *init, const char *ct_name,
+                          const char *expected)
+{
+    if (CData_Check(init))
+        PyErr_Format(PyExc_TypeError,
+                     "initializer for ctype '%s' must be a %s, "
+                     "not cdata '%s'",
+                     ct_name, expected,
+                     ((CDataObject *)init)->c_type->ct_name);
+    else
+        PyErr_Format(PyExc_TypeError,
+                     "initializer for ctype '%s' must be a %s, "
+                     "not %.200s",
+                     ct_name, expected, Py_TYPE(init)->tp_name);
+    return -1;
+}
+
+//1031
+static Py_ssize_t get_new_array_length(PyObject **pvalue)
+{
+    PyObject *value = *pvalue;
+
+    if (PyList_Check(value) || PyTuple_Check(value)) {
+        return PySequence_Fast_GET_SIZE(value);
+    }
+    else if (PyBytes_Check(value)) {
+        /* from a string, we add the null terminator */
+        return PyBytes_GET_SIZE(value) + 1;
+    }
+    else {
+        Py_ssize_t explicitlength;
+        explicitlength = PyNumber_AsSsize_t(value, PyExc_OverflowError);
+        if (explicitlength < 0) {
+            if (!PyErr_Occurred())
+                PyErr_SetString(PyExc_ValueError, "negative array length");
+            return -1;
+        }
+        *pvalue = Py_None;
+        return explicitlength;
+    }
+}
+
+//1061
+static int convert_field_from_object(char *data, CFieldObject *cf,
+                                     PyObject *value)
+{
+    data += cf->cf_offset;
+    if (cf->cf_bitshift >= 0)
+        return convert_from_object_bitfield(data, cf, value);
+    else
+        return convert_from_object(data, cf->cf_type, value);
+}
+
+//1071
+static int convert_vfield_from_object(char *data, CFieldObject *cf,
+                                      PyObject *value, Py_ssize_t *optvarsize)
+{
+    /* a special case for var-sized C99 arrays */
+    if ((cf->cf_type->ct_flags & CT_ARRAY) && cf->cf_type->ct_size < 0) {
+        Py_ssize_t varsizelength = get_new_array_length(&value);
+        if (varsizelength < 0)
+            return -1;
+        if (optvarsize != NULL) {
+            /* in this mode, the only purpose of this function is to compute
+               the real size of the structure from a var-sized C99 array */
+            Py_ssize_t size, itemsize;
+            assert(data == NULL);
+            itemsize = cf->cf_type->ct_itemdescr->ct_size;
+            size = cf->cf_offset + itemsize * varsizelength;
+            if (size < 0 ||
+                ((size - cf->cf_offset) / itemsize) != varsizelength) {
+                PyErr_SetString(PyExc_OverflowError,
+                                "array size would overflow a Py_ssize_t");
+                return -1;
+            }
+            if (size > *optvarsize)
+                *optvarsize = size;
+            return 0;
+        }
+        /* if 'value' was only an integer, get_new_array_length() returns
+           it and convert 'value' to be None.  Detect if this was the case,
+           and if so, stop here, leaving the content uninitialized
+           (it should be zero-initialized from somewhere else). */
+        if (value == Py_None)
+            return 0;
+    }
+    if (optvarsize == NULL)
+        return convert_field_from_object(data, cf, value);
+    else
+        return 0;
+}
+
+//1110
+static int convert_array_from_object(char *data, CTypeDescrObject *ct,
+                                     PyObject *init)
+{
+    /* used by convert_from_object(), and also to decode lists/tuples/unicodes
+       passed as function arguments.  'ct' is an CT_ARRAY in the first case
+       and a CT_POINTER in the second case. */
+    const char *expected;
+    CTypeDescrObject *ctitem = ct->ct_itemdescr;
+
+    if (PyList_Check(init) || PyTuple_Check(init)) {
+        PyObject **items;
+        Py_ssize_t i, n;
+        n = PySequence_Fast_GET_SIZE(init);
+        if (ct->ct_length >= 0 && n > ct->ct_length) {
+            PyErr_Format(PyExc_IndexError,
+                         "too many initializers for '%s' (got %zd)",
+                         ct->ct_name, n);
+            return -1;
+        }
+        items = PySequence_Fast_ITEMS(init);
+        for (i=0; i<n; i++) {
+            if (convert_from_object(data, ctitem, items[i]) < 0)
+                return -1;
+            data += ctitem->ct_size;
+        }
+        return 0;
+    }
+    else if ((ctitem->ct_flags & (CT_PRIMITIVE_CHAR |
+                                  CT_PRIMITIVE_SIGNED |
+                                  CT_PRIMITIVE_UNSIGNED))
+             && (ctitem->ct_size == sizeof(char))) {
+        char *srcdata;
+        Py_ssize_t n;
+        if (!PyBytes_Check(init)) {
+            expected = STR_OR_BYTES" or list or tuple";
+            goto cannot_convert;
+        }
+        n = PyBytes_GET_SIZE(init);
+        if (ct->ct_length >= 0 && n > ct->ct_length) {
+            PyErr_Format(PyExc_IndexError,
+                         "initializer "STR_OR_BYTES" is too long for '%s' "
+                         "(got %zd characters)", ct->ct_name, n);
+            return -1;
+        }
+        if (n != ct->ct_length)
+            n++;
+        srcdata = PyBytes_AS_STRING(init);
+        memcpy(data, srcdata, n);
+        return 0;
+    }
+    else {
+        expected = "list or tuple";
+        goto cannot_convert;
+    }
+
+ cannot_convert:
+    return _convert_error(init, ct->ct_name, expected);
+}
+
+//1190
+static int convert_struct_from_object(char *data, CTypeDescrObject *ct,
+                                      PyObject *init, Py_ssize_t *optvarsize)
+{
+    const char *expected;
+
+    if (ct->ct_flags & CT_UNION) {
+        Py_ssize_t n = PyObject_Size(init);
+        if (n < 0)
+            return -1;
+        if (n > 1) {
+            PyErr_Format(PyExc_ValueError,
+                         "initializer for '%s': %zd items given, but "
+                         "only one supported (use a dict if needed)",
+                         ct->ct_name, n);
+            return -1;
+        }
+    }
+    if (PyList_Check(init) || PyTuple_Check(init)) {
+        PyObject **items = PySequence_Fast_ITEMS(init);
+        Py_ssize_t i, n = PySequence_Fast_GET_SIZE(init);
+        CFieldObject *cf = (CFieldObject *)ct->ct_extra;
+
+        for (i=0; i<n; i++) {
+            if (cf == NULL) {
+                PyErr_Format(PyExc_ValueError,
+                             "too many initializers for '%s' (got %zd)",
+                             ct->ct_name, n);
+                return -1;
+            }
+            if (convert_vfield_from_object(data, cf, items[i], optvarsize) < 0)
+                return -1;
+            cf = cf->cf_next;
+        }
+        return 0;
+    }
+    if (PyDict_Check(init)) {
+        PyObject *d_key, *d_value;
+        Py_ssize_t i = 0;
+        CFieldObject *cf;
+
+        while (PyDict_Next(init, &i, &d_key, &d_value)) {
+            cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, d_key);
+            if (cf == NULL) {
+                PyErr_SetObject(PyExc_KeyError, d_key);
+                return -1;
+            }
+            if (convert_vfield_from_object(data, cf, d_value, optvarsize) < 0)
+                return -1;
+        }
+        return 0;
+    }
+    expected = optvarsize == NULL ? "list or tuple or dict or struct-cdata"
+                                  : "list or tuple or dict";
+    return _convert_error(init, ct->ct_name, expected);
+}
+
+#ifdef __GNUC__
+# if __GNUC__ >= 4
+/* Don't go inlining this huge function.  Needed because occasionally
+   it gets inlined in places where is causes a warning: call to
+   __builtin___memcpy_chk will always overflow destination buffer
+   (which is places where the 'ct' should never represent such a large
+   primitive type anyway). */
+__attribute__((noinline))
+# endif
+#endif
+//1257
+static int convert_from_object(char *data, CTypeDescrObject *ct, PyObject *init)
+{
+    const char *expected;
+    char buf[sizeof(PY_LONG_LONG)];
+
+    /*if (ct->ct_size > 0)*/
+        /*WRITE(data, ct->ct_size)*/
+
+    if (ct->ct_flags & CT_ARRAY) {
+        return convert_array_from_object(data, ct, init);
+    }
+    if (ct->ct_flags & CT_POINTER) {
+        char *ptrdata;
+        CTypeDescrObject *ctinit;
+
+        if (!CData_Check(init)) {
+            expected = "cdata pointer";
+            goto cannot_convert;
+        }
+        ctinit = ((CDataObject *)init)->c_type;
+        if (!(ctinit->ct_flags & CT_POINTER)) {
+            if (ctinit->ct_flags & CT_ARRAY)
+                ctinit = (CTypeDescrObject *)ctinit->ct_stuff;
+            else {
+                expected = "pointer or array";
+                goto cannot_convert;
+            }
+        }
+        if (ctinit != ct) {
+            if ((ct->ct_flags & CT_CAST_ANYTHING) ||
+                (ctinit->ct_flags & CT_CAST_ANYTHING))
+                ;   /* accept void* or char* as either source or target */
+            else {
+                expected = "pointer to same type";
+                goto cannot_convert;
+            }
+        }
+        ptrdata = ((CDataObject *)init)->c_data;
+
+        *(char **)data = ptrdata;
+        return 0;
+    }
+    if (ct->ct_flags & CT_PRIMITIVE_SIGNED) {
+        PY_LONG_LONG value = _my_PyLong_AsLongLong(init);
+        if (value == -1 && PyErr_Occurred())
+            return -1;
+        write_raw_integer_data(buf, value, ct->ct_size);
+        if (value != read_raw_signed_data(buf, ct->ct_size))
+            goto overflow;
+        write_raw_integer_data(data, value, ct->ct_size);
+        return 0;
+    }
+    if (ct->ct_flags & CT_PRIMITIVE_UNSIGNED) {
+        unsigned PY_LONG_LONG value = _my_PyLong_AsUnsignedLongLong(init, 1);
+        if (value == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred())
+            return -1;
+        if (ct->ct_flags & CT_IS_BOOL)
+            if (value & ~1)      /* value != 0 && value != 1 */
+                goto overflow;
+        write_raw_integer_data(buf, value, ct->ct_size);
+        if (value != read_raw_unsigned_data(buf, ct->ct_size))
+            goto overflow;
+        write_raw_integer_data(data, value, ct->ct_size);
+        return 0;
+    }
+    if (ct->ct_flags & CT_PRIMITIVE_FLOAT) {
+        double value;
+        if ((ct->ct_flags & CT_IS_LONGDOUBLE) &&
+                CData_Check(init) &&
+                (((CDataObject *)init)->c_type->ct_flags & CT_IS_LONGDOUBLE)) {
+            long double lvalue;
+            char *initdata = ((CDataObject *)init)->c_data;
+            /*READ(initdata, sizeof(long double))*/
+            lvalue = read_raw_longdouble_data(initdata);
+            write_raw_longdouble_data(data, lvalue);
+            return 0;
+        }
+        value = PyFloat_AsDouble(init);
+        if (value == -1.0 && PyErr_Occurred())
+            return -1;
+        if (!(ct->ct_flags & CT_IS_LONGDOUBLE))
+            write_raw_float_data(data, value, ct->ct_size);
+        else
+            write_raw_longdouble_data(data, (long double)value);
+        return 0;
+    }
+    if (ct->ct_flags & CT_PRIMITIVE_CHAR) {
+        int res;
+        assert(ct->ct_size == sizeof(char));
+        res = _convert_to_char(init);
+        if (res < 0)
+            return -1;
+        data[0] = res;
+        return 0;
+    }
+    if (ct->ct_flags & (CT_STRUCT|CT_UNION)) {
+
+        if (CData_Check(init)) {
+            if (((CDataObject *)init)->c_type == ct && ct->ct_size >= 0) {
+                memcpy(data, ((CDataObject *)init)->c_data, ct->ct_size);
+                return 0;
+            }
+        }
+        return convert_struct_from_object(data, ct, init, NULL);
+    }
+    PyErr_Format(PyExc_SystemError,
+                 "convert_from_object: '%s'", ct->ct_name);
+    return -1;
+
+ overflow:
+    return _convert_overflow(init, ct->ct_name);
+
+ cannot_convert:
+    return _convert_error(init, ct->ct_name, expected);
+}
+
+//1383
+static int convert_from_object_bitfield(char *data, CFieldObject *cf,
+                                        PyObject *init)
+{
+    CTypeDescrObject *ct = cf->cf_type;
+    PY_LONG_LONG fmin, fmax, value = PyLong_AsLongLong(init);
+    unsigned PY_LONG_LONG rawfielddata, rawvalue, rawmask;
+    if (value == -1 && PyErr_Occurred())
+        return -1;
+
+    if (ct->ct_flags & CT_PRIMITIVE_SIGNED) {
+        fmin = -(1LL << (cf->cf_bitsize-1));
+        fmax = (1LL << (cf->cf_bitsize-1)) - 1LL;
+        if (fmax == 0)
+            fmax = 1;    /* special case to let "int x:1" receive "1" */
+    }
+    else {
+        fmin = 0LL;
+        fmax = (PY_LONG_LONG)((1ULL << cf->cf_bitsize) - 1ULL);
+    }
+    if (value < fmin || value > fmax) {
+        /* phew, PyErr_Format does not support "%lld" in Python 2.6 */
+        PyObject *svalue = NULL, *sfmin = NULL, *sfmax = NULL;
+        PyObject *lfmin = NULL, *lfmax = NULL;
+        svalue = PyObject_Str(init);
+        if (svalue == NULL) goto skip;
+        lfmin = PyLong_FromLongLong(fmin);
+        if (lfmin == NULL) goto skip;
+        sfmin = PyObject_Str(lfmin);
+        if (sfmin == NULL) goto skip;
+        lfmax = PyLong_FromLongLong(fmax);
+        if (lfmax == NULL) goto skip;
+        sfmax = PyObject_Str(lfmax);
+        if (sfmax == NULL) goto skip;
+        PyErr_Format(PyExc_OverflowError,
+                     "value %s outside the range allowed by the "
+                     "bit field width: %s <= x <= %s",
+                     PyText_AS_UTF8(svalue),
+                     PyText_AS_UTF8(sfmin),
+                     PyText_AS_UTF8(sfmax));
+       skip:
+        Py_XDECREF(svalue);
+        Py_XDECREF(sfmin);
+        Py_XDECREF(sfmax);
+        Py_XDECREF(lfmin);
+        Py_XDECREF(lfmax);
+        return -1;
+    }
+
+    rawmask = ((1ULL << cf->cf_bitsize) - 1ULL) << cf->cf_bitshift;
+    rawvalue = ((unsigned PY_LONG_LONG)value) << cf->cf_bitshift;
+    /*WRITE(data, ct->ct_size)*/
+    rawfielddata = read_raw_unsigned_data(data, ct->ct_size);
+    rawfielddata = (rawfielddata & ~rawmask) | (rawvalue & rawmask);
+    write_raw_integer_data(data, rawfielddata, ct->ct_size);
+    return 0;
+}
+
+//1440
 static Py_ssize_t get_array_length(CDataObject *cd)
 {
     if (cd->c_type->ct_length < 0)
@@ -49,6 +816,7 @@
 }
 
 
+//1480
 static void cdata_dealloc(CDataObject *cd)
 {
     if (cd->c_weakreflist != NULL)
@@ -60,6 +828,7 @@
 #endif
 }
 
+//1491
 static void cdataowninggc_dealloc(CDataObject *cd)
 {
     abort();
@@ -83,6 +852,7 @@
 #endif
 }
 
+//1534
 static int cdataowninggc_traverse(CDataObject *cd, visitproc visit, void *arg)
 {
     abort();
@@ -100,6 +870,7 @@
 #endif
 }
 
+//1548
 static int cdataowninggc_clear(CDataObject *cd)
 {
     abort();
@@ -120,6 +891,7 @@
 #endif
 }
 
+//1599
 static PyObject *cdata_repr(CDataObject *cd)
 {
     char *extra;
@@ -174,6 +946,7 @@
     return result;
 }
 
+//1650
 static PyObject *_cdata_repr2(CDataObject *cd, char *text, PyObject *x)
 {
     PyObject *res, *s = PyObject_Repr(x);
@@ -185,6 +958,7 @@
     return res;
 }
 
+//1661
 static PyObject *cdataowning_repr(CDataObject *cd)
 {
     Py_ssize_t size;
@@ -223,6 +997,253 @@
     }
 }
 
+//1815
+static Py_ssize_t cdata_length(CDataObject *cd)
+{
+    if (cd->c_type->ct_flags & CT_ARRAY) {
+        return get_array_length(cd);
+    }
+    PyErr_Format(PyExc_TypeError, "cdata of type '%s' has no len()",
+                 cd->c_type->ct_name);
+    return -1;
+}
+
+//1826
+static char *_cdata_get_indexed_ptr(CDataObject *cd, PyObject *key)
+{
+    Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError);
+    if (i == -1 && PyErr_Occurred())
+        return NULL;
+
+    if (cd->c_type->ct_flags & CT_POINTER) {
+        if (CDataOwn_Check(cd) && i != 0) {
+            PyErr_Format(PyExc_IndexError,
+                         "cdata '%s' can only be indexed by 0",
+                         cd->c_type->ct_name);
+            return NULL;
+        }
+    }
+    else if (cd->c_type->ct_flags & CT_ARRAY) {
+        if (i < 0) {
+            PyErr_SetString(PyExc_IndexError,
+                            "negative index not supported");
+            return NULL;
+        }
+        if (i >= get_array_length(cd)) {
+            PyErr_Format(PyExc_IndexError,
+                         "index too large for cdata '%s' (expected %zd < %zd)",
+                         cd->c_type->ct_name,
+                         i, get_array_length(cd));
+            return NULL;
+        }
+    }
+    else {
+        PyErr_Format(PyExc_TypeError, "cdata of type '%s' cannot be indexed",
+                     cd->c_type->ct_name);
+        return NULL;
+    }
+    return cd->c_data + i * cd->c_type->ct_itemdescr->ct_size;
+}
+
+//1866
+static CTypeDescrObject *
+_cdata_getslicearg(CDataObject *cd, PySliceObject *slice, Py_ssize_t bounds[])
+{
+    Py_ssize_t start, stop;
+    CTypeDescrObject *ct;
+
+    start = PyInt_AsSsize_t(slice->start);
+    if (start == -1 && PyErr_Occurred()) {
+        if (slice->start == Py_None)
+            PyErr_SetString(PyExc_IndexError, "slice start must be specified");
+        return NULL;
+    }
+    stop = PyInt_AsSsize_t(slice->stop);
+    if (stop == -1 && PyErr_Occurred()) {
+        if (slice->stop == Py_None)
+            PyErr_SetString(PyExc_IndexError, "slice stop must be specified");
+        return NULL;
+    }
+    if (slice->step != Py_None) {
+        PyErr_SetString(PyExc_IndexError, "slice with step not supported");
+        return NULL;
+    }
+    if (start > stop) {
+        PyErr_SetString(PyExc_IndexError, "slice start > stop");
+        return NULL;
+    }
+
+    ct = cd->c_type;
+    if (ct->ct_flags & CT_ARRAY) {
+        if (start < 0) {
+            PyErr_SetString(PyExc_IndexError,
+                            "negative index not supported");
+            return NULL;
+        }
+        if (stop > get_array_length(cd)) {
+            PyErr_Format(PyExc_IndexError,
+                         "index too large (expected %zd <= %zd)",
+                         stop, get_array_length(cd));
+            return NULL;
+        }
+        ct = (CTypeDescrObject *)ct->ct_stuff;
+    }
+    else if (!(ct->ct_flags & CT_POINTER)) {
+        PyErr_Format(PyExc_TypeError, "cdata of type '%s' cannot be indexed",
+                     ct->ct_name);
+        return NULL;
+    }
+
+    bounds[0] = start;
+    bounds[1] = stop - start;
+    return ct;
+}
+
+//1919
+static PyObject *cdata_slice(CDataObject *cd, PySliceObject *slice)
+{
+    Py_ssize_t bounds[2];
+    CDataObject_own_length *scd;
+    CTypeDescrObject *ct = _cdata_getslicearg(cd, slice, bounds);
+    if (ct == NULL)
+        return NULL;
+
+    if (ct->ct_stuff == NULL) {
+        if (fill_array_type(ct) < 0)
+            return NULL;
+        assert(ct->ct_stuff != NULL);
+    }
+    ct = (CTypeDescrObject *)ct->ct_stuff;
+
+    scd = (CDataObject_own_length *)PyObject_Malloc(
+              offsetof(CDataObject_own_length, alignment));
+    if (PyObject_Init((PyObject *)scd, &CData_Type) == NULL)
+        return NULL;
+    Py_INCREF(ct);
+    scd->head.c_type = ct;
+    scd->head.c_data = cd->c_data + ct->ct_itemdescr->ct_size * bounds[0];
+    scd->head.c_weakreflist = NULL;
+    scd->length = bounds[1];
+    return (PyObject *)scd;
+}
+
+//1947
+static int cdata_ass_slice(CDataObject *cd, PySliceObject *slice, PyObject *v)
+{
+    Py_ssize_t bounds[2], i, length, itemsize;
+    PyObject *it, *item;
+    PyObject *(*iternext)(PyObject *);
+    char *cdata;
+    int err;
+    CTypeDescrObject *ct = _cdata_getslicearg(cd, slice, bounds);
+    if (ct == NULL)
+        return -1;
+    ct = ct->ct_itemdescr;
+    itemsize = ct->ct_size;
+    cdata = cd->c_data + itemsize * bounds[0];
+    length = bounds[1];
+
+    if (CData_Check(v)) {
+        CTypeDescrObject *ctv = ((CDataObject *)v)->c_type;
+        if ((ctv->ct_flags & CT_ARRAY) && (ctv->ct_itemdescr == ct) &&
+            (get_array_length((CDataObject *)v) == length)) {
+            /* fast path: copying from exactly the correct type */
+            memmove(cdata, ((CDataObject *)v)->c_data, itemsize * length);
+            return 0;
+        }
+    }
+
+    /* A fast path for <char[]>[0:N] = b"somestring", which also adds
+       support for Python 3: otherwise, you get integers while enumerating
+       the string, and you can't set them to characters :-/
+    */
+    if (PyBytes_Check(v) && (ct->ct_flags & CT_PRIMITIVE_CHAR)) {
+        if (PyBytes_GET_SIZE(v) != length) {
+            PyErr_Format(PyExc_ValueError,
+                         "need a string of length %zd, got %zd",
+                         length, PyBytes_GET_SIZE(v));
+            return -1;
+        }
+        memcpy(cdata, PyBytes_AS_STRING(v), length);
+        return 0;
+    }
+
+    it = PyObject_GetIter(v);
+    if (it == NULL)
+        return -1;
+    iternext = *it->ob_type->tp_iternext;
+
+    for (i = 0; i < length; i++) {
+        item = iternext(it);
+        if (item == NULL) {
+            if (!PyErr_Occurred())
+                PyErr_Format(PyExc_ValueError,
+                             "need %zd values to unpack, got %zd",
+                             length, i);
+            goto error;
+        }
+        err = convert_from_object(cdata, ct, item);
+        Py_DECREF(item);
+        if (err < 0)
+            goto error;
+
+        cdata += itemsize;
+    }
+    item = iternext(it);
+    if (item != NULL) {
+        Py_DECREF(item);
+        PyErr_Format(PyExc_ValueError,
+                     "got more than %zd values to unpack", length);
+    }
+ error:
+    Py_DECREF(it);
+    return PyErr_Occurred() ? -1 : 0;
+}
+
+//2044
+static PyObject *cdata_subscript(CDataObject *cd, PyObject *key)
+{
+    char *c;
+    if (PySlice_Check(key))
+        return cdata_slice(cd, (PySliceObject *)key);
+
+    c = _cdata_get_indexed_ptr(cd, key);
+    /* use 'mp_subscript' instead of 'sq_item' because we don't want
+       negative indexes to be corrected automatically */
+    if (c == NULL && PyErr_Occurred())
+        return NULL;
+    return convert_to_object(c, cd->c_type->ct_itemdescr);
+}
+
+//2059
+static int cdata_ass_sub(CDataObject *cd, PyObject *key, PyObject *v)
+{
+    char *c;
+    CTypeDescrObject *ctitem;
+    if (PySlice_Check(key))
+        return cdata_ass_slice(cd, (PySliceObject *)key, v);
+
+    c = _cdata_get_indexed_ptr(cd, key);
+    ctitem = cd->c_type->ct_itemdescr;
+    /* use 'mp_ass_subscript' instead of 'sq_ass_item' because we don't want
+       negative indexes to be corrected automatically */
+    if (c == NULL && PyErr_Occurred())
+        return -1;
+    if (v == NULL) {
+        PyErr_SetString(PyExc_TypeError,
+                        "'del x[n]' not supported for cdata objects");
+        return -1;
+    }
+    return convert_from_object(c, ctitem, v);
+}
+
+
+static PyMappingMethods CData_as_mapping = {
+    (lenfunc)cdata_length, /*mp_length*/
+    (binaryfunc)cdata_subscript, /*mp_subscript*/
+    (objobjargproc)cdata_ass_sub, /*mp_ass_subscript*/
+};
+
 static PyTypeObject CData_Type = {
     PyVarObject_HEAD_INIT(NULL, 0)
     "zeffir.CData",
@@ -236,7 +1257,7 @@
     (reprfunc)cdata_repr,                       /* tp_repr */
     0,//&CData_as_number,                           /* tp_as_number */
     0,                                          /* tp_as_sequence */
-    0,//&CData_as_mapping,                          /* tp_as_mapping */
+    &CData_as_mapping,                          /* tp_as_mapping */
     0,//(hashfunc)cdata_hash,                       /* tp_hash */
     0,//(ternaryfunc)cdata_call,                    /* tp_call */
     0,                                          /* tp_str */
diff --git a/zeffir/ctype.c b/zeffir/ctype.c
--- a/zeffir/ctype.c
+++ b/zeffir/ctype.c
@@ -30,13 +30,12 @@
 
     CTypeDescrObject *ct_itemdescr;    /* ptrs and arrays: the item type */
     PyObject *ct_stuff;                /* structs: dict of the fields
-                                          //arrays: ctypedescr of the ptr type
+                                          arrays: ctypedescr of the ptr type
                                           function: tuple(abi, ctres, ctargs..)
                                           enum: pair {"name":x},{x:"name"}
                                           ptrs: lazily, ctypedescr of array */
-    //void *ct_extra;                    /* structs: first field (not a ref!)
-    //                                      function types: cif_description
-    //                                      primitives: prebuilt "cif" object */
+    void *ct_extra;                    /* structs: first field (not a ref!)
+                                          function types: cif_description */
 
     PyObject *ct_weakreflist;    /* weakref support */
 
@@ -75,7 +74,7 @@
 
 static PyObject *ctypedescr_repr(CTypeDescrObject *ct)
 {
-    return PyString_FromFormat("<ctype '%s'>", ct->ct_name);
+    return PyText_FromFormat("<ctype '%s'>", ct->ct_name);
 }
 
 static void ctypedescr_dealloc(CTypeDescrObject *ct)
diff --git a/zeffir/ffi_obj.c b/zeffir/ffi_obj.c
--- a/zeffir/ffi_obj.c
+++ b/zeffir/ffi_obj.c
@@ -121,12 +121,12 @@
     /* Returns the CTypeDescrObject from the user-supplied 'arg'.
        Does not return a new reference!
     */
-    if ((accept & ACCEPT_STRING) && PyString_Check(arg)) {
+    if ((accept & ACCEPT_STRING) && PyText_Check(arg)) {
         PyObject *x = PyDict_GetItem(ffi->types_dict, arg);
         if (x != NULL && CTypeDescr_Check(x))
             return (CTypeDescrObject *)x;
 
-        CTypeDescrObject *ct = parse_c_decl(ffi, PyString_AS_STRING(arg));
+        CTypeDescrObject *ct = parse_c_decl(ffi, PyText_AS_UTF8(arg));
         if (ct == NULL)
             return NULL;
 
diff --git a/zeffir/lib_obj.c b/zeffir/lib_obj.c
--- a/zeffir/lib_obj.c
+++ b/zeffir/lib_obj.c
@@ -20,9 +20,9 @@
 
 static PyObject *lib_repr(ZefLibObject *lib)
 {
-    return PyString_FromFormat("<zeffir.Lib object for '%.200s'%s>",
-                               lib->l_libname,
-                               lib->l_dl_lib == NULL ? " (closed)" : "");
+    return PyText_FromFormat("<zeffir.Lib object for '%.200s'%s>",
+                             lib->l_libname,
+                             lib->l_dl_lib == NULL ? " (closed)" : "");
 }
 
 static PyObject *lib_findattr(ZefLibObject *lib, PyObject *name)
@@ -40,7 +40,7 @@
                      "lib '%.200s' has no function,"
                      " global variable or constant '%.200s'",
                      lib->l_libname,
-                     PyString_Check(name) ? PyString_AS_STRING(name) : "?");
+                     PyText_Check(name) ? PyText_AS_UTF8(name) : "?");
         return NULL;
     }
     return x;
@@ -83,7 +83,7 @@
 
     PyErr_Format(PyExc_AttributeError,
                  "cannot write to function or constant '%.200s'",
-                 PyString_Check(name) ? PyString_AS_STRING(name) : "?");
+                 PyText_Check(name) ? PyText_AS_UTF8(name) : "?");
     return -1;
 }
 
@@ -152,7 +152,7 @@
         return NULL;
 
     lib->l_dl_lib = NULL;
-    lib->l_libname = PyString_AS_STRING(path);
+    lib->l_libname = PyString_AsString(path);
     Py_INCREF(path);
     lib->l_libname_obj = path;
     lib->l_dict = PyDict_New();
diff --git a/zeffir/py3support.h b/zeffir/py3support.h
new file mode 100644
--- /dev/null
+++ b/zeffir/py3support.h
@@ -0,0 +1,28 @@
+
+#if PY_MAJOR_VERSION >= 3
+# define STR_OR_BYTES "bytes"
+# define PyText_Type PyUnicode_Type
+# define PyText_Check PyUnicode_Check
+# define PyTextAny_Check PyUnicode_Check
+# define PyText_FromFormat PyUnicode_FromFormat
+# define PyText_AsUTF8 _PyUnicode_AsString   /* PyUnicode_AsUTF8 in Py3.3 */
+# define PyText_AS_UTF8 _PyUnicode_AsString
+# define PyText_GetSize PyUnicode_GetSize
+# define PyText_FromString PyUnicode_FromString
+# define PyText_FromStringAndSize PyUnicode_FromStringAndSize
+# define PyText_InternInPlace PyUnicode_InternInPlace
+# define PyIntOrLong_Check PyLong_Check
+#else
+# define STR_OR_BYTES "str"
+# define PyText_Type PyString_Type
+# define PyText_Check PyString_Check
+# define PyTextAny_Check(op) (PyString_Check(op) || PyUnicode_Check(op))
+# define PyText_FromFormat PyString_FromFormat
+# define PyText_AsUTF8 PyString_AsString
+# define PyText_AS_UTF8 PyString_AS_STRING
+# define PyText_GetSize PyString_Size
+# define PyText_FromString PyString_FromString
+# define PyText_FromStringAndSize PyString_FromStringAndSize
+# define PyText_InternInPlace PyString_InternInPlace
+# define PyIntOrLong_Check(op) (PyInt_Check(op) || PyLong_Check(op))
+#endif
diff --git a/zeffir/test/test_cdata.py b/zeffir/test/test_cdata.py
--- a/zeffir/test/test_cdata.py
+++ b/zeffir/test/test_cdata.py
@@ -6,3 +6,10 @@
     ffi = support.new_ffi()
     p = ffi.new("short *")
     assert repr(p) == "<cdata 'short *' owning 2 bytes>"
+
+def test_cdata_read_write():
+    ffi = support.new_ffi()
+    p = ffi.new("short *")
+    assert p[0] == 0
+    p[0] = 43
+    assert p[0] == 43
diff --git a/zeffir/zeffir.c b/zeffir/zeffir.c
--- a/zeffir/zeffir.c
+++ b/zeffir/zeffir.c
@@ -9,6 +9,7 @@
 /* Works by including all other .c files.                   */
 /* Allows all function and global symbols to remain static. */
 
+#include "py3support.h"
 #include "zeffir.h"
 #include "ctype.c"
 #include "cdata.c"
diff --git a/zeffir/zeffir.h b/zeffir/zeffir.h
--- a/zeffir/zeffir.h
+++ b/zeffir/zeffir.h
@@ -1,5 +1,6 @@
 
 typedef struct _crx_type_s CTypeDescrObject;
+typedef struct cfieldobject_s CFieldObject;
 typedef struct ZefLibObject_s ZefLibObject;
 typedef struct ZefFFIObject_s ZefFFIObject;
 
@@ -15,3 +16,8 @@
 static int lib_close(ZefLibObject *);
 static int load_creflect_main(ZefFFIObject *, ZefLibObject *);
 static CTypeDescrObject *parse_c_decl(ZefFFIObject *ffi, const char *str);
+
+static int convert_from_object(char *, CTypeDescrObject *, PyObject *);
+static int convert_from_object_bitfield(char *, CFieldObject *, PyObject *);
+
+static int fill_array_type(CTypeDescrObject *ctptr);


More information about the pypy-commit mailing list