Commits

Alex Gaynor committed 596bebb

First pass.

Comments (0)

Files changed (2)

c/_cffi_backend.c

                            CT_PRIMITIVE_CHAR |          \
                            CT_PRIMITIVE_FLOAT)
 
+typedef struct {
+    PyObject_HEAD
+    PyObject *l_ffi;
+    PyObject *l_generic_module;
+    PyObject *l_defines;
+    PyObject *l_property_defines;
+    PyObject *l_weakreflist;
+} FFILibrary;
+
 typedef struct _ctypedescr {
     PyObject_VAR_HEAD
 
 #define BS_REGULAR     (-1)      /* a regular field, not with bitshift */
 #define BS_EMPTY_ARRAY (-2)      /* a field which is an array 'type[0]' */
 
+static PyTypeObject FFILibrary_Type;
 static PyTypeObject CTypeDescr_Type;
 static PyTypeObject CField_Type;
 static PyTypeObject CData_Type;
 
 /************************************************************/
 
+static PyObject *
+ffilibrary_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+    static char *kwlist[] = {"generic_module", "ffi", NULL};
+    PyObject *generic_module = NULL;
+    PyObject *ffi = NULL;
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO", kwlist,
+                                     &generic_module, &ffi))
+        return NULL;
+    FFILibrary *lib = PyObject_GC_New(FFILibrary, &FFILibrary_Type);
+    if (lib == NULL)
+        return NULL;
+    Py_INCREF(ffi);
+    lib->l_ffi = ffi;
+    Py_INCREF(generic_module);
+    lib->l_generic_module = generic_module;
+    lib->l_weakreflist = NULL;
+    lib->l_defines = PyDict_New();
+    if (lib->l_defines == NULL)
+        return NULL;
+    lib->l_property_defines = PyDict_New();
+    if (lib->l_property_defines == NULL)
+        return NULL;
+    PyObject_GC_Track(lib);
+    return lib;
+}
+
+static PyObject *
+ffilibrary_define(FFILibrary *self, PyObject *args)
+{
+    PyObject *name = NULL;
+    PyObject *value = NULL;
+    if (!PyArg_ParseTuple(args, "SO:define", &name, &value))
+        return NULL;
+    int res = PyDict_Contains(self->l_defines, name);
+    if (res == -1)
+        return NULL;
+    if (res == 1)
+        PyErr_Format(PyExc_ValueError, "%s was already defined",
+            PyString_AS_STRING(name)
+        );
+        return NULL;
+    res = PyDict_Contains(self->l_property_defines, name);
+    if (res == -1)
+        return NULL;
+    if (res == 1)
+        PyErr_Format(PyExc_ValueError, "%s was already defined as a property",
+            PyString_AS_STRING(name)
+        );
+        return NULL;
+    res = PyDict_SetItem(self->l_defines, name, value);
+    if (res == -1)
+        return NULL;
+    Py_RETURN_NONE;
+}
+
+static int
+ffilibrary_traverse(FFILibrary *self, visitproc visit, void *arg)
+{
+    Py_VISIT(self->l_generic_module);
+    Py_VISIT(self->l_ffi);
+    return 0;
+}
+
 static CTypeDescrObject *
 ctypedescr_new(int name_size)
 {
 
 static PyObject *cdata_iter(CDataObject *);
 
+#undef OFF
+#define OFF(x) offsetof(FFILibrary, x)
+
+static PyMemberDef ffilibrary_members[] = {
+    {"_cffi_generic_module", T_OBJECT, OFF(l_generic_module), READONLY},
+    {NULL}      /* Sentinel */
+};
+#undef OFF
+
+static PyMethodDef ffilibrary_methods[] = {
+    {"define", ffilibrary_define, METH_VARARGS, NULL},
+    {NULL},
+};
+
+static PyTypeObject FFILibrary_Type = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "_cffi_backend.FFILibrary",
+    sizeof(FFILibrary),
+    0,
+    0,                                          /* tp_dealloc */
+    0,                                          /* tp_print */
+    0,                                          /* tp_getattr */
+    0,                                          /* tp_setattr */
+    0,                                          /* tp_compare */
+    0,                                          /* tp_repr */
+    0,                                          /* tp_as_number */
+    0,                                          /* tp_as_sequence */
+    0,                                          /* tp_as_mapping */
+    0,                                          /* tp_hash */
+    0,                                          /* tp_call */
+    0,                                          /* tp_str */
+    0,                                          /* tp_getattro */
+    0,                                          /* tp_setattro */
+    0,                                          /* tp_as_buffer */
+    Py_TPFLAGS_DEFAULT,                         /* tp_flags */
+    0,                                          /* tp_doc */
+    (traverseproc)ffilibrary_traverse,          /* tp_traverse */
+    0,                                          /* tp_clear */
+    0,                                          /* tp_richcompare */
+    offsetof(FFILibrary, l_weakreflist),        /* tp_weaklistoffset */
+    0,                                          /* tp_iter */
+    0,                                          /* tp_iternext */
+    ffilibrary_methods,                         /* tp_methods */
+    ffilibrary_members,                         /* tp_members */
+};
+
 static PyNumberMethods CData_as_number = {
     (binaryfunc)cdata_add,      /*nb_add*/
     (binaryfunc)cdata_sub,      /*nb_subtract*/
 
     if (m == NULL)
         INITERROR;
+
+    FFILibrary_Type.tp_new = ffilibrary_new;
+
     if (PyType_Ready(&dl_type) < 0)
         INITERROR;
+    if (PyType_Ready(&FFILibrary_Type) < 0)
+        INITERROR;
     if (PyType_Ready(&CTypeDescr_Type) < 0)
         INITERROR;
     if (PyType_Ready(&CField_Type) < 0)
     if (v == NULL || PyModule_AddObject(m, "__version__", v) < 0)
         INITERROR;
 
+    Py_INCREF(&FFILibrary_Type);
+    if (PyModule_AddObject(m, "FFILibrary", (PyObject *)&FFILibrary_Type) < 0)
+        INITERROR;
+
     if (PyModule_AddIntConstant(m, "FFI_DEFAULT_ABI", FFI_DEFAULT_ABI) < 0 ||
 #if defined(MS_WIN32) && !defined(_WIN64)
         PyModule_AddIntConstant(m, "FFI_STDCALL", FFI_STDCALL) < 0 ||

cffi/vengine_gen.py

         # call loading_gen_struct() to get the struct layout inferred by
         # the C compiler
         self._load(module, 'loading')
-        #
-        # build the FFILibrary class and instance
-        class FFILibrary(object):
-            _cffi_generic_module = module
-            _cffi_ffi = self.ffi
-        library = FFILibrary()
+        library = backend.FFILibrary(generic_module=module, ffi=self.ffi)
         #
         # finally, call the loaded_gen_xxx() functions.  This will set
         # up the 'library' object.
             newfunction = module.load_function(BFunc, wrappername)
             for i, type in indirections:
                 newfunction = self._make_struct_wrapper(newfunction, i, type)
-        setattr(library, name, newfunction)
+        library.define(name, newfunction)
 
     def _make_struct_wrapper(self, oldfunc, i, tp):
         backend = self.ffi._backend
     def _loaded_gen_constant(self, tp, name, module, library):
         is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type()
         value = self._load_constant(is_int, tp, name, module)
-        setattr(library, name, value)
+        library.define(name, value)
 
     # ----------
     # enums
 
     def _loaded_gen_enum(self, tp, name, module, library):
         for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
-            setattr(library, enumerator, enumvalue)
+            library.define(enumerator, enumvalue)
 
     # ----------
     # macros: for now only for integers
 
     def _loaded_gen_macro(self, tp, name, module, library):
         value = self._load_constant(True, tp, name, module)
-        setattr(library, name, value)
+        library.define(name, value)
 
     # ----------
     # global variables
         BFunc = self.ffi.typeof(tp.get_c_name('*(*)(void)', name))
         function = module.load_function(BFunc, funcname)
         ptr = function()
+
         def getter(library):
             return ptr[0]
+
         def setter(library, value):
             ptr[0] = value
-        setattr(library.__class__, name, property(getter, setter))
+        library.define_property(name, getter, setter)
 
 cffimod_header = r'''
 #include <stdio.h>