gjs r118 - in trunk: gi test/js



Author: otaylor
Date: Wed Nov 19 22:31:12 2008
New Revision: 118
URL: http://svn.gnome.org/viewvc/gjs?rev=118&view=rev

Log:
Support simple structures not registered as boxed

Allow creating a "Boxed" object for a simple structure that is not
registered as a GBoxed.

Renames:
  gjs_g_boxed_from_boxed() => gjs_c_struct_from_boxed()
  gjs_boxed_from_g_boxed() => gjs_boxed_from_c_struct()
  gjs_g_boxed_from_union() => gjs_c_struct_from_union()
  gjs_union_from_g_boxed() => gjs_union_from_c_struct()

Change from passing GType to _from_g_boxed() to passing
GI[Struct|Union]Info to _from_c_struct()

gi/boxed.c: Allow for g_registered_type_info_get_g_type() returning
 G_TYPE_NONE.

gi/union.c: Add check (for now) that the union type is registered as
 a GBoxed before registering the JS class.

gi/arg.c: Check whether the GIBaseInfo STRUCT/BOXED/UNION before
 getting the GType and making a decision based on that.

test/js/testEverythingEncapsulated.js: Add tests for simple structures

https://bugzilla.gnome.org/show_bug.cgi?id=560808

Modified:
   trunk/gi/arg.c
   trunk/gi/boxed.c
   trunk/gi/boxed.h
   trunk/gi/function.c
   trunk/gi/union.c
   trunk/gi/union.h
   trunk/gi/value.c
   trunk/test/js/testEverythingEncapsulated.js

Modified: trunk/gi/arg.c
==============================================================================
--- trunk/gi/arg.c	(original)
+++ trunk/gi/arg.c	Wed Nov 19 22:31:12 2008
@@ -408,15 +408,19 @@
         nullable_type = TRUE;
         {
             GIBaseInfo* symbol_info;
+            GIInfoType symbol_type;
             GType gtype;
 
             symbol_info = g_type_info_get_interface(type_info);
             g_assert(symbol_info != NULL);
 
+            symbol_type = g_base_info_get_type(symbol_info);
+
             gtype = g_registered_type_info_get_g_type((GIRegisteredTypeInfo*)symbol_info);
 
-            gjs_debug_marshal(GJS_DEBUG_GFUNCTION,
-                              "gtype of SYMBOL is %s", g_type_name(gtype));
+            if (gtype != G_TYPE_NONE)
+                gjs_debug_marshal(GJS_DEBUG_GFUNCTION,
+                                  "gtype of SYMBOL is %s", g_type_name(gtype));
 
             if (gtype == G_TYPE_VALUE) {
                 GValue *gvalue;
@@ -433,53 +437,65 @@
             } else if (JSVAL_IS_NULL(value)) {
                 arg->v_pointer = NULL;
             } else if (JSVAL_IS_OBJECT(value)) {
-                if (g_type_is_a(gtype, G_TYPE_OBJECT) || g_type_is_a(gtype, G_TYPE_INTERFACE)) {
-                    arg->v_pointer = gjs_g_object_from_object(context,
-                                                                 JSVAL_TO_OBJECT(value));
-                    if (arg->v_pointer != NULL) {
-                        if (!g_type_is_a(G_TYPE_FROM_INSTANCE(arg->v_pointer),
-                                         gtype)) {
+                /* Handle Struct/Union first since we don't necessarily need a GType for them */
+                if (symbol_type == GI_INFO_TYPE_STRUCT || symbol_type == GI_INFO_TYPE_BOXED) {
+                    arg->v_pointer = gjs_c_struct_from_boxed(context,
+                                                             JSVAL_TO_OBJECT(value));
+
+                } else if (symbol_type == GI_INFO_TYPE_UNION) {
+                    arg->v_pointer = gjs_c_union_from_union(context,
+                                                            JSVAL_TO_OBJECT(value));
+
+                } else if (gtype != G_TYPE_NONE) {
+
+                    if (g_type_is_a(gtype, G_TYPE_OBJECT) || g_type_is_a(gtype, G_TYPE_INTERFACE)) {
+                        arg->v_pointer = gjs_g_object_from_object(context,
+                                                                  JSVAL_TO_OBJECT(value));
+                        if (arg->v_pointer != NULL) {
+                            if (!g_type_is_a(G_TYPE_FROM_INSTANCE(arg->v_pointer),
+                                             gtype)) {
+                                gjs_throw(context,
+                                          "Expected type '%s' but got '%s'",
+                                          g_type_name(gtype),
+                                          g_type_name(G_TYPE_FROM_INSTANCE(arg->v_pointer)));
+                                arg->v_pointer = NULL;
+                                wrong = TRUE;
+                            }
+                        }
+                    } else if (g_type_is_a(gtype, G_TYPE_BOXED)) {
+                        if (g_type_is_a(gtype, G_TYPE_CLOSURE)) {
+                            arg->v_pointer = gjs_closure_new_marshaled(context,
+                                                                       JSVAL_TO_OBJECT(value),
+                                                                       "boxed");
+                        } else {
+                            /* Should have been caught above as STRUCT/BOXED/UNION */
                             gjs_throw(context,
-                                      "Expected type '%s' but got '%s'",
+                                      "Boxed type %s registered for unexpected symbol_type %d",
                                       g_type_name(gtype),
-                                      g_type_name(G_TYPE_FROM_INSTANCE(arg->v_pointer)));
-                            arg->v_pointer = NULL;
-                            wrong = TRUE;
+                                      symbol_type);
                         }
-                    }
-                } else if (g_type_is_a(gtype, G_TYPE_BOXED)) {
-                    if (g_type_is_a(gtype, G_TYPE_CLOSURE)) {
-                        arg->v_pointer = gjs_closure_new_marshaled(context,
-                                                                   JSVAL_TO_OBJECT(value),
-                                                                   "boxed");
-                    } else if (g_base_info_get_type(symbol_info) == GI_INFO_TYPE_UNION) {
-                        arg->v_pointer = gjs_g_boxed_from_union(context,
-                                                                JSVAL_TO_OBJECT(value));
                     } else {
-                        arg->v_pointer = gjs_g_boxed_from_boxed(context,
-                                                                JSVAL_TO_OBJECT(value));
+                        gjs_throw(context, "Unhandled GType %s unpacking SYMBOL GArgument from Object",
+                                  g_type_name(gtype));
                     }
-                } else {
-                    gjs_throw(context, "Unhandled GType %s unpacking SYMBOL GArgument from Object",
-                              g_type_name(gtype));
                 }
 
                 if (arg->v_pointer == NULL) {
                     gjs_debug(GJS_DEBUG_GFUNCTION,
-                              "conversion of JSObject %p type %s to gtype %s failed",
+                              "conversion of JSObject %p type %s to type %s failed",
                               JSVAL_TO_OBJECT(value),
                               JS_GetTypeName(context,
                                              JS_TypeOfValue(context, value)),
-                              g_type_name(gtype));
+                              g_base_info_get_name ((GIBaseInfo *)symbol_info));
 
-                    /* bis_js_throw should have been called already */
+                    /* gjs_throw should have been called already */
                     wrong = TRUE;
                 }
 
             } else if (JSVAL_IS_NUMBER(value)) {
                 nullable_type = FALSE;
 
-                if (g_base_info_get_type(symbol_info) == GI_INFO_TYPE_ENUM) {
+                if (symbol_type == GI_INFO_TYPE_ENUM) {
                     if (!JS_ValueToInt32(context, value, &arg->v_int)) {
                         wrong = TRUE;
                     } else if (!_gjs_enum_value_is_valid(context, (GIEnumInfo *)symbol_info, arg->v_int)) {
@@ -838,12 +854,15 @@
             } else {
                 jsval value;
                 GIBaseInfo* symbol_info;
+                GIInfoType symbol_type;
                 GType gtype;
 
                 symbol_info = g_type_info_get_interface(type_info);
                 g_assert(symbol_info != NULL);
 
-                if (g_base_info_get_type(symbol_info) == GI_INFO_TYPE_UNRESOLVED) {
+                symbol_type = g_base_info_get_type(symbol_info);
+
+                if (symbol_type == GI_INFO_TYPE_UNRESOLVED) {
                     gjs_throw(context,
                               "Unable to resolve arg type '%s'",
                               g_base_info_get_name(symbol_info));
@@ -851,13 +870,30 @@
                     return JS_FALSE;
                 }
 
+                value = JSVAL_VOID;
+
+                /* Handle Struct/Union first since we don't necessarily need a GType for them */
+                if (symbol_type == GI_INFO_TYPE_STRUCT || symbol_type == GI_INFO_TYPE_BOXED) {
+                    JSObject *obj;
+                    obj = gjs_boxed_from_c_struct(context, (GIStructInfo *)symbol_info, arg->v_pointer);
+                    if (obj)
+                        value = OBJECT_TO_JSVAL(obj);
+
+                    goto out;
+                } else if (symbol_type == GI_INFO_TYPE_UNION) {
+                    JSObject *obj;
+                    obj = gjs_union_from_c_union(context, (GIUnionInfo *)symbol_info, arg->v_pointer);
+                    if (obj)
+                        value = OBJECT_TO_JSVAL(obj);
+
+                    goto out;
+                }
+
                 gtype = g_registered_type_info_get_g_type((GIRegisteredTypeInfo*)symbol_info);
 
                 gjs_debug_marshal(GJS_DEBUG_GFUNCTION,
                                   "gtype of SYMBOL is %s", g_type_name(gtype));
 
-                value = JSVAL_VOID;
-
                 if (g_type_is_a(gtype, G_TYPE_OBJECT) || g_type_is_a(gtype, G_TYPE_INTERFACE)) {
                     JSObject *obj;
                     obj = gjs_object_from_g_object(context, G_OBJECT(arg->v_pointer));
@@ -869,15 +905,13 @@
                         return JS_FALSE;
                     }
                 } else if (g_type_is_a(gtype, G_TYPE_BOXED)) {
-                    JSObject *obj;
-                    if (g_base_info_get_type(symbol_info) == GI_INFO_TYPE_UNION) {
-                        obj = gjs_union_from_g_boxed(context, gtype, arg->v_pointer);
-                    } else {
-                        obj = gjs_boxed_from_g_boxed(context, gtype, arg->v_pointer);
-                    }
-                    if (obj)
-                        value = OBJECT_TO_JSVAL(obj);
-                } else if (g_base_info_get_type(symbol_info) == GI_INFO_TYPE_ENUM) {
+                    /* Should have been caught above as STRUCT/BOXED/UNION */
+                    gjs_throw(context,
+                              "Boxed type %s registered for unexpected symbol_type %d",
+                              g_type_name(gtype),
+                              symbol_type);
+                    return JS_FALSE;
+                } else if (symbol_type == GI_INFO_TYPE_ENUM) {
                     if (_gjs_enum_value_is_valid(context, (GIEnumInfo *)symbol_info, arg->v_int))
                         value = INT_TO_JSVAL(arg->v_int);
                 } else if (g_type_is_a(gtype, G_TYPE_FLAGS)) {
@@ -894,6 +928,7 @@
                                  g_type_name(gtype));
                 }
 
+            out:
                 g_base_info_unref( (GIBaseInfo*) symbol_info);
 
                 if (JSVAL_IS_VOID(value))

Modified: trunk/gi/boxed.c
==============================================================================
--- trunk/gi/boxed.c	(original)
+++ trunk/gi/boxed.c	Wed Nov 19 22:31:12 2008
@@ -184,69 +184,85 @@
 }
 
 static JSBool
+boxed_new_direct(JSContext   *context,
+                 JSObject    *obj, /* "this" for constructor */
+                 Boxed       *priv)
+{
+    g_assert(priv->can_allocate_directly);
+
+    priv->gboxed = g_slice_alloc0(g_struct_info_get_size (priv->info));
+    priv->allocated_directly = TRUE;
+
+    gjs_debug_lifecycle(GJS_DEBUG_GBOXED,
+                        "JSObject created by directly allocating %s",
+                        g_base_info_get_name ((GBaseInfo *)priv->info));
+
+    return JS_TRUE;
+}
+
+static JSBool
 boxed_new(JSContext   *context,
           JSObject    *obj, /* "this" for constructor */
           Boxed       *priv)
 {
+    GType gtype;
     int n_methods;
     int i;
 
-    /* Find a zero-args constructor and call it */
+    gtype = g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) priv->info);
 
-    n_methods = g_struct_info_get_n_methods(priv->info);
-
-    for (i = 0; i < n_methods; ++i) {
-        GIFunctionInfo *func_info;
-        GIFunctionInfoFlags flags;
-
-        func_info = g_struct_info_get_method(priv->info, i);
+    if (gtype != G_TYPE_NONE) {
+        /* If the structure is registered as a boxed, we can create a new instance by
+         * looking for a zero-args constructor and calling it; constructors don't
+         * really make sense for non-boxed types, since there is no memory management
+         * for the return value; those are handled below along with simple boxed
+         * structures without constructor.
+         */
+        n_methods = g_struct_info_get_n_methods(priv->info);
 
-        flags = g_function_info_get_flags(func_info);
-        if ((flags & GI_FUNCTION_IS_CONSTRUCTOR) != 0 &&
-            g_callable_info_get_n_args((GICallableInfo*) func_info) == 0) {
+        for (i = 0; i < n_methods; ++i) {
+            GIFunctionInfo *func_info;
+            GIFunctionInfoFlags flags;
 
-            jsval rval;
-            GType gtype;
-            void *gboxed;
+            func_info = g_struct_info_get_method(priv->info, i);
 
-            rval = JSVAL_NULL;
-            gjs_invoke_c_function(context, func_info, obj,
-                                     0, NULL, &rval);
+            flags = g_function_info_get_flags(func_info);
+            if ((flags & GI_FUNCTION_IS_CONSTRUCTOR) != 0 &&
+                g_callable_info_get_n_args((GICallableInfo*) func_info) == 0) {
 
-            g_base_info_unref((GIBaseInfo*) func_info);
+                jsval rval;
+                void *gboxed;
 
-            if (JSVAL_IS_NULL(rval))
-                return JS_FALSE;
+                rval = JSVAL_NULL;
+                gjs_invoke_c_function(context, func_info, obj,
+                                      0, NULL, &rval);
 
-            /* We are somewhat wasteful here; invoke_c_function() above
-             * creates a JSObject wrapper for the boxed that we immediately
-             * discard.
-             */
-            gtype = g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) priv->info);
-            gboxed = gjs_g_boxed_from_boxed(context, JSVAL_TO_OBJECT(rval));
-            priv->gboxed = g_boxed_copy (gtype, gboxed);
-
-            gjs_debug_lifecycle(GJS_DEBUG_GBOXED,
-                                "JSObject created with boxed instance %p type %s",
-                                priv->gboxed, g_type_name(gtype));
+                g_base_info_unref((GIBaseInfo*) func_info);
 
-            return JS_TRUE;
-        }
+                if (JSVAL_IS_NULL(rval))
+                    return JS_FALSE;
 
-        g_base_info_unref((GIBaseInfo*) func_info);
-    }
+                /* We are somewhat wasteful here; invoke_c_function() above
+                 * creates a JSObject wrapper for the boxed that we immediately
+                 * discard.
+                 */
+                gboxed = gjs_c_struct_from_boxed(context, JSVAL_TO_OBJECT(rval));
+                priv->gboxed = g_boxed_copy (gtype, gboxed);
 
-    if (priv->can_allocate_directly) {
-        priv->gboxed = g_slice_alloc0(g_struct_info_get_size (priv->info));
-        priv->allocated_directly = TRUE;
+                gjs_debug_lifecycle(GJS_DEBUG_GBOXED,
+                                    "JSObject created with boxed instance %p type %s",
+                                    priv->gboxed, g_type_name(gtype));
 
-        gjs_debug_lifecycle(GJS_DEBUG_GBOXED,
-                            "JSObject created by directly allocating %s",
-                            g_base_info_get_name ((GBaseInfo *)priv->info));
+                return JS_TRUE;
+            }
 
-        return JS_TRUE;
+            g_base_info_unref((GIBaseInfo*) func_info);
+        }
     }
 
+    if (priv->can_allocate_directly)
+        return boxed_new_direct(context, obj, priv);
+
     gjs_throw(context, "Unable to construct boxed type %s since it has no zero-args <constructor>, can only wrap an existing one",
               g_base_info_get_name((GIBaseInfo*) priv->info));
 
@@ -503,8 +519,25 @@
         } else {
             GType gtype = g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) priv->info);
 
-            priv->gboxed = g_boxed_copy(gtype, unthreadsafe_template_for_constructor.gboxed);
+            if (gtype != G_TYPE_NONE) {
+                priv->gboxed = g_boxed_copy(gtype,
+                                            unthreadsafe_template_for_constructor.gboxed);
+            } else if (priv->can_allocate_directly) {
+                if (!boxed_new_direct(context, obj, priv))
+                    return JS_FALSE;
+
+                memcpy(priv->gboxed,
+                       unthreadsafe_template_for_constructor.gboxed,
+                       g_struct_info_get_size (priv->info));
+            } else {
+                gjs_throw(context,
+                          "Can't create a Javascript object for %s; no way to copy",
+                          g_base_info_get_name( (GIBaseInfo*) priv->info));
+            }
+
             unthreadsafe_template_for_constructor.gboxed = NULL;
+
+            return priv->gboxed != NULL;
         }
     }
 
@@ -524,11 +557,14 @@
         return; /* wrong class? */
 
     if (priv->gboxed) {
-        if (priv->allocated_directly)
+        if (priv->allocated_directly) {
             g_slice_free1(g_struct_info_get_size (priv->info), priv->gboxed);
-        else
-            g_boxed_free(g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) priv->info),
-                         priv->gboxed);
+        } else {
+            GType gtype = g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) priv->info);
+            g_assert(gtype != G_TYPE_NONE);
+
+            g_boxed_free(gtype,  priv->gboxed);
+        }
 
         priv->gboxed = NULL;
     }
@@ -581,7 +617,6 @@
 
     info = g_type_info_get_interface (type_info);
     if (!(g_base_info_get_type (info) == GI_INFO_TYPE_STRUCT || g_base_info_get_type (info) == GI_INFO_TYPE_BOXED) ||
-        g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*)info) == G_TYPE_NONE ||
         !struct_is_simple ((GIStructInfo *)info)) {
         gjs_throw(context, "Reading field %s.%s is not supported",
                   g_base_info_get_name ((GIBaseInfo *)parent_priv->info),
@@ -693,7 +728,6 @@
 
     info = g_type_info_get_interface (type_info);
     if (!(g_base_info_get_type (info) == GI_INFO_TYPE_STRUCT || g_base_info_get_type (info) == GI_INFO_TYPE_BOXED) ||
-        g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*)info) == G_TYPE_NONE ||
         !struct_is_simple ((GIStructInfo *)info)) {
         gjs_throw(context, "Writing field %s.%s is not supported",
                   g_base_info_get_name ((GIBaseInfo *)parent_priv->info),
@@ -1016,8 +1050,7 @@
                 switch (g_base_info_get_type (interface)) {
 		case GI_INFO_TYPE_BOXED:
 		case GI_INFO_TYPE_STRUCT:
-                    if (g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*)info) == G_TYPE_NONE ||
-                        !struct_is_simple ((GIStructInfo *)interface))
+                    if (!struct_is_simple ((GIStructInfo *)interface))
                         is_simple = FALSE;
                     break;
 		case GI_INFO_TYPE_UNION:
@@ -1170,58 +1203,33 @@
 }
 
 JSObject*
-gjs_boxed_from_g_boxed(JSContext    *context,
-                       GType         gtype,
-                       void         *gboxed)
+gjs_boxed_from_c_struct(JSContext    *context,
+                        GIStructInfo *info,
+                        void         *gboxed)
 {
-    JSObject *obj;
     JSObject *proto;
-    GIBaseInfo *info;
 
     if (gboxed == NULL)
         return NULL;
 
     gjs_debug_marshal(GJS_DEBUG_GBOXED,
-                      "Wrapping boxed %s %p with JSObject",
-                      g_type_name(gtype), gboxed);
-
-    info = g_irepository_find_by_gtype(g_irepository_get_default(),
-                                       gtype);
-
-    if (info == NULL) {
-        gjs_throw(context,
-                     "Unknown boxed type %s",
-                     g_type_name(gtype));
-        return NULL;
-    }
-
-    if (g_base_info_get_type( (GIBaseInfo*) info) != GI_INFO_TYPE_BOXED &&
-        g_base_info_get_type( (GIBaseInfo*) info) != GI_INFO_TYPE_STRUCT) {
-        gjs_throw(context,
-                  "GType %s doesn't map to boxed in g-i?",
-                  g_base_info_get_name( (GIBaseInfo*) info));
-        g_base_info_unref( (GIBaseInfo*) info);
-        return NULL;
-    }
+                      "Wrapping struct %s %p with JSObject",
+                      g_base_info_get_name((GBaseInfo *)info), gboxed);
 
-    proto = gjs_lookup_boxed_prototype(context, (GIBoxedInfo*) info);
+    proto = gjs_lookup_boxed_prototype(context, info);
 
     /* can't come up with a better approach... */
-    unthreadsafe_template_for_constructor.info = (GIBoxedInfo*) info;
+    unthreadsafe_template_for_constructor.info = info;
     unthreadsafe_template_for_constructor.gboxed = gboxed;
     unthreadsafe_template_for_constructor.parent_jsval = JSVAL_NULL;
 
-    obj = gjs_construct_object_dynamic(context, proto,
-                                       0, NULL);
-
-    g_base_info_unref( (GIBaseInfo*) info);
-
-    return obj;
+    return gjs_construct_object_dynamic(context, proto,
+                                        0, NULL);
 }
 
 void*
-gjs_g_boxed_from_boxed(JSContext    *context,
-                       JSObject     *obj)
+gjs_c_struct_from_boxed(JSContext    *context,
+                        JSObject     *obj)
 {
     Boxed *priv;
 

Modified: trunk/gi/boxed.h
==============================================================================
--- trunk/gi/boxed.h	(original)
+++ trunk/gi/boxed.h	Wed Nov 19 22:31:12 2008
@@ -46,10 +46,10 @@
                                         GIBoxedInfo  *info);
 JSClass*  gjs_lookup_boxed_class       (JSContext    *context,
                                         GIBoxedInfo  *info);
-void*     gjs_g_boxed_from_boxed       (JSContext    *context,
+void*     gjs_c_struct_from_boxed      (JSContext    *context,
                                         JSObject     *obj);
-JSObject* gjs_boxed_from_g_boxed       (JSContext    *context,
-                                        GType         gtype,
+JSObject* gjs_boxed_from_c_struct      (JSContext    *context,
+                                        GIStructInfo *info,
                                         void         *gboxed);
 
 G_END_DECLS

Modified: trunk/gi/function.c
==============================================================================
--- trunk/gi/function.c	(original)
+++ trunk/gi/function.c	Wed Nov 19 22:31:12 2008
@@ -173,9 +173,9 @@
         GIInfoType type = g_base_info_get_type(container);
 
         if (type == GI_INFO_TYPE_STRUCT || type == GI_INFO_TYPE_BOXED) {
-            in_args[0].v_pointer = gjs_g_boxed_from_boxed(context, obj);
+            in_args[0].v_pointer = gjs_c_struct_from_boxed(context, obj);
         } else if (type == GI_INFO_TYPE_UNION) {
-            in_args[0].v_pointer = gjs_g_boxed_from_union(context, obj);
+            in_args[0].v_pointer = gjs_c_union_from_union(context, obj);
         } else { /* by fallback is always object */
             in_args[0].v_pointer = gjs_g_object_from_object(context, obj);
         }

Modified: trunk/gi/union.c
==============================================================================
--- trunk/gi/union.c	(original)
+++ trunk/gi/union.c	Wed Nov 19 22:31:12 2008
@@ -178,7 +178,7 @@
             if (JSVAL_IS_NULL(rval))
                 return NULL;
             else
-                return gjs_g_boxed_from_union(context, JSVAL_TO_OBJECT(rval));
+                return gjs_c_union_from_union(context, JSVAL_TO_OBJECT(rval));
         }
 
         g_base_info_unref((GIBaseInfo*) func_info);
@@ -429,6 +429,16 @@
     JSObject *prototype;
     jsval value;
     Union *priv;
+    GType gtype;
+
+    /* For certain unions, we may be able to relax this in the future by
+     * directly allocating union memory, as we do for structures in boxed.c
+     */
+    gtype = g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) info);
+    if (gtype == G_TYPE_NONE) {
+        gjs_throw(context, "Unions must currently be registered as boxed types");
+        return JS_FALSE;
+    }
 
     /* See the comment in gjs_define_object_class() for an
      * explanation of how this all works; Union is pretty much the
@@ -522,38 +532,18 @@
 }
 
 JSObject*
-gjs_union_from_g_boxed(JSContext    *context,
-                       GType         gtype,
+gjs_union_from_c_union(JSContext    *context,
+                       GIUnionInfo  *info,
                        void         *gboxed)
 {
-    JSObject *obj;
     JSObject *proto;
-    GIBaseInfo *info;
 
     if (gboxed == NULL)
         return NULL;
 
     gjs_debug_marshal(GJS_DEBUG_GBOXED,
                       "Wrapping union %s %p with JSObject",
-                      g_type_name(gtype), gboxed);
-
-    info = g_irepository_find_by_gtype(g_irepository_get_default(),
-                                       gtype);
-
-    if (info == NULL) {
-        gjs_throw(context,
-                     "Unknown union type %s",
-                     g_type_name(gtype));
-        return NULL;
-    }
-
-    if (g_base_info_get_type( (GIBaseInfo*) info) != GI_INFO_TYPE_UNION) {
-        gjs_throw(context,
-                  "GType %s doesn't map to union in g-i?",
-                  g_base_info_get_name( (GIBaseInfo*) info));
-        g_base_info_unref( (GIBaseInfo*) info);
-        return NULL;
-    }
+                      g_base_info_get_name((GBaseInfo *)info), gboxed);
 
     proto = gjs_lookup_union_prototype(context, (GIUnionInfo*) info);
 
@@ -561,16 +551,12 @@
     unthreadsafe_template_for_constructor.info = (GIUnionInfo*) info;
     unthreadsafe_template_for_constructor.gboxed = gboxed;
 
-    obj = gjs_construct_object_dynamic(context, proto,
-                                       0, NULL);
-
-    g_base_info_unref( (GIBaseInfo*) info);
-
-    return obj;
+    return gjs_construct_object_dynamic(context, proto,
+                                        0, NULL);
 }
 
 void*
-gjs_g_boxed_from_union(JSContext    *context,
+gjs_c_union_from_union(JSContext    *context,
                        JSObject     *obj)
 {
     Union *priv;

Modified: trunk/gi/union.h
==============================================================================
--- trunk/gi/union.h	(original)
+++ trunk/gi/union.h	Wed Nov 19 22:31:12 2008
@@ -43,10 +43,10 @@
                                         GIUnionInfo  *info);
 JSClass*  gjs_lookup_union_class       (JSContext    *context,
                                         GIUnionInfo  *info);
-void*     gjs_g_boxed_from_union       (JSContext    *context,
+void*     gjs_c_union_from_union       (JSContext    *context,
                                         JSObject     *obj);
-JSObject* gjs_union_from_g_boxed       (JSContext    *context,
-                                        GType         gtype,
+JSObject* gjs_union_from_c_union       (JSContext    *context,
+                                        GIUnionInfo  *info,
                                         void         *gboxed);
 
 G_END_DECLS

Modified: trunk/gi/value.c
==============================================================================
--- trunk/gi/value.c	(original)
+++ trunk/gi/value.c	Wed Nov 19 22:31:12 2008
@@ -324,7 +324,7 @@
         } else if (JSVAL_IS_OBJECT(value)) {
             JSObject *obj;
             obj = JSVAL_TO_OBJECT(value);
-            gboxed = gjs_g_boxed_from_boxed(context, obj);
+            gboxed = gjs_c_struct_from_boxed(context, obj);
         } else {
             gjs_throw(context,
                       "Wrong type %s; boxed type %s expected",
@@ -502,11 +502,27 @@
          * their g-i info as both GBoxed */
         info = g_irepository_find_by_gtype(g_irepository_get_default(),
                                            gtype);
+        if (info == NULL) {
+            gjs_throw(context,
+                      "No introspection information found for %s",
+                      g_type_name(gtype));
+            return JS_FALSE;
+        }
 
-        if (g_base_info_get_type(info) == GI_INFO_TYPE_UNION) {
-            obj = gjs_union_from_g_boxed(context, gtype, gboxed);
-        } else {
-            obj = gjs_boxed_from_g_boxed(context, gtype, gboxed);
+        switch (g_base_info_get_type(info)) {
+        case GI_INFO_TYPE_BOXED:
+        case GI_INFO_TYPE_STRUCT:
+            obj = gjs_boxed_from_c_struct(context, (GIStructInfo *)info, gboxed);
+            break;
+        case GI_INFO_TYPE_UNION:
+            obj = gjs_union_from_c_union(context, (GIUnionInfo *)info, gboxed);
+            break;
+        default:
+            gjs_throw(context,
+                      "Unexpected introspection type %d for %s",
+                      g_base_info_get_type(info),
+                      g_type_name(gtype));
+            return JS_FALSE;
         }
         *value_p = OBJECT_TO_JSVAL(obj);
     } else if (g_type_is_a(gtype, G_TYPE_ENUM)) {

Modified: trunk/test/js/testEverythingEncapsulated.js
==============================================================================
--- trunk/test/js/testEverythingEncapsulated.js	(original)
+++ trunk/test/js/testEverythingEncapsulated.js	Wed Nov 19 22:31:12 2008
@@ -1,5 +1,39 @@
 const Everything = imports.gi.Everything;
 
+function testStruct() {
+    let struct = new Everything.TestStructA();
+    struct.some_int = 42;
+    struct.some_int8 = 43;
+    struct.some_double = 42.5;
+    assertEquals(42, struct.some_int);
+    assertEquals(43, struct.some_int8);
+    assertEquals(42.5, struct.some_double);
+}
+
+function testStructConstructor()
+{
+    // "Copy" an object from a hash of field values
+    let struct = new Everything.TestStructA({ some_int: 42,
+					      some_int8: 43,
+					      some_double: 42.5 });
+
+    assertEquals(42, struct.some_int);
+    assertEquals(43, struct.some_int8);
+    assertEquals(42.5, struct.some_double);
+
+    // Make sure we catch bad field names
+    assertRaises(function() {
+	let t = new Everything.TestStructA({ junk: 42 });
+    });
+
+    // Copy an object from another object of the same type, shortcuts to memcpy()
+    let copy = new Everything.TestStructA(struct);
+
+    assertEquals(42, copy.some_int);
+    assertEquals(43, copy.some_int8);
+    assertEquals(42.5, copy.some_double);
+}
+
 function testSimpleBoxed() {
     let simple_boxed = new Everything.TestSimpleBoxedA();
     simple_boxed.some_int = 42;



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