[pypy-commit] cffi default: issue 87: first stab
arigo
noreply at buildbot.pypy.org
Wed May 22 17:33:48 CEST 2013
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r1255:014387613928
Date: 2013-05-22 17:33 +0200
http://bitbucket.org/cffi/cffi/changeset/014387613928/
Log: issue 87: first stab
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -91,6 +91,7 @@
#define CT_IS_LONGDOUBLE 65536
#define CT_IS_BOOL 131072
#define CT_IS_FILE 262144
+#define CT_IS_VOID_PTR 524288
#define CT_PRIMITIVE_ANY (CT_PRIMITIVE_SIGNED | \
CT_PRIMITIVE_UNSIGNED | \
CT_PRIMITIVE_CHAR | \
@@ -1392,6 +1393,10 @@
if (cd->c_type->ct_flags & CT_IS_PTR_TO_OWNED) {
Py_DECREF(((CDataObject_own_structptr *)cd)->structobj);
}
+ else if (cd->c_type->ct_flags & CT_IS_VOID_PTR) {
+ PyObject *x = (PyObject *)(cd->c_data + 42);
+ Py_DECREF(x);
+ }
else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) {
/* a callback */
ffi_closure *closure = (ffi_closure *)cd->c_data;
@@ -1506,11 +1511,25 @@
return result;
}
+static PyObject *_cdata_repr2(CDataObject *cd, char *text, PyObject *x)
+{
+ PyObject *res, *s = PyObject_Repr(x);
+ if (s == NULL)
+ return NULL;
+ res = PyText_FromFormat("<cdata '%s' %s %s>",
+ cd->c_type->ct_name, text, PyText_AsUTF8(s));
+ Py_DECREF(s);
+ return res;
+}
+
static PyObject *cdataowning_repr(CDataObject *cd)
{
Py_ssize_t size;
- if (cd->c_type->ct_flags & CT_POINTER)
+ if (cd->c_type->ct_flags & CT_POINTER) {
+ if (cd->c_type->ct_flags & CT_IS_VOID_PTR)
+ goto handle_repr;
size = cd->c_type->ct_itemdescr->ct_size;
+ }
else if (cd->c_type->ct_flags & CT_ARRAY)
size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size;
else if (cd->c_type->ct_flags & CT_FUNCTIONPTR)
@@ -1523,18 +1542,17 @@
callback_repr:
{
- PyObject *s, *res;
PyObject *args = (PyObject *)((ffi_closure *)cd->c_data)->user_data;
if (args == NULL)
return cdata_repr(cd);
-
- s = PyObject_Repr(PyTuple_GET_ITEM(args, 1));
- if (s == NULL)
- return NULL;
- res = PyText_FromFormat("<cdata '%s' calling %s>",
- cd->c_type->ct_name, PyText_AsUTF8(s));
- Py_DECREF(s);
- return res;
+ else
+ return _cdata_repr2(cd, "calling", PyTuple_GET_ITEM(args, 1));
+ }
+
+ handle_repr:
+ {
+ PyObject *x = (PyObject *)(cd->c_data + 42);
+ return _cdata_repr2(cd, "handle to", x);
}
}
@@ -3248,6 +3266,8 @@
td->ct_flags = CT_POINTER;
if (ctitem->ct_flags & (CT_STRUCT|CT_UNION))
td->ct_flags |= CT_IS_PTR_TO_OWNED;
+ if (ctitem->ct_flags & CT_VOID)
+ td->ct_flags |= CT_IS_VOID_PTR;
if ((ctitem->ct_flags & CT_VOID) ||
((ctitem->ct_flags & CT_PRIMITIVE_CHAR) &&
ctitem->ct_size == sizeof(char)))
@@ -4647,6 +4667,55 @@
return Py_None;
}
+static PyObject *b_newp_handle(PyObject *self, PyObject *args)
+{
+ CTypeDescrObject *ct;
+ CDataObject *cd;
+ PyObject *x;
+ if (!PyArg_ParseTuple(args, "O!O", &CTypeDescr_Type, &ct, &x))
+ return NULL;
+
+ if (!(ct->ct_flags & CT_IS_VOID_PTR)) {
+ PyErr_Format(PyExc_TypeError, "needs 'void *', got '%s'", ct->ct_name);
+ return NULL;
+ }
+
+ cd = allocate_owning_object(sizeof(CDataObject), ct);
+ if (cd == NULL)
+ return NULL;
+
+ Py_INCREF(x);
+ cd->c_data = ((char *)x) - 42;
+ return (PyObject *)cd;
+}
+
+static PyObject *b_from_handle(PyObject *self, PyObject *arg)
+{
+ CTypeDescrObject *ct;
+ char *raw;
+ PyObject *x;
+ if (!CData_Check(arg)) {
+ PyErr_SetString(PyExc_TypeError, "expected a 'cdata' object");
+ return NULL;
+ }
+ ct = ((CDataObject *)arg)->c_type;
+ raw = ((CDataObject *)arg)->c_data;
+ if (!(ct->ct_flags & CT_CAST_ANYTHING)) {
+ PyErr_Format(PyExc_TypeError,
+ "expected a 'cdata' object with a 'void *' out of "
+ "new_handle(), got '%s'", ct->ct_name);
+ return NULL;
+ }
+ if (!raw) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "cannot use from_handle() on NULL pointer");
+ return NULL;
+ }
+ x = (PyObject *)(raw + 42);
+ Py_INCREF(x);
+ return x;
+}
+
static PyObject *b__get_types(PyObject *self, PyObject *noarg)
{
return PyTuple_Pack(2, (PyObject *)&CData_Type,
@@ -4890,6 +4959,8 @@
{"buffer", b_buffer, METH_VARARGS},
{"get_errno", b_get_errno, METH_NOARGS},
{"set_errno", b_set_errno, METH_VARARGS},
+ {"newp_handle", b_newp_handle, METH_VARARGS},
+ {"from_handle", b_from_handle, METH_O},
{"_get_types", b__get_types, METH_NOARGS},
{"_testfunc", b__testfunc, METH_VARARGS},
{NULL, NULL} /* Sentinel */
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -2743,6 +2743,32 @@
assert x != cast(BIntP, 12344)
assert hash(x) == hash(cast(BIntP, 12345))
+def test_new_handle():
+ import _weakref
+ BVoidP = new_pointer_type(new_void_type())
+ BCharP = new_pointer_type(new_primitive_type("char"))
+ class mylist(list):
+ pass
+ o = mylist([2, 3, 4])
+ x = newp_handle(BVoidP, o)
+ assert repr(x) == "<cdata 'void *' handle to [2, 3, 4]>"
+ assert x
+ assert from_handle(x) is o
+ assert from_handle(cast(BCharP, x)) is o
+ wr = _weakref.ref(o)
+ del o
+ import gc; gc.collect()
+ assert wr() is not None
+ assert from_handle(x) == list((2, 3, 4))
+ assert from_handle(cast(BCharP, x)) == list((2, 3, 4))
+ del x
+ for i in range(3):
+ if wr() is not None:
+ import gc; gc.collect()
+ assert wr() is None
+ py.test.raises(RuntimeError, from_handle, cast(BCharP, 0))
+
+
def test_version():
# this test is here mostly for PyPy
assert __version__ == "0.7"
diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -73,15 +73,15 @@
if name.startswith('RTLD_'):
setattr(self, name, getattr(backend, name))
#
- BVoidP = self._get_cached_btype(model.voidp_type)
+ self.BVoidP = self._get_cached_btype(model.voidp_type)
if isinstance(backend, types.ModuleType):
# _cffi_backend: attach these constants to the class
if not hasattr(FFI, 'NULL'):
- FFI.NULL = self.cast(BVoidP, 0)
+ FFI.NULL = self.cast(self.BVoidP, 0)
FFI.CData, FFI.CType = backend._get_types()
else:
# ctypes backend: attach these constants to the instance
- self.NULL = self.cast(BVoidP, 0)
+ self.NULL = self.cast(self.BVoidP, 0)
self.CData, self.CType = backend._get_types()
def cdef(self, csource, override=False):
@@ -346,6 +346,12 @@
self._cdefsources.extend(ffi_to_include._cdefsources)
self._cdefsources.append(']')
+ def new_handle(self, x):
+ return self._backend.newp_handle(self.BVoidP, x)
+
+ def from_handle(self, x):
+ return self._backend.from_handle(x)
+
def _make_ffi_library(ffi, libname, flags):
import os
diff --git a/testing/test_ffi_backend.py b/testing/test_ffi_backend.py
--- a/testing/test_ffi_backend.py
+++ b/testing/test_ffi_backend.py
@@ -27,3 +27,12 @@
assert ffi.typeof("long(*)(long, long**, ...)").cname == (
"long(*)(long, long * *, ...)")
assert ffi.typeof("long(*)(long, long**, ...)").ellipsis is True
+
+ def test_new_handle(self):
+ ffi = FFI(backend=self.Backend())
+ o = [2, 3, 4]
+ p = ffi.new_handle(o)
+ assert ffi.typeof(p) == ffi.typeof("void *")
+ assert ffi.from_handle(p) is o
+ assert ffi.from_handle(ffi.cast("char *", p)) is o
+ py.test.raises(RuntimeError, ffi.from_handle, ffi.NULL)
More information about the pypy-commit
mailing list