LCOV - code coverage report
Current view: top level - gi - value.h (source / functions) Coverage Total Hit
Test: gjs- Code Coverage Lines: 77.5 % 71 55
Test Date: 2025-02-04 05:33:54 Functions: 76.9 % 65 50
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 50.0 % 10 5

             Branch data     Line data    Source code
       1                 :             : /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
       2                 :             : // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
       3                 :             : // SPDX-FileCopyrightText: 2008 litl, LLC
       4                 :             : 
       5                 :             : #ifndef GI_VALUE_H_
       6                 :             : #define GI_VALUE_H_
       7                 :             : 
       8                 :             : #include <config.h>
       9                 :             : 
      10                 :             : #include <stdint.h>
      11                 :             : 
      12                 :             : #include <sstream>  // for ostringstream
      13                 :             : #include <string>   // for string
      14                 :             : #include <type_traits>
      15                 :             : #include <utility>  // for move, swap
      16                 :             : #include <vector>   // for vector
      17                 :             : 
      18                 :             : #include <glib-object.h>
      19                 :             : #include <glib.h>    // for FALSE, g_clear_pointer, g_free, g_variant_...
      20                 :             : 
      21                 :             : #include <js/TypeDecls.h>
      22                 :             : 
      23                 :             : #include "gi/arg-types-inl.h"
      24                 :             : #include "gi/utils-inl.h"
      25                 :             : #include "gjs/auto.h"
      26                 :             : #include "gjs/macros.h"
      27                 :             : 
      28                 :             : namespace Gjs {
      29                 :             : struct AutoGValue : GValue {
      30                 :        1667 :     AutoGValue() : GValue(G_VALUE_INIT) {
      31                 :             :         static_assert(sizeof(AutoGValue) == sizeof(GValue));
      32                 :        1667 :     }
      33                 :        1590 :     explicit AutoGValue(GType gtype) : AutoGValue() {
      34                 :        1590 :         g_value_init(this, gtype);
      35                 :        1590 :     }
      36                 :           0 :     AutoGValue(AutoGValue const& src) : AutoGValue(G_VALUE_TYPE(&src)) {
      37                 :           0 :         g_value_copy(&src, this);
      38                 :           0 :     }
      39                 :             :     AutoGValue& operator=(AutoGValue other) {
      40                 :             :         // We need to cast to GValue here not to make swap to recurse here
      41                 :             :         std::swap(*static_cast<GValue*>(this), *static_cast<GValue*>(&other));
      42                 :             :         return *this;
      43                 :             :     }
      44                 :             :     AutoGValue(AutoGValue&& src) {
      45                 :             :         switch (G_VALUE_TYPE(&src)) {
      46                 :             :             case G_TYPE_NONE:
      47                 :             :             case G_TYPE_CHAR:
      48                 :             :             case G_TYPE_UCHAR:
      49                 :             :             case G_TYPE_BOOLEAN:
      50                 :             :             case G_TYPE_INT:
      51                 :             :             case G_TYPE_UINT:
      52                 :             :             case G_TYPE_LONG:
      53                 :             :             case G_TYPE_ULONG:
      54                 :             :             case G_TYPE_INT64:
      55                 :             :             case G_TYPE_UINT64:
      56                 :             :             case G_TYPE_FLOAT:
      57                 :             :             case G_TYPE_DOUBLE:
      58                 :             :                 *static_cast<GValue*>(this) =
      59                 :             :                     std::move(static_cast<GValue const&&>(src));
      60                 :             :                 break;
      61                 :             :             default:
      62                 :             :                 // We can't safely move in complex cases, so let's just copy
      63                 :             :                 this->steal();
      64                 :             :                 *this = src;
      65                 :             :                 g_value_unset(&src);
      66                 :             :         }
      67                 :             :     }
      68                 :           3 :     void steal() { *static_cast<GValue*>(this) = G_VALUE_INIT; }
      69                 :        1666 :     ~AutoGValue() { g_value_unset(this); }
      70                 :             : };
      71                 :             : 
      72                 :             : /* This is based on what GMarshalling does, it is an unsupported API but
      73                 :             :  * gjs can be considered a glib implementation for JS, so it is fine
      74                 :             :  * to do this, but we need to be in sync with gmarshal.c in GLib.
      75                 :             :  * https://gitlab.gnome.org/GNOME/glib/-/blob/main/gobject/gmarshal.c
      76                 :             :  */
      77                 :             : 
      78                 :             : template <typename TAG>
      79                 :        1768 : inline constexpr Tag::RealT<TAG> gvalue_get(const GValue* gvalue) {
      80                 :             :     if constexpr (std::is_same_v<TAG, Tag::GBoolean>)
      81                 :          11 :         return gvalue->data[0].v_int != FALSE;
      82                 :             :     else if constexpr (std::is_same_v<TAG, bool>)
      83                 :          42 :         return gvalue->data[0].v_int != FALSE;
      84                 :             :     else if constexpr (std::is_same_v<TAG, char>)
      85                 :             :         return gvalue->data[0].v_int;
      86                 :             :     else if constexpr (std::is_same_v<TAG, signed char>)
      87                 :          35 :         return gvalue->data[0].v_int;
      88                 :             :     else if constexpr (std::is_same_v<TAG, unsigned char>)
      89                 :          19 :         return gvalue->data[0].v_uint;
      90                 :             :     else if constexpr (std::is_same_v<TAG, int>)
      91                 :         184 :         return gvalue->data[0].v_int;
      92                 :             :     else if constexpr (std::is_same_v<TAG, unsigned int>)
      93                 :          20 :         return gvalue->data[0].v_uint;
      94                 :             :     else if constexpr (std::is_same_v<TAG, Tag::Long>)
      95                 :          56 :         return gvalue->data[0].v_long;
      96                 :             :     else if constexpr (std::is_same_v<TAG, Tag::UnsignedLong>)
      97                 :          21 :         return gvalue->data[0].v_ulong;
      98                 :             :     else if constexpr (std::is_same_v<TAG, int64_t>)
      99                 :          39 :         return gvalue->data[0].v_int64;
     100                 :             :     else if constexpr (std::is_same_v<TAG, uint64_t>)
     101                 :          29 :         return gvalue->data[0].v_uint64;
     102                 :             :     else if constexpr (std::is_same_v<TAG, Tag::Enum>)
     103                 :             :         return gvalue->data[0].v_long;
     104                 :             :     else if constexpr (std::is_same_v<TAG, Tag::UnsignedEnum>)
     105                 :             :         return gvalue->data[0].v_ulong;
     106                 :             :     else if constexpr (std::is_same_v<TAG, float>)
     107                 :          23 :         return gvalue->data[0].v_float;
     108                 :             :     else if constexpr (std::is_same_v<TAG, double>)
     109                 :          36 :         return gvalue->data[0].v_double;
     110                 :             :     else if constexpr (std::is_same_v<TAG, Tag::GType>)
     111                 :           5 :         return gjs_pointer_to_int<GType>(gvalue->data[0].v_pointer);
     112                 :             :     else if constexpr (!std::is_pointer_v<TAG>)
     113                 :             :         static_assert(std::is_pointer_v<TAG>,
     114                 :             :                       "Scalar type not properly handled");
     115                 :             :     else
     116                 :        1248 :         return static_cast<TAG>(gvalue->data[0].v_pointer);
     117                 :             : }
     118                 :             : 
     119                 :             : template <typename TAG>
     120                 :        9880 : void gvalue_set(GValue* gvalue, Tag::RealT<TAG> value) {
     121                 :             :     if constexpr (std::is_same_v<TAG, Tag::GBoolean>)
     122                 :           8 :         gvalue->data[0].v_int = value != FALSE;
     123                 :             :     else if constexpr (std::is_same_v<TAG, bool>)
     124                 :        9280 :         gvalue->data[0].v_int = value != false;
     125                 :             :     else if constexpr (std::is_same_v<TAG, char>)
     126                 :             :         gvalue->data[0].v_int = value;
     127                 :             :     else if constexpr (std::is_same_v<TAG, signed char>)
     128                 :          24 :         gvalue->data[0].v_int = value;
     129                 :             :     else if constexpr (std::is_same_v<TAG, unsigned char>)
     130                 :          24 :         gvalue->data[0].v_uint = value;
     131                 :             :     else if constexpr (std::is_same_v<TAG, int>)
     132                 :         239 :         gvalue->data[0].v_int = value;
     133                 :             :     else if constexpr (std::is_same_v<TAG, unsigned int>)
     134                 :          25 :         gvalue->data[0].v_uint = value;
     135                 :             :     else if constexpr (std::is_same_v<TAG, Tag::Long>)
     136                 :           6 :         gvalue->data[0].v_long = value;
     137                 :             :     else if constexpr (std::is_same_v<TAG, Tag::UnsignedLong>)
     138                 :           6 :         gvalue->data[0].v_ulong = value;
     139                 :             :     else if constexpr (std::is_same_v<TAG, int64_t>)
     140                 :          39 :         gvalue->data[0].v_int64 = value;
     141                 :             :     else if constexpr (std::is_same_v<TAG, uint64_t>)
     142                 :          31 :         gvalue->data[0].v_uint64 = value;
     143                 :             :     else if constexpr (std::is_same_v<TAG, Tag::Enum>)
     144                 :             :         gvalue->data[0].v_long = value;
     145                 :             :     else if constexpr (std::is_same_v<TAG, Tag::UnsignedEnum>)
     146                 :             :         gvalue->data[0].v_ulong = value;
     147                 :             :     else if constexpr (std::is_same_v<TAG, float>)
     148                 :          91 :         gvalue->data[0].v_float = value;
     149                 :             :     else if constexpr (std::is_same_v<TAG, double>)
     150                 :          97 :         gvalue->data[0].v_double = value;
     151                 :             :     else if constexpr (std::is_same_v<TAG, Tag::GType>)
     152                 :          10 :         gvalue->data[0].v_pointer = gjs_int_to_pointer(value);
     153                 :             :     else
     154                 :             :         static_assert(!std::is_scalar_v<Tag::RealT<TAG>>,
     155                 :             :                       "Scalar type not properly handled");
     156                 :        9880 : }
     157                 :             : 
     158                 :             : // Specialization for types where TAG and RealT<TAG> are the same type, to allow
     159                 :             : // inferring template parameter
     160                 :             : template <typename T,
     161                 :             :           typename = std::enable_if_t<std::is_same_v<Gjs::Tag::RealT<T>, T>>>
     162                 :        9663 : inline void gvalue_set(GValue* gvalue, T value) {
     163                 :        9663 :     gvalue_set<T>(gvalue, value);
     164                 :        9663 : }
     165                 :             : 
     166                 :             : template <typename T>
     167                 :             : void gvalue_set(GValue* gvalue, T* value) = delete;
     168                 :             : 
     169                 :             : template <>
     170                 :         108 : inline void gvalue_set(GValue* gvalue, char* value) {
     171         [ -  + ]:         108 :     g_clear_pointer(&gvalue->data[0].v_pointer, g_free);
     172                 :         108 :     gvalue->data[0].v_pointer = g_strdup(value);
     173                 :         108 : }
     174                 :             : 
     175                 :             : template <>
     176                 :          49 : inline void gvalue_set(GValue* gvalue, GObject* value) {
     177                 :          49 :     g_set_object(&gvalue->data[0].v_pointer, value);
     178                 :          49 : }
     179                 :             : 
     180                 :             : template <>
     181                 :          53 : inline void gvalue_set(GValue* gvalue, GVariant* value) {
     182         [ -  + ]:          53 :     g_clear_pointer(reinterpret_cast<GVariant**>(&gvalue->data[0].v_pointer),
     183                 :             :                     g_variant_unref);
     184         [ +  + ]:          53 :     gvalue->data[0].v_pointer = value ? g_variant_ref(value) : nullptr;
     185                 :          53 : }
     186                 :             : 
     187                 :             : template <typename T>
     188                 :           0 : void gvalue_set(GValue* gvalue, std::nullptr_t) {
     189                 :             :     if constexpr (std::is_same_v<T, char*>) {
     190         [ #  # ]:           0 :         g_clear_pointer(&gvalue->data[0].v_pointer, g_free);
     191                 :             :     } else if constexpr (std::is_same_v<T, GObject*>) {
     192                 :             :         g_set_object(&gvalue->data[0].v_pointer, nullptr);
     193                 :             :     } else if constexpr (std::is_same_v<T, GVariant*>) {
     194                 :             :         g_clear_pointer(reinterpret_cast<T*>(&gvalue->data[0].v_pointer),
     195                 :             :                         g_variant_unref);
     196                 :             :         gvalue->data[0].v_pointer = nullptr;
     197                 :             :     } else {
     198                 :             :         static_assert(!std::is_pointer_v<T>, "Not a known pointer type");
     199                 :             :     }
     200                 :           0 : }
     201                 :             : 
     202                 :             : template <typename TAG>
     203                 :          16 : void gvalue_take(GValue* gvalue, Tag::RealT<TAG> value) {
     204                 :             :     using T = Tag::RealT<TAG>;
     205                 :             :     if constexpr (!std::is_pointer_v<T>) {
     206                 :             :         return gvalue_set<TAG>(gvalue, value);
     207                 :             :     }
     208                 :             : 
     209                 :             :     if constexpr (std::is_same_v<T, char*>) {
     210         [ -  + ]:          16 :         g_clear_pointer(&gvalue->data[0].v_pointer, g_free);
     211                 :          16 :         gvalue->data[0].v_pointer = g_steal_pointer(&value);
     212                 :             :     } else if constexpr (std::is_same_v<T, GObject*>) {
     213                 :             :         g_clear_object(&gvalue->data[0].v_pointer);
     214                 :             :         gvalue->data[0].v_pointer = g_steal_pointer(&value);
     215                 :             :     } else if constexpr (std::is_same_v<T, GVariant*>) {
     216                 :             :         g_clear_pointer(reinterpret_cast<T*>(&gvalue->data[0].v_pointer),
     217                 :             :                         g_variant_unref);
     218                 :             :         gvalue->data[0].v_pointer = value;
     219                 :             :     } else {
     220                 :             :         static_assert(!std::is_pointer_v<T>, "Not a known pointer type");
     221                 :             :     }
     222                 :          16 : }
     223                 :             : 
     224                 :             : template <typename TAG>
     225                 :           0 : std::string gvalue_to_string(GValue* gvalue) {
     226                 :           0 :     auto str =
     227                 :           0 :         std::string("GValue of type ") + G_VALUE_TYPE_NAME(gvalue) + ": ";
     228                 :             : 
     229                 :             :     if constexpr (std::is_same_v<TAG, char*>) {
     230                 :           0 :         str += std::string("\"") + Gjs::gvalue_get<TAG>(gvalue) + '"';
     231                 :             :     } else if constexpr (std::is_same_v<TAG, GVariant*>) {
     232                 :             :         AutoChar variant{g_variant_print(Gjs::gvalue_get<TAG>(gvalue), true)};
     233                 :             :         str += std::string("<") + variant.get() + '>';
     234                 :             :     } else if constexpr (std::is_arithmetic_v<TAG>) {
     235                 :           0 :         str += std::to_string(Gjs::gvalue_get<TAG>(gvalue));
     236                 :             :     } else {
     237                 :           0 :         std::ostringstream out;
     238                 :           0 :         out << Gjs::gvalue_get<TAG>(gvalue);
     239                 :           0 :         str += out.str();
     240                 :           0 :     }
     241                 :           0 :     return str;
     242                 :             : }
     243                 :             : 
     244                 :             : }  // namespace Gjs
     245                 :             : 
     246                 :             : using AutoGValueVector = std::vector<Gjs::AutoGValue>;
     247                 :             : 
     248                 :             : GJS_JSAPI_RETURN_CONVENTION
     249                 :             : bool       gjs_value_to_g_value         (JSContext      *context,
     250                 :             :                                          JS::HandleValue value,
     251                 :             :                                          GValue         *gvalue);
     252                 :             : GJS_JSAPI_RETURN_CONVENTION
     253                 :             : bool       gjs_value_to_g_value_no_copy (JSContext      *context,
     254                 :             :                                          JS::HandleValue value,
     255                 :             :                                          GValue         *gvalue);
     256                 :             : 
     257                 :             : GJS_JSAPI_RETURN_CONVENTION
     258                 :             : bool gjs_value_from_g_value(JSContext             *context,
     259                 :             :                             JS::MutableHandleValue value_p,
     260                 :             :                             const GValue          *gvalue);
     261                 :             : 
     262                 :             : 
     263                 :             : #endif  // GI_VALUE_H_
        

Generated by: LCOV version 2.0-1