[pybank] Implement support for struct fields



commit 9491dcb53777415e91a137fa4e6076fbc31b4b24
Author: Tomeu Vizoso <tomeu sugarlabs org>
Date:   Fri May 8 11:23:49 2009 +0200

    Implement support for struct fields
---
 bank/bank-argument.c   |   16 ++++--
 bank/bank-info.c       |  127 +++++++++++++++++++++++++++++++++++++++++++++++-
 bank/bank.h            |    2 +-
 bank/btypes.py         |   40 ++++++++++-----
 everything_unittest.py |    6 ++
 5 files changed, 170 insertions(+), 21 deletions(-)

diff --git a/bank/bank-argument.c b/bank/bank-argument.c
index a4265d4..ecd3def 100644
--- a/bank/bank-argument.c
+++ b/bank/bank-argument.c
@@ -23,13 +23,11 @@
 
 
 GArgument
-pyg_argument_from_pyobject(PyObject *object, GIArgInfo *info)
+pyg_argument_from_pyobject(PyObject *object, GITypeInfo *type_info)
 {
-    GITypeInfo *type_info;
     GArgument arg;
     GITypeTag type_tag;
 	
-    type_info = g_arg_info_get_type(info);
     type_tag = g_type_info_get_tag((GITypeInfo*)type_info);
     switch (type_tag) {
     case GI_TYPE_TAG_VOID:
@@ -99,7 +97,6 @@ pyg_argument_from_pyobject(PyObject *object, GIArgInfo *info)
 		g_type_tag_to_string(type_tag));
 	break;
     }
-    g_base_info_unref((GIBaseInfo*)type_info);
     
     return arg;
 }
@@ -132,6 +129,11 @@ pyg_argument_to_pyobject(GArgument *arg, GITypeInfo *type_info)
 	    PyObject_GC_Track(obj);
 	    Py_INCREF(obj);
 	    return obj;
+        } else if (interface_type == GI_INFO_TYPE_ENUM) {
+            g_warning("pyg_argument_to_pyobject: enums not implemented");
+	    obj = Py_None;
+	    Py_INCREF(obj);
+	    return obj;
 	} else if ( arg->v_pointer == NULL ) {
 	    obj = Py_None;
 	    Py_INCREF(obj);
@@ -152,7 +154,7 @@ pyg_argument_to_pyobject(GArgument *arg, GITypeInfo *type_info)
 	obj = Py_None;
 	break;
     case GI_TYPE_TAG_BOOLEAN:
-	obj = PyBool_FromLong(arg->v_int);
+	obj = PyBool_FromLong(arg->v_boolean);
 	break;
     case GI_TYPE_TAG_UINT8:
 	obj = PyInt_FromLong(arg->v_uint8);
@@ -167,9 +169,11 @@ pyg_argument_to_pyobject(GArgument *arg, GITypeInfo *type_info)
 	obj = PyLong_FromUnsignedLongLong(arg->v_uint64);
 	break;
     case GI_TYPE_TAG_INT:
-    case GI_TYPE_TAG_INT8:
 	obj = PyInt_FromLong(arg->v_int);
 	break;
+    case GI_TYPE_TAG_INT8:
+	obj = PyInt_FromLong(arg->v_int8);
+	break;
     case GI_TYPE_TAG_INT16:
 	obj = PyInt_FromLong(arg->v_int16);
 	break;
diff --git a/bank/bank-info.c b/bank/bank-info.c
index 62f3b5b..e751584 100644
--- a/bank/bank-info.c
+++ b/bank/bank-info.c
@@ -240,6 +240,9 @@ pyg_info_new(void *info)
 	case GI_INFO_TYPE_VALUE:
 	    tp = &PyGIValueInfo_Type;
 	    break;
+	case GI_INFO_TYPE_FIELD:
+	    tp = &PyGIFieldInfo_Type;
+	    break;
 	default:
 	    g_print ("Unhandled GIInfoType: %d\n", type_info);
 	    Py_INCREF(Py_None);
@@ -383,6 +386,8 @@ _wrap_g_function_info_invoke(PyGIBaseInfo *self, PyObject *args)
     in_args = g_newa(GArgument, expected_in_argc);
     out_args = g_newa(GArgument, expected_out_argc);
     /* each out arg is a pointer, they point to these values */
+    /* FIXME: This will break for caller-allocates funcs:
+       http://bugzilla.gnome.org/show_bug.cgi?id=573314 */
     out_values = g_newa(GArgument, expected_out_argc);
 
     failed = FALSE;
@@ -428,7 +433,7 @@ _wrap_g_function_info_invoke(PyGIBaseInfo *self, PyObject *args)
 
         if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) {
             py_arg = PyTuple_GetItem(args, i);
-	    GArgument in_value = pyg_argument_from_pyobject(py_arg, arg_info);
+	    GArgument in_value = pyg_argument_from_pyobject(py_arg, g_arg_info_get_type(arg_info));
 
             ++argv_pos;
 
@@ -608,6 +613,27 @@ static PyMethodDef _PyGIRegisteredTypeInfo_methods[] = {
 NEW_CLASS("StructInfo", GIStructInfo);
 
 static PyObject *
+_wrap_g_struct_info_get_fields(PyGIBaseInfo *self)
+{
+    int i, length;
+    PyObject *retval;
+
+    g_base_info_ref(self->info);
+    length = g_struct_info_get_n_fields((GIStructInfo*)self->info);
+    retval = PyTuple_New(length);
+
+    for (i = 0; i < length; i++) {
+        GIFieldInfo *field;
+	field = g_struct_info_get_field((GIStructInfo*)self->info, i);
+	PyTuple_SetItem(retval, i, pyg_info_new(field));
+	g_base_info_unref((GIBaseInfo*)field);
+    }
+    g_base_info_unref(self->info);
+
+    return retval;
+}
+
+static PyObject *
 _wrap_g_struct_info_get_methods(PyGIBaseInfo *self)
 {
     int i, length;
@@ -628,8 +654,107 @@ _wrap_g_struct_info_get_methods(PyGIBaseInfo *self)
     return retval;
 }
 
+static PyObject *
+_wrap_g_struct_info_new_buffer(PyGIBaseInfo *self)
+{
+    gsize size = g_struct_info_get_size ((GIStructInfo*)self->info);
+    PyObject *buffer = PyBuffer_New (size);
+    Py_INCREF(buffer);
+    return buffer;
+}
+
+static PyObject *
+_wrap_g_struct_info_get_value(PyGIBaseInfo *self, PyObject *args)
+{
+    PyObject *pybuffer;
+    PyBufferProcs *buffer_procs;
+    void *buffer;
+    char *field_name;
+    GArgument value;
+    GIFieldInfo *field_info;
+    int i;
+    int n_fields;
+    PyObject *retval;
+
+    if (!PyArg_ParseTuple(args, "Os:TypeInfo.getValue", &pybuffer, &field_name))
+        return NULL;
+
+    buffer_procs = pybuffer->ob_type->tp_as_buffer;
+    (*buffer_procs->bf_getreadbuffer)(pybuffer, 0, &buffer);
+
+    field_info = NULL;
+    n_fields = g_struct_info_get_n_fields ((GIStructInfo*) self->info);
+    for( i = 0; i < n_fields; i++ ) {
+        GIFieldInfo *temp = g_struct_info_get_field((GIStructInfo*) self->info, i);
+        if( !strcmp( g_base_info_get_name((GIBaseInfo *) temp), field_name ) ) {
+            field_info = temp;
+            break;
+        }
+    }
+
+    if( field_info == NULL ) {
+        return NULL;
+    }
+
+    if (!g_field_info_get_field (field_info, buffer, &value)) {
+        return NULL;
+    }
+
+    retval = pyg_argument_to_pyobject(&value, g_field_info_get_type (field_info));
+
+    Py_INCREF(retval);
+    return retval;
+}
+
+static PyObject *
+_wrap_g_struct_info_set_value(PyGIBaseInfo *self, PyObject *args)
+{
+    PyObject *pybuffer;
+    PyBufferProcs *buffer_procs;
+    void *buffer;
+    char *field_name;
+    GArgument arg;
+    GIFieldInfo *field_info;
+    int i;
+    int n_fields;
+    PyObject *value;
+
+    if (!PyArg_ParseTuple(args, "OsO:TypeInfo.setValue", &pybuffer, &field_name, &value))
+        return NULL;
+
+    buffer_procs = pybuffer->ob_type->tp_as_buffer;
+    (*buffer_procs->bf_getreadbuffer)(pybuffer, 0, &buffer);
+
+    field_info = NULL;
+    n_fields = g_struct_info_get_n_fields ((GIStructInfo*) self->info);
+    for( i = 0; i < n_fields; i++ ) {
+        GIFieldInfo *temp = g_struct_info_get_field((GIStructInfo*) self->info, i);
+        if( !strcmp( g_base_info_get_name((GIBaseInfo *) temp), field_name ) ) {
+            field_info = temp;
+            break;
+        }
+    }
+
+    if( field_info == NULL ) {
+        return NULL;
+    }
+
+    arg = pyg_argument_from_pyobject(value, g_field_info_get_type (field_info));
+
+    if (!g_field_info_set_field (field_info, buffer, &arg)) {
+        return NULL;
+    }
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
 static PyMethodDef _PyGIStructInfo_methods[] = {
+    { "getFields", (PyCFunction)_wrap_g_struct_info_get_fields, METH_NOARGS },
     { "getMethods", (PyCFunction)_wrap_g_struct_info_get_methods, METH_NOARGS },
+    { "newBuffer", (PyCFunction)_wrap_g_struct_info_new_buffer, METH_NOARGS },
+    { "getValue", (PyCFunction)_wrap_g_struct_info_get_value, METH_VARARGS },
+    { "setValue", (PyCFunction)_wrap_g_struct_info_set_value, METH_VARARGS },
     { NULL, NULL, 0 }
 };
 
diff --git a/bank/bank.h b/bank/bank.h
index b0c8ba6..b8f0181 100644
--- a/bank/bank.h
+++ b/bank/bank.h
@@ -73,7 +73,7 @@ extern PyTypeObject PyGIErrorDomainInfo_Type;
 extern PyTypeObject PyGIUnresolvedInfo_Type;
 
 GArgument pyg_argument_from_pyobject(PyObject *object,
-				     GIArgInfo *info);
+				     GITypeInfo *info);
 PyObject*  pyg_argument_to_pyobject(GArgument *arg,
 				    GITypeInfo *info);
 
diff --git a/bank/btypes.py b/bank/btypes.py
index 593bd0a..a72c93a 100644
--- a/bank/btypes.py
+++ b/bank/btypes.py
@@ -283,6 +283,27 @@ def buildInterface(info):
 
     return newType
 
+class BaseBlob(object):
+    """Base class for Struct, Boxed and Union.
+    """
+    def __init__(self, buf=None):
+        if buf is None:
+            buf = self.__info__.newBuffer()
+        self.__dict__['__buffer__'] = buf
+
+    def __getattr__(self, name):
+        return self.__info__.getValue(self.__dict__['__buffer__'], name)
+
+    def __setattr__(self, name, value):
+        print "__setattr__ %r %r" % (name, value)
+        self.__info__.setValue(self.__dict__['__buffer__'], name, value)
+
+    def __eq__(self, other):
+        for field in self.__info__.getFields():
+            if getattr(self, field.getName()) != getattr(other, field.getName()):
+                return False
+        return True
+
 def buildBoxed(info):
     className = info.getName()
     namespaceName = info.getNamespace()
@@ -294,7 +315,12 @@ def buildBoxed(info):
     namespace = {}
     namespace['__info__'] = info
     namespace['__module__'] = namespaceName
-    newType = type(className, (object,), namespace)
+
+    bases = (BaseBlob,)
+    if isinstance(info, repo.BoxedInfo):
+        bases += gobject.Boxed
+
+    newType = type(className, bases, namespace)
 
     constructors = []
     for method in info.getMethods():
@@ -310,18 +336,6 @@ def buildBoxed(info):
 
     setupConstructors(className, newType, constructors)
 
-    def __getattr__(self, name):
-        pass
-    newType.__getattr__ = new.instancemethod(__getattr__, None, newType)
-
-    def __setattr__(self, name, value):
-        pass
-    newType.__setattr__ = new.instancemethod(__setattr__, None, newType)
-
-    def __init__(self, buf):
-        self.__dict__['__buffer__'] = buf
-    newType.__init__ = new.instancemethod(__init__, None, newType)
-
     _classDict[fullName] = newType
     
     return newType
diff --git a/everything_unittest.py b/everything_unittest.py
index 7be9b55..5e39871 100644
--- a/everything_unittest.py
+++ b/everything_unittest.py
@@ -238,6 +238,12 @@ class TestGIEverything(unittest.TestCase):
         a.some_int8 = 1
         a.some_double = 4.15
         a.some_enum= Everything.TestEnum.VALUE3
+
+        self.assertEquals(a.some_int, 3)
+        self.assertEquals(a.some_int8, 1)
+        self.assertEquals(a.some_double, 4.15)
+        self.assertEquals(a.some_enum, Everything.TestEnum.VALUE3)
+
         return a
 
     def testStructA(self):



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]