[pygi] Add basic support for unions



commit 3ba666b7ab9c393963922c272e7d87bff50a93f9
Author: Tomeu Vizoso <tomeu sugarlabs org>
Date:   Sat Jan 2 16:31:55 2010 +0100

    Add basic support for unions
    
    https://bugzilla.gnome.org/show_bug.cgi?id=603598

 gi/module.py       |    3 +-
 gi/pygi-argument.c |   24 +++----------
 gi/pygi-boxed.c    |   18 +++++++++-
 gi/pygi-info.c     |   94 +++++++++++++++++++++++++++++++++++++++++++++++-----
 gi/pygi-info.h     |    1 +
 tests/test_gi.py   |   56 +++++++++++++++++++++++++++++++
 6 files changed, 165 insertions(+), 31 deletions(-)
---
diff --git a/gi/module.py b/gi/module.py
index 2d5a8cc..3afdc18 100644
--- a/gi/module.py
+++ b/gi/module.py
@@ -34,6 +34,7 @@ from ._gi import \
     InterfaceInfo, \
     ConstantInfo, \
     StructInfo, \
+    UnionInfo, \
     Struct, \
     Boxed, \
     enum_add, \
@@ -125,7 +126,7 @@ class DynamicModule(object):
             elif isinstance(info, InterfaceInfo):
                 bases = (gobject.GInterface,)
                 metaclass = GObjectMeta
-            elif isinstance(info, StructInfo):
+            elif isinstance(info, (StructInfo, UnionInfo)):
                 if g_type.is_a(gobject.TYPE_BOXED):
                     bases = (Boxed,)
                 elif g_type.is_a(gobject.TYPE_POINTER) or g_type == gobject.TYPE_NONE:
diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c
index 8244659..57547a0 100644
--- a/gi/pygi-argument.c
+++ b/gi/pygi-argument.c
@@ -441,11 +441,8 @@ check_number_release:
                 case GI_INFO_TYPE_BOXED:
                 case GI_INFO_TYPE_INTERFACE:
                 case GI_INFO_TYPE_OBJECT:
-                    retval = _pygi_g_registered_type_info_check_object((GIRegisteredTypeInfo *)info, TRUE, object);
-                    break;
                 case GI_INFO_TYPE_UNION:
-                    /* TODO */
-                    PyErr_SetString(PyExc_NotImplementedError, "union marshalling is not supported yet");
+                    retval = _pygi_g_registered_type_info_check_object((GIRegisteredTypeInfo *)info, TRUE, object);
                     break;
                 default:
                     g_assert_not_reached();
@@ -910,6 +907,7 @@ array_item_error:
                     break;
                 case GI_INFO_TYPE_BOXED:
                 case GI_INFO_TYPE_STRUCT:
+                case GI_INFO_TYPE_UNION:
                 {
                     GType type;
 
@@ -1005,10 +1003,6 @@ array_item_error:
                     }
 
                     break;
-                case GI_INFO_TYPE_UNION:
-                    PyErr_SetString(PyExc_NotImplementedError, "union marshalling is not supported yet");
-                    /* TODO */
-                    break;
                 default:
                     g_assert_not_reached();
             }
@@ -1445,6 +1439,7 @@ _pygi_argument_to_object (GArgument  *arg,
                 }
                 case GI_INFO_TYPE_BOXED:
                 case GI_INFO_TYPE_STRUCT:
+                case GI_INFO_TYPE_UNION:
                 {
                     GType type;
 
@@ -1461,11 +1456,8 @@ _pygi_argument_to_object (GArgument  *arg,
                         PyObject *py_type;
 
                         py_type = _pygi_type_get_from_g_type(type);
-                        if (py_type == NULL) {
-                            PyErr_Format(PyExc_ValueError, "couldn't find a wrapper for type '%s'",
-                                         g_type_name(type));
+                        if (py_type == NULL)
                             break;
-                        }
 
                         object = _pygi_boxed_new((PyTypeObject *)py_type, arg->v_pointer, transfer == GI_TRANSFER_EVERYTHING);
 
@@ -1547,10 +1539,6 @@ _pygi_argument_to_object (GArgument  *arg,
                     }
                     object = pygobject_new(arg->v_pointer);
                     break;
-                case GI_INFO_TYPE_UNION:
-                    /* TODO */
-                    PyErr_SetString(PyExc_NotImplementedError, "union marshalling is not supported yet");
-                    break;
                 default:
                     g_assert_not_reached();
             }
@@ -1769,6 +1757,7 @@ _pygi_argument_release (GArgument   *arg,
                     break;
                 case GI_INFO_TYPE_BOXED:
                 case GI_INFO_TYPE_STRUCT:
+                case GI_INFO_TYPE_UNION:
                 {
                     GType type;
 
@@ -1819,9 +1808,6 @@ _pygi_argument_release (GArgument   *arg,
                         g_object_unref(arg->v_pointer);
                     }
                     break;
-                case GI_INFO_TYPE_UNION:
-                    /* TODO */
-                    break;
                 default:
                     g_assert_not_reached();
             }
diff --git a/gi/pygi-boxed.c b/gi/pygi-boxed.c
index b157eb8..c320796 100644
--- a/gi/pygi-boxed.c
+++ b/gi/pygi-boxed.c
@@ -63,7 +63,7 @@ _boxed_new (PyTypeObject *type,
         return NULL;
     }
 
-    info = _pygi_object_get_gi_info((PyObject *)type, &PyGIStructInfo_Type);
+    info = _pygi_object_get_gi_info((PyObject *)type, &PyGIBaseInfo_Type);
     if (info == NULL) {
         if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
             PyErr_Format(PyExc_TypeError, "missing introspection information");
@@ -71,7 +71,21 @@ _boxed_new (PyTypeObject *type,
         return NULL;
     }
 
-    size = g_struct_info_get_size((GIStructInfo *)info);
+    switch (g_base_info_get_type(info)) {
+        case GI_INFO_TYPE_UNION:
+            size = g_union_info_get_size((GIUnionInfo *)info);
+            break;
+        case GI_INFO_TYPE_BOXED:
+        case GI_INFO_TYPE_STRUCT:
+            size = g_struct_info_get_size((GIStructInfo *)info);
+            break;
+        default:
+            PyErr_Format(PyExc_TypeError,
+                         "info should be Boxed or Union, not '%d'",
+                         g_base_info_get_type(info));
+            return NULL;
+    }
+
     boxed = g_slice_alloc0(size);
     if (boxed == NULL) {
         PyErr_NoMemory();
diff --git a/gi/pygi-info.c b/gi/pygi-info.c
index 504bdac..59c99fa 100644
--- a/gi/pygi-info.c
+++ b/gi/pygi-info.c
@@ -204,8 +204,8 @@ _pygi_info_new (GIBaseInfo *info)
             PyErr_SetString(PyExc_NotImplementedError, "GIErrorDomainInfo bindings not implemented");
             return NULL;
         case GI_INFO_TYPE_UNION:
-            PyErr_SetString(PyExc_NotImplementedError, "GIUnionInfo bindings not implemented");
-            return NULL;
+            type = &PyGIUnionInfo_Type;
+            break;
         case GI_INFO_TYPE_VALUE:
             type = &PyGIValueInfo_Type;
             break;
@@ -792,9 +792,6 @@ _wrap_g_function_info_invoke (PyGIBaseInfo *self,
 
             switch(container_info_type) {
                 case GI_INFO_TYPE_UNION:
-                    PyErr_SetString(PyExc_NotImplementedError, "calling methods on unions is not supported yet.");
-                    goto out;
-                    break;
                 case GI_INFO_TYPE_STRUCT:
                 {
                     GType type;
@@ -1931,8 +1928,6 @@ _wrap_g_field_info_get_value (PyGIBaseInfo *self,
     container_info_type = g_base_info_get_type(container_info);
     switch (container_info_type) {
         case GI_INFO_TYPE_UNION:
-            PyErr_SetString(PyExc_NotImplementedError, "getting a field from an union is not supported yet");
-            return NULL;
         case GI_INFO_TYPE_STRUCT:
             pointer = pyg_boxed_get(instance, void);
             break;
@@ -2028,8 +2023,6 @@ _wrap_g_field_info_set_value (PyGIBaseInfo *self,
     container_info_type = g_base_info_get_type(container_info);
     switch (container_info_type) {
         case GI_INFO_TYPE_UNION:
-            PyErr_SetString(PyExc_NotImplementedError, "setting a field in an union is not supported yet");
-            return NULL;
         case GI_INFO_TYPE_STRUCT:
             pointer = pyg_boxed_get(instance, void);
             break;
@@ -2159,6 +2152,88 @@ static PyMethodDef _PyGIVFuncInfo_methods[] = {
     { NULL, NULL, 0 }
 };
 
+
+/* GIUnionInfo */
+_PyGI_DEFINE_INFO_TYPE("UnionInfo", GIUnionInfo, PyGIRegisteredTypeInfo_Type);
+
+static PyObject *
+_wrap_g_union_info_get_fields (PyGIBaseInfo *self)
+{
+    gssize n_infos;
+    PyObject *infos;
+    gssize i;
+
+    n_infos = g_union_info_get_n_fields((GIUnionInfo *)self->info);
+
+    infos = PyTuple_New(n_infos);
+    if (infos == NULL) {
+        return NULL;
+    }
+
+    for (i = 0; i < n_infos; i++) {
+        GIBaseInfo *info;
+        PyObject *py_info;
+
+        info = (GIBaseInfo *)g_union_info_get_field((GIUnionInfo *)self->info, i);
+        g_assert(info != NULL);
+
+        py_info = _pygi_info_new(info);
+
+        g_base_info_unref(info);
+
+        if (py_info == NULL) {
+            Py_CLEAR(infos);
+            break;
+        }
+
+        PyTuple_SET_ITEM(infos, i, py_info);
+    }
+
+    return infos;
+}
+
+static PyObject *
+_wrap_g_union_info_get_methods (PyGIBaseInfo *self)
+{
+    gssize n_infos;
+    PyObject *infos;
+    gssize i;
+
+    n_infos = g_union_info_get_n_methods((GIUnionInfo *)self->info);
+
+    infos = PyTuple_New(n_infos);
+    if (infos == NULL) {
+        return NULL;
+    }
+
+    for (i = 0; i < n_infos; i++) {
+        GIBaseInfo *info;
+        PyObject *py_info;
+
+        info = (GIBaseInfo *)g_union_info_get_method((GIUnionInfo *)self->info, i);
+        g_assert(info != NULL);
+
+        py_info = _pygi_info_new(info);
+
+        g_base_info_unref(info);
+
+        if (py_info == NULL) {
+            Py_CLEAR(infos);
+            break;
+        }
+
+        PyTuple_SET_ITEM(infos, i, py_info);
+    }
+
+    return infos;
+}
+
+static PyMethodDef _PyGIUnionInfo_methods[] = {
+    { "get_fields", (PyCFunction)_wrap_g_union_info_get_fields, METH_NOARGS },
+    { "get_methods", (PyCFunction)_wrap_g_union_info_get_methods, METH_NOARGS },
+    { NULL, NULL, 0 }
+};
+
 /* Private */
 
 gchar *
@@ -2209,6 +2284,7 @@ _pygi_info_register_types (PyObject *m)
     _PyGI_REGISTER_TYPE(m, PyGIValueInfo_Type, "ValueInfo");
     _PyGI_REGISTER_TYPE(m, PyGIFieldInfo_Type, "FieldInfo");
     _PyGI_REGISTER_TYPE(m, PyGIVFuncInfo_Type, "VFuncInfo");
+    _PyGI_REGISTER_TYPE(m, PyGIUnionInfo_Type, "UnionInfo");
 
 #undef _PyGI_REGISTER_TYPE
 }
diff --git a/gi/pygi-info.h b/gi/pygi-info.h
index fe02d1a..0d2bade 100644
--- a/gi/pygi-info.h
+++ b/gi/pygi-info.h
@@ -46,6 +46,7 @@ extern PyTypeObject PyGIValueInfo_Type;
 extern PyTypeObject PyGIFieldInfo_Type;
 extern PyTypeObject PyGIUnresolvedInfo_Type;
 extern PyTypeObject PyGIVFuncInfo_Type;
+extern PyTypeObject PyGIUnionInfo_Type;
 
 #define PyGIBaseInfo_GET_GI_INFO(object) g_base_info_ref(((PyGIBaseInfo *)object)->info)
 
diff --git a/tests/test_gi.py b/tests/test_gi.py
index 0930d7c..7cab5db 100644
--- a/tests/test_gi.py
+++ b/tests/test_gi.py
@@ -1193,6 +1193,62 @@ class TestStructure(unittest.TestCase):
         del in_struct
         del out_struct
 
+    def test_union(self):
+        union = GIMarshallingTests.Union()
+
+        self.assertTrue(isinstance(union, GIMarshallingTests.Union))
+
+        new_union = union.copy()
+        self.assertTrue(isinstance(new_union, GIMarshallingTests.Union))
+
+        del union
+        del new_union
+
+    def test_union_return(self):
+        union = GIMarshallingTests.union_return()
+
+        self.assertTrue(isinstance(union, GIMarshallingTests.Union))
+        self.assertEquals(42, union.long_)
+
+        del union
+
+    def test_union_in(self):
+        union = GIMarshallingTests.Union()
+        union.long_ = 42
+
+        GIMarshallingTests.union_in(union)
+
+        del union
+
+    def test_union_out(self):
+        union = GIMarshallingTests.union_out()
+
+        self.assertTrue(isinstance(union, GIMarshallingTests.Union))
+        self.assertEquals(42, union.long_)
+
+        del union
+
+    def test_union_inout(self):
+        in_union = GIMarshallingTests.Union()
+        in_union.long_ = 42
+
+        out_union = GIMarshallingTests.union_inout(in_union)
+
+        self.assertTrue(isinstance(out_union, GIMarshallingTests.Union))
+        self.assertEquals(0, out_union.long_)
+
+        del in_union
+        del out_union
+
+    def test_union_method(self):
+        union = GIMarshallingTests.Union()
+        union.long_ = 42
+
+        union.method()
+
+        del union
+
+        self.assertRaises(TypeError, GIMarshallingTests.Union.method)
 
 class TestGObject(unittest.TestCase):
 



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