[gjs: 1/5] arg: Use argument flags for the gjs conversion functions




commit 95f83e5964db4a2cc2aa8fe0020f57d5f5dfb365
Author: Marco Trevisan (TreviƱo) <mail 3v1n0 net>
Date:   Mon Oct 5 13:58:50 2020 +0200

    arg: Use argument flags for the gjs conversion functions
    
    Make arguments more readable and easier to extend when it comes to pass
    flags to such functions, instead of rely on hard-to-maintain booleans.
    
    Using an enum class that needs some more redefinitions but gives more
    type safety, as per this adding a enum-utils.h header with some smarter
    templated definitions for operators that match all the enum class types.
    
    We automatically define operators for Enum class (only if strongly typed)
    types, just include this header and the magic will happen now.
    
    Internally using a wrapper struct to wrap the return values so that we
    can define the bool() operator and so no need to use the !! operator
    anymore for simple true checks.

 gi/arg-cache.cpp          | 16 ++++++----
 gi/arg-cache.h            |  8 +++--
 gi/arg.cpp                | 56 ++++++++++++++-------------------
 gi/arg.h                  | 30 ++++++++++++------
 gi/boxed.cpp              | 10 +++---
 gi/foreign.cpp            | 19 ++++--------
 gi/foreign.h              | 23 +++++---------
 gi/function.cpp           |  7 +++--
 gi/value.cpp              | 10 +++---
 gjs/enum-utils.h          | 79 +++++++++++++++++++++++++++++++++++++++++++++++
 modules/cairo-context.cpp |  4 +--
 modules/cairo-region.cpp  |  4 +--
 modules/cairo-surface.cpp |  4 +--
 13 files changed, 171 insertions(+), 99 deletions(-)
---
diff --git a/gi/arg-cache.cpp b/gi/arg-cache.cpp
index 90d8d0ce..550314b0 100644
--- a/gi/arg-cache.cpp
+++ b/gi/arg-cache.cpp
@@ -186,7 +186,7 @@ static bool gjs_marshal_generic_in_in(JSContext* cx, GjsArgumentCache* self,
                                    self->is_return_value()
                                        ? GJS_ARGUMENT_RETURN_VALUE
                                        : GJS_ARGUMENT_ARGUMENT,
-                                   self->transfer, self->nullable, arg);
+                                   self->transfer, self->flags, arg);
 }
 
 GJS_JSAPI_RETURN_CONVENTION
@@ -214,7 +214,7 @@ static bool gjs_marshal_explicit_array_in_in(JSContext* cx,
 
     if (!gjs_array_to_explicit_array(
             cx, value, &self->type_info, self->arg_name, GJS_ARGUMENT_ARGUMENT,
-            self->transfer, self->nullable, &data, &length))
+            self->transfer, self->flags, &data, &length))
         return false;
 
     uint8_t length_pos = self->contents.array.length_pos;
@@ -266,7 +266,7 @@ static bool gjs_marshal_callback_in(JSContext* cx, GjsArgumentCache* self,
     GjsCallbackTrampoline* trampoline;
     ffi_closure* closure;
 
-    if (value.isNull() && self->nullable) {
+    if (value.isNull() && !!(self->flags & GjsArgumentFlags::MAY_BE_NULL)) {
         closure = nullptr;
         trampoline = nullptr;
     } else {
@@ -446,7 +446,7 @@ static bool gjs_marshal_gtype_in_in(JSContext* cx, GjsArgumentCache* self,
 
 // Common code for most types that are pointers on the C side
 bool GjsArgumentCache::handle_nullable(JSContext* cx, GIArgument* arg) {
-    if (!nullable)
+    if (!(flags & GjsArgumentFlags::MAY_BE_NULL))
         return report_invalid_null(cx, arg_name);
     gjs_arg_unset<void*>(arg);
     return true;
@@ -540,7 +540,7 @@ static bool gjs_marshal_foreign_in_in(JSContext* cx, GjsArgumentCache* self,
     self->contents.tmp_foreign_info = foreign_info;
     return gjs_struct_foreign_convert_to_g_argument(
         cx, value, foreign_info, self->arg_name, GJS_ARGUMENT_ARGUMENT,
-        self->transfer, self->nullable, arg);
+        self->transfer, self->flags, arg);
 }
 
 GJS_JSAPI_RETURN_CONVENTION
@@ -1612,7 +1612,11 @@ bool gjs_arg_cache_build_arg(JSContext* cx, GjsArgumentCache* self,
     self->arg_name = g_base_info_get_name(arg);
     g_arg_info_load_type(arg, &self->type_info);
     self->transfer = g_arg_info_get_ownership_transfer(arg);
-    self->nullable = g_arg_info_may_be_null(arg);
+
+    GjsArgumentFlags flags = GjsArgumentFlags::NONE;
+    if (g_arg_info_may_be_null(arg))
+        flags |= GjsArgumentFlags::MAY_BE_NULL;
+    self->flags = flags;
 
     if (direction == GI_DIRECTION_IN)
         self->skip_out = true;
diff --git a/gi/arg-cache.h b/gi/arg-cache.h
index d6e293df..70b8c64e 100644
--- a/gi/arg-cache.h
+++ b/gi/arg-cache.h
@@ -16,6 +16,7 @@
 #include <js/RootingAPI.h>
 #include <js/TypeDecls.h>
 
+#include "gi/arg.h"
 #include "gjs/macros.h"
 
 struct GjsFunctionCallState;
@@ -43,7 +44,7 @@ struct GjsArgumentCache {
     bool skip_in : 1;
     bool skip_out : 1;
     GITransfer transfer : 2;
-    bool nullable : 1;
+    GjsArgumentFlags flags : 1;
     bool is_unsigned : 1;  // number and enum only
 
     union {
@@ -122,14 +123,15 @@ struct GjsArgumentCache {
         arg_name = "instance parameter";
         // Some calls accept null for the instance, but generally in an object
         // oriented language it's wrong to call a method on null
-        nullable = false;
+        flags = GjsArgumentFlags::NONE;
         skip_out = true;
     }
 
     void set_return_value() {
         arg_pos = RETURN_VALUE;
         arg_name = "return value";
-        nullable = false;  // We don't really care for return values
+        flags =
+            GjsArgumentFlags::NONE;  // We don't really care for return values
     }
     [[nodiscard]] bool is_return_value() { return arg_pos == RETURN_VALUE; }
 };
diff --git a/gi/arg.cpp b/gi/arg.cpp
index df8205fc..0a5d16db 100644
--- a/gi/arg.cpp
+++ b/gi/arg.cpp
@@ -422,8 +422,8 @@ GJS_JSAPI_RETURN_CONVENTION static bool gjs_array_to_g_list(
          * gobject-introspection needs to tell us this.
          * Always say they can't for now.
          */
-        if (!gjs_value_to_g_argument(cx, elem, param_info, NULL,
-                                     GJS_ARGUMENT_LIST_ELEMENT, transfer, false,
+        if (!gjs_value_to_g_argument(cx, elem, param_info,
+                                     GJS_ARGUMENT_LIST_ELEMENT, transfer,
                                      &elem_arg)) {
             return false;
         }
@@ -666,7 +666,7 @@ gjs_object_to_g_hash(JSContext   *context,
             // Type check and convert value to a C type
             !gjs_value_to_g_argument(context, val_js, val_param_info, nullptr,
                                      GJS_ARGUMENT_HASH_ELEMENT, transfer,
-                                     true /* allow null */, &val_arg))
+                                     GjsArgumentFlags::MAY_BE_NULL, &val_arg))
             return false;
 
         GITypeTag val_type = g_type_info_get_tag(val_param_info);
@@ -888,10 +888,8 @@ gjs_array_to_ptrarray(JSContext   *context,
         success = gjs_value_to_g_argument (context,
                                            elem,
                                            param_info,
-                                           NULL, /* arg name */
                                            GJS_ARGUMENT_ARRAY_ELEMENT,
                                            transfer,
-                                           false, /* absent better information, false for now */
                                            &arg);
 
         if (!success) {
@@ -939,10 +937,8 @@ static bool gjs_array_to_flat_struct_array(JSContext* cx,
 
         GIArgument arg;
         if (!gjs_value_to_g_argument(cx, elem, param_info,
-                                     /* arg_name = */ nullptr,
                                      GJS_ARGUMENT_ARRAY_ELEMENT,
-                                     GI_TRANSFER_NOTHING,
-                                     /* may_be_null = */ false, &arg))
+                                     GI_TRANSFER_NOTHING, &arg))
             return false;
 
         memcpy(&flat_array[struct_size * i], gjs_arg_get<void*>(&arg),
@@ -1243,7 +1239,7 @@ GJS_JSAPI_RETURN_CONVENTION
 bool gjs_array_to_explicit_array(JSContext* context, JS::HandleValue value,
                                  GITypeInfo* type_info, const char* arg_name,
                                  GjsArgumentType arg_type, GITransfer transfer,
-                                 bool may_be_null, void** contents,
+                                 GjsArgumentFlags flags, void** contents,
                                  size_t* length_p) {
     bool found_length;
 
@@ -1254,7 +1250,7 @@ bool gjs_array_to_explicit_array(JSContext* context, JS::HandleValue value,
 
     GjsAutoTypeInfo param_info = g_type_info_get_param_type(type_info, 0);
 
-    if ((value.isNull() && !may_be_null) ||
+    if ((value.isNull() && !(flags & GjsArgumentFlags::MAY_BE_NULL)) ||
         (!value.isString() && !value.isObjectOrNull())) {
         throw_invalid_argument(context, value, param_info, arg_name, arg_type);
         return false;
@@ -1588,16 +1584,10 @@ GJS_JSAPI_RETURN_CONVENTION inline static bool gjs_arg_set_from_js_value(
     return true;
 }
 
-bool
-gjs_value_to_g_argument(JSContext      *context,
-                        JS::HandleValue value,
-                        GITypeInfo     *type_info,
-                        const char     *arg_name,
-                        GjsArgumentType arg_type,
-                        GITransfer      transfer,
-                        bool            may_be_null,
-                        GArgument      *arg)
-{
+bool gjs_value_to_g_argument(JSContext* context, JS::HandleValue value,
+                             GITypeInfo* type_info, const char* arg_name,
+                             GjsArgumentType arg_type, GITransfer transfer,
+                             GjsArgumentFlags flags, GIArgument* arg) {
     GITypeTag type_tag = g_type_info_get_tag(type_info);
 
     gjs_debug_marshal(
@@ -1776,7 +1766,7 @@ gjs_value_to_g_argument(JSContext      *context,
                 g_struct_info_is_foreign(interface_info)) {
                 return gjs_struct_foreign_convert_to_g_argument(
                     context, value, interface_info, arg_name, arg_type,
-                    transfer, may_be_null, arg);
+                    transfer, flags, arg);
             }
 
             if (!value_to_interface_gi_argument(
@@ -1798,7 +1788,7 @@ gjs_value_to_g_argument(JSContext      *context,
     case GI_TYPE_TAG_GHASH:
         if (value.isNull()) {
             gjs_arg_set(arg, nullptr);
-            if (!may_be_null) {
+            if (!(flags & GjsArgumentFlags::MAY_BE_NULL)) {
                 wrong = true;
                 report_type_mismatch = true;
             }
@@ -1861,7 +1851,7 @@ _Pragma("GCC diagnostic pop")
         }
 
         if (!gjs_array_to_explicit_array(context, value, type_info, arg_name,
-                                         arg_type, transfer, may_be_null, &data,
+                                         arg_type, transfer, flags, &data,
                                          &length)) {
             wrong = true;
             break;
@@ -1917,7 +1907,8 @@ _Pragma("GCC diagnostic pop")
             throw_invalid_argument(context, value, type_info, arg_name, arg_type);
         }
         return false;
-    } else if (nullable_type && !gjs_arg_get<void*>(arg) && !may_be_null) {
+    } else if (nullable_type && !gjs_arg_get<void*>(arg) &&
+               !(flags & GjsArgumentFlags::MAY_BE_NULL)) {
         GjsAutoChar display_name =
             gjs_argument_display_name(arg_name, arg_type);
         gjs_throw(context, "%s (type %s) may not be null", display_name.get(),
@@ -2032,18 +2023,19 @@ gjs_value_to_arg(JSContext      *context,
                  GIArgInfo      *arg_info,
                  GIArgument     *arg)
 {
+    GjsArgumentFlags flags = GjsArgumentFlags::NONE;
     GITypeInfo type_info;
 
     g_arg_info_load_type(arg_info, &type_info);
 
-    return gjs_value_to_g_argument(context, value,
-                                   &type_info,
-                                   g_base_info_get_name( (GIBaseInfo*) arg_info),
-                                   (g_arg_info_is_return_value(arg_info) ?
-                                    GJS_ARGUMENT_RETURN_VALUE : GJS_ARGUMENT_ARGUMENT),
-                                   g_arg_info_get_ownership_transfer(arg_info),
-                                   g_arg_info_may_be_null(arg_info),
-                                   arg);
+    if (g_arg_info_may_be_null(arg_info))
+        flags |= GjsArgumentFlags::MAY_BE_NULL;
+
+    return gjs_value_to_g_argument(
+        context, value, &type_info, g_base_info_get_name(arg_info),
+        (g_arg_info_is_return_value(arg_info) ? GJS_ARGUMENT_RETURN_VALUE
+                                              : GJS_ARGUMENT_ARGUMENT),
+        g_arg_info_get_ownership_transfer(arg_info), flags, arg);
 }
 
 template <typename T>
diff --git a/gi/arg.h b/gi/arg.h
index 3fca4077..8b2f4d61 100644
--- a/gi/arg.h
+++ b/gi/arg.h
@@ -15,6 +15,7 @@
 
 #include <js/TypeDecls.h>
 
+#include "gjs/enum-utils.h"
 #include "gjs/macros.h"
 
 // Different roles for a GIArgument; currently used only in exception and debug
@@ -28,6 +29,11 @@ typedef enum {
     GJS_ARGUMENT_ARRAY_ELEMENT
 } GjsArgumentType;
 
+enum class GjsArgumentFlags : uint8_t {
+    NONE = 0,
+    MAY_BE_NULL = 1 << 0,
+};
+
 [[nodiscard]] char* gjs_argument_display_name(const char* arg_name,
                                               GjsArgumentType arg_type);
 
@@ -41,20 +47,26 @@ GJS_JSAPI_RETURN_CONVENTION
 bool gjs_array_to_explicit_array(JSContext* cx, JS::HandleValue value,
                                  GITypeInfo* type_info, const char* arg_name,
                                  GjsArgumentType arg_type, GITransfer transfer,
-                                 bool may_be_null, void** contents,
+                                 GjsArgumentFlags flags, void** contents,
                                  size_t* length_p);
 
 void gjs_gi_argument_init_default(GITypeInfo* type_info, GIArgument* arg);
 
 GJS_JSAPI_RETURN_CONVENTION
-bool gjs_value_to_g_argument (JSContext      *context,
-                              JS::HandleValue value,
-                              GITypeInfo     *type_info,
-                              const char     *arg_name,
-                              GjsArgumentType argument_type,
-                              GITransfer      transfer,
-                              bool            may_be_null,
-                              GArgument      *arg);
+bool gjs_value_to_g_argument(JSContext* cx, JS::HandleValue value,
+                             GITypeInfo* type_info, const char* arg_name,
+                             GjsArgumentType argument_type, GITransfer transfer,
+                             GjsArgumentFlags flags, GIArgument* arg);
+
+GJS_JSAPI_RETURN_CONVENTION
+bool inline gjs_value_to_g_argument(JSContext* cx, JS::HandleValue value,
+                                    GITypeInfo* type_info,
+                                    GjsArgumentType argument_type,
+                                    GITransfer transfer, GIArgument* arg) {
+    return gjs_value_to_g_argument(cx, value, type_info, nullptr /* arg_name */,
+                                   argument_type, transfer,
+                                   GjsArgumentFlags::NONE, arg);
+}
 
 GJS_JSAPI_RETURN_CONVENTION
 bool gjs_value_from_g_argument(JSContext             *context,
diff --git a/gi/boxed.cpp b/gi/boxed.cpp
index ed879406..d14dbc74 100644
--- a/gi/boxed.cpp
+++ b/gi/boxed.cpp
@@ -633,12 +633,10 @@ bool BoxedInstance::field_setter_impl(JSContext* context,
         }
     }
 
-    if (!gjs_value_to_g_argument(context, value,
-                                 type_info,
-                                 g_base_info_get_name ((GIBaseInfo *)field_info),
-                                 GJS_ARGUMENT_FIELD,
-                                 GI_TRANSFER_NOTHING,
-                                 true, &arg))
+    if (!gjs_value_to_g_argument(context, value, type_info,
+                                 g_base_info_get_name(field_info),
+                                 GJS_ARGUMENT_FIELD, GI_TRANSFER_NOTHING,
+                                 GjsArgumentFlags::MAY_BE_NULL, &arg))
         return false;
 
     bool success = true;
diff --git a/gi/foreign.cpp b/gi/foreign.cpp
index b126977f..d7a03257 100644
--- a/gi/foreign.cpp
+++ b/gi/foreign.cpp
@@ -11,7 +11,6 @@
 
 #include <js/TypeDecls.h>
 
-#include "gi/arg.h"
 #include "gi/foreign.h"
 #include "gjs/context-private.h"
 #include "gjs/jsapi-util.h"
@@ -109,24 +108,18 @@ void gjs_struct_foreign_register(const char* gi_namespace,
     return retval;
 }
 
-bool
-gjs_struct_foreign_convert_to_g_argument(JSContext      *context,
-                                         JS::Value       value,
-                                         GIBaseInfo     *interface_info,
-                                         const char     *arg_name,
-                                         GjsArgumentType argument_type,
-                                         GITransfer      transfer,
-                                         bool            may_be_null,
-                                         GArgument      *arg)
-{
+bool gjs_struct_foreign_convert_to_g_argument(
+    JSContext* context, JS::Value value, GIBaseInfo* interface_info,
+    const char* arg_name, GjsArgumentType argument_type, GITransfer transfer,
+    GjsArgumentFlags flags, GArgument* arg) {
     GjsForeignInfo *foreign;
 
     foreign = gjs_struct_foreign_lookup(context, interface_info);
     if (!foreign)
         return false;
 
-    if (!foreign->to_func(context, value, arg_name,
-                           argument_type, transfer, may_be_null, arg))
+    if (!foreign->to_func(context, value, arg_name, argument_type, transfer,
+                          flags, arg))
         return false;
 
     return true;
diff --git a/gi/foreign.h b/gi/foreign.h
index b6a9d6b8..167f2527 100644
--- a/gi/foreign.h
+++ b/gi/foreign.h
@@ -16,13 +16,10 @@
 #include "gi/arg.h"
 #include "gjs/macros.h"
 
-typedef bool (*GjsArgOverrideToGArgumentFunc) (JSContext      *context,
-                                               JS::Value       value,
-                                               const char     *arg_name,
-                                               GjsArgumentType argument_type,
-                                               GITransfer      transfer,
-                                               bool            may_be_null,
-                                               GArgument      *arg);
+typedef bool (*GjsArgOverrideToGArgumentFunc)(
+    JSContext* context, JS::Value value, const char* arg_name,
+    GjsArgumentType argument_type, GITransfer transfer, GjsArgumentFlags flags,
+    GArgument* arg);
 
 typedef bool (*GjsArgOverrideFromGArgumentFunc) (JSContext             *context,
                                                  JS::MutableHandleValue value_p,
@@ -42,14 +39,10 @@ void gjs_struct_foreign_register(const char* gi_namespace,
                                  const char* type_name, GjsForeignInfo* info);
 
 GJS_JSAPI_RETURN_CONVENTION
-bool  gjs_struct_foreign_convert_to_g_argument   (JSContext      *context,
-                                                  JS::Value       value,
-                                                  GIBaseInfo     *interface_info,
-                                                  const char     *arg_name,
-                                                  GjsArgumentType argument_type,
-                                                  GITransfer      transfer,
-                                                  bool            may_be_null,
-                                                  GArgument      *arg);
+bool gjs_struct_foreign_convert_to_g_argument(
+    JSContext* context, JS::Value value, GIBaseInfo* interface_info,
+    const char* arg_name, GjsArgumentType argument_type, GITransfer transfer,
+    GjsArgumentFlags flags, GArgument* arg);
 GJS_JSAPI_RETURN_CONVENTION
 bool gjs_struct_foreign_convert_from_g_argument(JSContext             *context,
                                                 JS::MutableHandleValue value_p,
diff --git a/gi/function.cpp b/gi/function.cpp
index 5b74fde0..689b8e52 100644
--- a/gi/function.cpp
+++ b/gi/function.cpp
@@ -424,8 +424,8 @@ bool GjsCallbackTrampoline::callback_closure_inner(
         /* non-void return value, no out args. Should
          * be a single return value. */
         if (!gjs_value_to_g_argument(context, rval, ret_type, "callback",
-                                     GJS_ARGUMENT_RETURN_VALUE, transfer, true,
-                                     &argument))
+                                     GJS_ARGUMENT_RETURN_VALUE, transfer,
+                                     GjsArgumentFlags::MAY_BE_NULL, &argument))
             return false;
 
         set_return_ffi_arg_from_giargument(ret_type, result, &argument);
@@ -474,7 +474,8 @@ bool GjsCallbackTrampoline::callback_closure_inner(
 
             if (!gjs_value_to_g_argument(context, elem, ret_type, "callback",
                                          GJS_ARGUMENT_RETURN_VALUE, transfer,
-                                         true, &argument))
+                                         GjsArgumentFlags::MAY_BE_NULL,
+                                         &argument))
                 return false;
 
             set_return_ffi_arg_from_giargument(ret_type, result, &argument);
diff --git a/gi/value.cpp b/gi/value.cpp
index a7c401ab..bca3aec7 100644
--- a/gi/value.cpp
+++ b/gi/value.cpp
@@ -564,12 +564,10 @@ gjs_value_to_g_value_internal(JSContext      *context,
                         g_struct_info_is_foreign ((GIStructInfo*)registered)) {
                         GArgument arg;
 
-                        if (!gjs_struct_foreign_convert_to_g_argument (context, value,
-                                                                       registered,
-                                                                       NULL,
-                                                                       GJS_ARGUMENT_ARGUMENT,
-                                                                       GI_TRANSFER_NOTHING,
-                                                                       true, &arg))
+                        if (!gjs_struct_foreign_convert_to_g_argument(
+                                context, value, registered, nullptr,
+                                GJS_ARGUMENT_ARGUMENT, GI_TRANSFER_NOTHING,
+                                GjsArgumentFlags::MAY_BE_NULL, &arg))
                             return false;
 
                         gboxed = gjs_arg_get<void*>(&arg);
diff --git a/gjs/enum-utils.h b/gjs/enum-utils.h
new file mode 100644
index 00000000..80044b6d
--- /dev/null
+++ b/gjs/enum-utils.h
@@ -0,0 +1,79 @@
+/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+// SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
+// SPDX-FileCopyrightText: 2020 Marco Trevisan <marco trevisan canonical com>
+
+#pragma once
+
+#include <type_traits>
+
+namespace GjsEnum {
+
+template <typename T>
+constexpr bool is_class() {
+    if constexpr (std::is_enum_v<T>) {
+        return !std::is_convertible_v<T, std::underlying_type_t<T>>;
+    }
+    return false;
+}
+
+template <class EnumType>
+struct WrapperImpl {
+    EnumType e;
+
+    constexpr explicit WrapperImpl(EnumType const& en) : e(en) {}
+    constexpr explicit WrapperImpl(std::underlying_type_t<EnumType> const& en)
+        : e(static_cast<EnumType>(en)) {}
+    constexpr explicit operator bool() const { return static_cast<bool>(e); }
+    constexpr operator EnumType() const { return e; }
+    constexpr operator std::underlying_type_t<EnumType>() const {
+        return std::underlying_type_t<EnumType>(e);
+    }
+};
+
+template <class EnumType>
+using Wrapper =
+    std::conditional_t<is_class<EnumType>(), WrapperImpl<EnumType>, void>;
+}  // namespace GjsEnum
+
+template <class EnumType, class Wrapped = GjsEnum::Wrapper<EnumType>>
+constexpr std::enable_if_t<GjsEnum::is_class<EnumType>(), Wrapped> operator&(
+    EnumType const& first, EnumType const& second) {
+    return static_cast<Wrapped>(static_cast<Wrapped>(first) &
+                                static_cast<Wrapped>(second));
+}
+
+template <class EnumType, class Wrapped = GjsEnum::Wrapper<EnumType>>
+constexpr std::enable_if_t<GjsEnum::is_class<EnumType>(), Wrapped> operator|(
+    EnumType const& first, EnumType const& second) {
+    return static_cast<Wrapped>(static_cast<Wrapped>(first) |
+                                static_cast<Wrapped>(second));
+}
+
+template <class EnumType, class Wrapped = GjsEnum::Wrapper<EnumType>>
+constexpr std::enable_if_t<GjsEnum::is_class<EnumType>(), Wrapped> operator^(
+    EnumType const& first, EnumType const& second) {
+    return static_cast<Wrapped>(static_cast<Wrapped>(first) ^
+                                static_cast<Wrapped>(second));
+}
+
+template <class EnumType, class Wrapped = GjsEnum::Wrapper<EnumType>>
+constexpr std::enable_if_t<GjsEnum::is_class<EnumType>(), Wrapped&> operator|=(
+    EnumType& first,  //  NOLINT(runtime/references)
+    EnumType const& second) {
+    first = (first | second);
+    return reinterpret_cast<Wrapped&>(first);
+}
+
+template <class EnumType, class Wrapped = GjsEnum::Wrapper<EnumType>>
+constexpr std::enable_if_t<GjsEnum::is_class<EnumType>(), Wrapped&> operator&=(
+    EnumType& first,  //  NOLINT(runtime/references)
+    EnumType const& second) {
+    first = (first & second);
+    return reinterpret_cast<Wrapped&>(first);
+}
+
+template <class EnumType, class Wrapped = GjsEnum::Wrapper<EnumType>>
+constexpr std::enable_if_t<GjsEnum::is_class<EnumType>(), EnumType> operator~(
+    EnumType const& first) {
+    return static_cast<EnumType>(~static_cast<Wrapped>(first));
+}
diff --git a/modules/cairo-context.cpp b/modules/cairo-context.cpp
index a8049b1c..d674096c 100644
--- a/modules/cairo-context.cpp
+++ b/modules/cairo-context.cpp
@@ -963,10 +963,10 @@ gjs_cairo_context_get_context(JSContext       *context,
 
 [[nodiscard]] static bool context_to_g_argument(
     JSContext* context, JS::Value value, const char* arg_name,
-    GjsArgumentType argument_type, GITransfer transfer, bool may_be_null,
+    GjsArgumentType argument_type, GITransfer transfer, GjsArgumentFlags flags,
     GIArgument* arg) {
     if (value.isNull()) {
-        if (!may_be_null) {
+        if (!(flags & GjsArgumentFlags::MAY_BE_NULL)) {
             GjsAutoChar display_name =
                 gjs_argument_display_name(arg_name, argument_type);
             gjs_throw(context, "%s may not be null", display_name.get());
diff --git a/modules/cairo-region.cpp b/modules/cairo-region.cpp
index effc0724..a5385274 100644
--- a/modules/cairo-region.cpp
+++ b/modules/cairo-region.cpp
@@ -279,10 +279,10 @@ gjs_cairo_region_from_region(JSContext *context,
 
 [[nodiscard]] static bool region_to_g_argument(
     JSContext* context, JS::Value value, const char* arg_name,
-    GjsArgumentType argument_type, GITransfer transfer, bool may_be_null,
+    GjsArgumentType argument_type, GITransfer transfer, GjsArgumentFlags flags,
     GIArgument* arg) {
     if (value.isNull()) {
-        if (!may_be_null) {
+        if (!(flags & GjsArgumentFlags::MAY_BE_NULL)) {
             GjsAutoChar display_name =
                 gjs_argument_display_name(arg_name, argument_type);
             gjs_throw(context, "%s may not be null", display_name.get());
diff --git a/modules/cairo-surface.cpp b/modules/cairo-surface.cpp
index 0f0f1f5d..a824af1d 100644
--- a/modules/cairo-surface.cpp
+++ b/modules/cairo-surface.cpp
@@ -224,10 +224,10 @@ cairo_surface_t* gjs_cairo_surface_get_surface(
 
 [[nodiscard]] static bool surface_to_g_argument(
     JSContext* context, JS::Value value, const char* arg_name,
-    GjsArgumentType argument_type, GITransfer transfer, bool may_be_null,
+    GjsArgumentType argument_type, GITransfer transfer, GjsArgumentFlags flags,
     GIArgument* arg) {
     if (value.isNull()) {
-        if (!may_be_null) {
+        if (!(flags & GjsArgumentFlags::MAY_BE_NULL)) {
             GjsAutoChar display_name =
                 gjs_argument_display_name(arg_name, argument_type);
             gjs_throw(context, "%s may not be null", display_name.get());


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