[gjs: 6/26] boxed: Move to C++-style API



commit 14f1253c134a4870ad9e6b2317e4072f653326f6
Author: Philip Chimento <philip chimento gmail com>
Date:   Sun Jan 20 17:44:45 2019 -0800

    boxed: Move to C++-style API
    
    This allows cleaning up the public API in boxed.h a bit, changing some
    methods to be private, adding missing error checks in calling code, and
    creating a BoxedInstance::new_for_c_struct() method with a
    BoxedInstance::NoCopy overload.
    
    The idea is to gradually provide more typesafe, C++-style APIs for all
    of the GI wrapper classes, and change calling code to use them rather
    than the old C-style APIs.

 gi/arg.cpp        | 17 ++++++-----------
 gi/boxed.cpp      | 52 +++++++++++++++++++++++++++++++++++++++++-----------
 gi/boxed.h        | 40 ++++++++++++++++------------------------
 gi/gerror.cpp     |  2 +-
 gi/repo.cpp       |  2 +-
 gi/value.cpp      |  8 ++++----
 gjs/byteArray.cpp |  9 +++++----
 7 files changed, 74 insertions(+), 56 deletions(-)
---
diff --git a/gi/arg.cpp b/gi/arg.cpp
index 7f209fbd..c68f9ef5 100644
--- a/gi/arg.cpp
+++ b/gi/arg.cpp
@@ -2907,19 +2907,14 @@ gjs_value_from_g_argument (JSContext             *context,
                 }
 
                 JSObject *obj;
-                GjsBoxedCreationFlags flags;
 
-                if (copy_structs)
-                    flags = GJS_BOXED_CREATION_NONE;
-                else if (g_type_is_a(gtype, G_TYPE_VARIANT))
-                    flags = GJS_BOXED_CREATION_NONE;
+                if (copy_structs || g_type_is_a(gtype, G_TYPE_VARIANT))
+                    obj = BoxedInstance::new_for_c_struct(
+                        context, interface_info, arg->v_pointer);
                 else
-                    flags = GJS_BOXED_CREATION_NO_COPY;
-
-                obj = gjs_boxed_from_c_struct(context,
-                                              (GIStructInfo *)interface_info,
-                                              arg->v_pointer,
-                                              flags);
+                    obj = BoxedInstance::new_for_c_struct(
+                        context, interface_info, arg->v_pointer,
+                        BoxedInstance::NoCopy());
 
                 if (obj)
                     value = JS::ObjectValue(*obj);
diff --git a/gi/boxed.cpp b/gi/boxed.cpp
index 2a471ba3..b9cc3191 100644
--- a/gi/boxed.cpp
+++ b/gi/boxed.cpp
@@ -25,6 +25,8 @@
 
 #include <string.h>
 
+#include <utility>
+
 #include "gjs/jsapi-wrapper.h"
 #include "js/GCHashTable.h"
 
@@ -948,8 +950,17 @@ bool BoxedPrototype::init(JSContext* context) {
     return true;
 }
 
-bool gjs_define_boxed_class(JSContext* context, JS::HandleObject in_object,
-                            GIStructInfo* info) {
+/*
+ * BoxedPrototype::define_class:
+ * @in_object: Object where the constructor is stored, typically a repo object.
+ * @info: Introspection info for the boxed class.
+ *
+ * Define a boxed class constructor and prototype, including all the necessary
+ * methods and properties.
+ */
+bool BoxedPrototype::define_class(JSContext* context,
+                                  JS::HandleObject in_object,
+                                  GIStructInfo* info) {
     JS::RootedObject prototype(context), constructor(context);
     GType gtype = g_registered_type_info_get_g_type(info);
     BoxedPrototype* priv = BoxedPrototype::create_class(
@@ -967,8 +978,13 @@ bool gjs_define_boxed_class(JSContext* context, JS::HandleObject in_object,
     return true;
 }
 
-JSObject* gjs_boxed_from_c_struct(JSContext* cx, GIStructInfo* info,
-                                  void* gboxed, GjsBoxedCreationFlags flags) {
+/* Helper function to make the public API more readable. The overloads are
+ * specified explicitly in the public API, but the implementation uses
+ * std::forward in order to avoid duplicating code. */
+template <typename... Args>
+JSObject* BoxedInstance::new_for_c_struct_impl(JSContext* cx,
+                                               GIStructInfo* info, void* gboxed,
+                                               Args&&... args) {
     if (gboxed == NULL)
         return NULL;
 
@@ -984,13 +1000,8 @@ JSObject* gjs_boxed_from_c_struct(JSContext* cx, GIStructInfo* info,
     if (!priv)
         return nullptr;
 
-    if ((flags & GJS_BOXED_CREATION_NO_COPY) != 0) {
-        if (!priv->init_from_c_struct(cx, gboxed, BoxedInstance::NoCopy()))
-            return nullptr;
-    } else {
-        if (!priv->init_from_c_struct(cx, gboxed))
-            return nullptr;
-    }
+    if (!priv->init_from_c_struct(cx, gboxed, std::forward<Args>(args)...))
+        return nullptr;
 
     if (priv->gtype() == G_TYPE_ERROR && !gjs_define_error_properties(cx, obj))
         return nullptr;
@@ -998,6 +1009,25 @@ JSObject* gjs_boxed_from_c_struct(JSContext* cx, GIStructInfo* info,
     return obj;
 }
 
+/*
+ * BoxedInstance::new_for_c_struct:
+ *
+ * Creates a new BoxedInstance JS object from a C boxed struct pointer.
+ *
+ * There are two overloads of this method; the NoCopy overload will simply take
+ * the passed-in pointer but not own it, while the normal method will take a
+ * reference, or if the boxed type can be directly allocated, copy the memory.
+ */
+JSObject* BoxedInstance::new_for_c_struct(JSContext* cx, GIStructInfo* info,
+                                          void* gboxed) {
+    return new_for_c_struct_impl(cx, info, gboxed);
+}
+
+JSObject* BoxedInstance::new_for_c_struct(JSContext* cx, GIStructInfo* info,
+                                          void* gboxed, NoCopy no_copy) {
+    return new_for_c_struct_impl(cx, info, gboxed, no_copy);
+}
+
 /*
  * BoxedInstance::init_from_c_struct:
  *
diff --git a/gi/boxed.h b/gi/boxed.h
index 5c134c5a..f2f004a9 100644
--- a/gi/boxed.h
+++ b/gi/boxed.h
@@ -35,15 +35,6 @@
 
 #include "js/GCHashTable.h"
 
-G_BEGIN_DECLS
-
-typedef enum {
-    GJS_BOXED_CREATION_NONE    =  0,
-    GJS_BOXED_CREATION_NO_COPY = (1 << 0)
-} GjsBoxedCreationFlags;
-
-G_END_DECLS
-
 class BoxedPrototype;
 class BoxedInstance;
 
@@ -146,10 +137,13 @@ class BoxedPrototype : public GIWrapperPrototype<BoxedBase, BoxedPrototype,
     static FieldMap* create_field_map(JSContext* cx, GIStructInfo* struct_info);
     GJS_JSAPI_RETURN_CONVENTION
     bool ensure_field_map(JSContext* cx);
+    GJS_JSAPI_RETURN_CONVENTION
+    bool define_boxed_class_fields(JSContext* cx, JS::HandleObject proto);
 
  public:
     GJS_JSAPI_RETURN_CONVENTION
-    bool define_boxed_class_fields(JSContext* cx, JS::HandleObject proto);
+    static bool define_class(JSContext* cx, JS::HandleObject in_object,
+                             GIStructInfo* info);
     GJS_JSAPI_RETURN_CONVENTION
     GIFieldInfo* lookup_field(JSContext* cx, JSString* prop_name);
 };
@@ -213,24 +207,22 @@ class BoxedInstance
  public:
     struct NoCopy {};
 
+ private:
     GJS_JSAPI_RETURN_CONVENTION
     bool init_from_c_struct(JSContext* cx, void* gboxed);
     GJS_JSAPI_RETURN_CONVENTION
     bool init_from_c_struct(JSContext* cx, void* gboxed, NoCopy);
-};
+    template <typename... Args>
+    GJS_JSAPI_RETURN_CONVENTION static JSObject* new_for_c_struct_impl(
+        JSContext* cx, GIStructInfo* info, void* gboxed, Args&&... args);
 
-G_BEGIN_DECLS
-
-GJS_JSAPI_RETURN_CONVENTION
-bool gjs_define_boxed_class(JSContext* cx, JS::HandleObject in_object,
-                            GIStructInfo* info);
-
-GJS_JSAPI_RETURN_CONVENTION
-JSObject* gjs_boxed_from_c_struct      (JSContext             *context,
-                                        GIStructInfo          *info,
-                                        void                  *gboxed,
-                                        GjsBoxedCreationFlags  flags);
-
-G_END_DECLS
+ public:
+    GJS_JSAPI_RETURN_CONVENTION
+    static JSObject* new_for_c_struct(JSContext* cx, GIStructInfo* info,
+                                      void* gboxed);
+    GJS_JSAPI_RETURN_CONVENTION
+    static JSObject* new_for_c_struct(JSContext* cx, GIStructInfo* info,
+                                      void* gboxed, NoCopy);
+};
 
 #endif  /* __GJS_BOXED_H__ */
diff --git a/gi/gerror.cpp b/gi/gerror.cpp
index 9d3c656a..056ca7e0 100644
--- a/gi/gerror.cpp
+++ b/gi/gerror.cpp
@@ -374,7 +374,7 @@ gjs_error_from_gerror(JSContext             *context,
         JSObject *retval;
 
         glib_boxed = g_irepository_find_by_name(NULL, "GLib", "Error");
-        retval = gjs_boxed_from_c_struct(context, glib_boxed, gerror, (GjsBoxedCreationFlags) 0);
+        retval = BoxedInstance::new_for_c_struct(context, glib_boxed, gerror);
 
         g_base_info_unref(glib_boxed);
         return retval;
diff --git a/gi/repo.cpp b/gi/repo.cpp
index 9ce7aa41..9dc6eec1 100644
--- a/gi/repo.cpp
+++ b/gi/repo.cpp
@@ -466,7 +466,7 @@ gjs_define_info(JSContext       *context,
         /* Fall through */
 
     case GI_INFO_TYPE_BOXED:
-        if (!gjs_define_boxed_class(context, in_object, info))
+        if (!BoxedPrototype::define_class(context, in_object, info))
             return false;
         break;
     case GI_INFO_TYPE_UNION:
diff --git a/gi/value.cpp b/gi/value.cpp
index 241c35ad..c9309aac 100644
--- a/gi/value.cpp
+++ b/gi/value.cpp
@@ -829,7 +829,6 @@ gjs_value_from_g_value_internal(JSContext             *context,
         return false;
     } else if (g_type_is_a(gtype, G_TYPE_BOXED) ||
                g_type_is_a(gtype, G_TYPE_VARIANT)) {
-        GjsBoxedCreationFlags boxed_flags;
         void *gboxed;
         JSObject *obj;
 
@@ -837,7 +836,6 @@ gjs_value_from_g_value_internal(JSContext             *context,
             gboxed = g_value_get_boxed(gvalue);
         else
             gboxed = g_value_get_variant(gvalue);
-        boxed_flags = GJS_BOXED_CREATION_NONE;
 
         /* special case GError */
         if (g_type_is_a(gtype, G_TYPE_ERROR)) {
@@ -874,8 +872,10 @@ gjs_value_from_g_value_internal(JSContext             *context,
         GIInfoType type = info.type();
         if (type == GI_INFO_TYPE_BOXED || type == GI_INFO_TYPE_STRUCT) {
             if (no_copy)
-                boxed_flags = (GjsBoxedCreationFlags) (boxed_flags | GJS_BOXED_CREATION_NO_COPY);
-            obj = gjs_boxed_from_c_struct(context, info, gboxed, boxed_flags);
+                obj = BoxedInstance::new_for_c_struct(context, info, gboxed,
+                                                      BoxedInstance::NoCopy());
+            else
+                obj = BoxedInstance::new_for_c_struct(context, info, gboxed);
         } else if (type == GI_INFO_TYPE_UNION) {
             obj = gjs_union_from_c_union(context, info, gboxed);
         } else {
diff --git a/gjs/byteArray.cpp b/gjs/byteArray.cpp
index 49d279a2..01b39a2e 100644
--- a/gjs/byteArray.cpp
+++ b/gjs/byteArray.cpp
@@ -164,7 +164,6 @@ to_gbytes_func(JSContext *context,
                JS::Value *vp)
 {
     JS::CallArgs rec = JS::CallArgsFromVp(argc, vp);
-    JSObject *ret_bytes_obj;
     GIBaseInfo *gbytes_info;
     JS::RootedObject byte_array(context);
 
@@ -183,11 +182,13 @@ to_gbytes_func(JSContext *context,
     g_irepository_require(nullptr, "GLib", "2.0", GIRepositoryLoadFlags(0),
                           nullptr);
     gbytes_info = g_irepository_find_by_gtype(NULL, G_TYPE_BYTES);
-    ret_bytes_obj = gjs_boxed_from_c_struct(context, (GIStructInfo*)gbytes_info,
-                                            bytes, GJS_BOXED_CREATION_NONE);
+    JSObject* ret_bytes_obj =
+        BoxedInstance::new_for_c_struct(context, gbytes_info, bytes);
     g_bytes_unref(bytes);
+    if (!ret_bytes_obj)
+        return false;
 
-    rec.rval().setObjectOrNull(ret_bytes_obj);
+    rec.rval().setObject(*ret_bytes_obj);
     return true;
 }
 


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