LCOV - code coverage report
Current view: top level - gi - arg-inl.h (source / functions) Hit Total Coverage
Test: gjs- Code Coverage Lines: 69 76 90.8 %
Date: 2023-09-17 02:39:54 Functions: 165 182 90.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 15 19 78.9 %

           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: 2020 Marco Trevisan <marco.trevisan@canonical.com>
       4                 :            : 
       5                 :            : #pragma once
       6                 :            : 
       7                 :            : #include <stdint.h>
       8                 :            : 
       9                 :            : #include <cstddef>  // for nullptr_t
      10                 :            : #include <limits>
      11                 :            : #include <string>  // for to_string
      12                 :            : #include <type_traits>
      13                 :            : 
      14                 :            : #include <girepository.h>
      15                 :            : #include <glib-object.h>  // for GType
      16                 :            : #include <glib.h>         // for gboolean
      17                 :            : #include <js/TypeDecls.h>  // for HandleValue
      18                 :            : 
      19                 :            : #include "gi/js-value-inl.h"
      20                 :            : #include "gi/utils-inl.h"
      21                 :            : #include "gjs/macros.h"
      22                 :            : 
      23                 :            : // GIArgument accessor templates
      24                 :            : //
      25                 :            : // These are intended to make access to the GIArgument union more type-safe and
      26                 :            : // reduce bugs that occur from assigning to one member and reading from another.
      27                 :            : // (These bugs often work fine on one processor architecture but crash on
      28                 :            : // another.)
      29                 :            : //
      30                 :            : // gjs_arg_member<T>(GIArgument*) - returns a reference to the appropriate union
      31                 :            : //   member that would hold the type T. Rarely used, unless as a pointer to a
      32                 :            : //   return location.
      33                 :            : // gjs_arg_get<T>(GIArgument*) - returns the value of type T from the
      34                 :            : //   appropriate union member.
      35                 :            : // gjs_arg_set(GIArgument*, T) - sets the appropriate union member for type T.
      36                 :            : // gjs_arg_unset<T>(GIArgument*) - sets the appropriate zero value in the
      37                 :            : //   appropriate union member for type T.
      38                 :            : // gjs_arg_steal<T>(GIArgument*) - sets the appropriate zero value in the
      39                 :            : //   appropriate union member for type T and returns the replaced value.
      40                 :            : 
      41                 :            : template <auto GIArgument::*member>
      42                 :     319826 : [[nodiscard]] constexpr inline decltype(auto) gjs_arg_member(GIArgument* arg) {
      43                 :     319826 :     return (arg->*member);
      44                 :            : }
      45                 :            : 
      46                 :            : /* The tag is needed to disambiguate types such as gboolean and GType
      47                 :            :  * which are in fact typedef's of other generic types.
      48                 :            :  * Setting a tag for a type allows to perform proper specialization. */
      49                 :            : template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
      50                 :     319826 : [[nodiscard]] constexpr inline decltype(auto) gjs_arg_member(GIArgument* arg) {
      51                 :            :     if constexpr (TAG == GI_TYPE_TAG_VOID) {
      52                 :            :         if constexpr (std::is_same_v<T, bool>)
      53                 :       1426 :             return gjs_arg_member<&GIArgument::v_boolean>(arg);
      54                 :            :         if constexpr (std::is_same_v<T, int8_t>)
      55                 :        280 :             return gjs_arg_member<&GIArgument::v_int8>(arg);
      56                 :            :         if constexpr (std::is_same_v<T, uint8_t>)
      57                 :         71 :             return gjs_arg_member<&GIArgument::v_uint8>(arg);
      58                 :            :         if constexpr (std::is_same_v<T, int16_t>)
      59                 :         82 :             return gjs_arg_member<&GIArgument::v_int16>(arg);
      60                 :            :         if constexpr (std::is_same_v<T, uint16_t>)
      61                 :         46 :             return gjs_arg_member<&GIArgument::v_uint16>(arg);
      62                 :            :         if constexpr (std::is_same_v<T, int32_t>)
      63                 :      15012 :             return gjs_arg_member<&GIArgument::v_int32>(arg);
      64                 :            :         if constexpr (std::is_same_v<T, uint32_t>)
      65                 :      33534 :             return gjs_arg_member<&GIArgument::v_uint32>(arg);
      66                 :            :         if constexpr (std::is_same_v<T, int64_t>)
      67                 :        441 :             return gjs_arg_member<&GIArgument::v_int64>(arg);
      68                 :            :         if constexpr (std::is_same_v<T, uint64_t>)
      69                 :       3382 :             return gjs_arg_member<&GIArgument::v_uint64>(arg);
      70                 :            : 
      71                 :            :         // gunichar is stored in v_uint32
      72                 :            :         if constexpr (std::is_same_v<T, char32_t>)
      73                 :          8 :             return gjs_arg_member<&GIArgument::v_uint32>(arg);
      74                 :            : 
      75                 :            :         if constexpr (std::is_same_v<T, float>)
      76                 :         80 :             return gjs_arg_member<&GIArgument::v_float>(arg);
      77                 :            : 
      78                 :            :         if constexpr (std::is_same_v<T, double>)
      79                 :        114 :             return gjs_arg_member<&GIArgument::v_double>(arg);
      80                 :            : 
      81                 :            :         if constexpr (std::is_same_v<T, char*>)
      82                 :       5057 :             return gjs_arg_member<&GIArgument::v_string>(arg);
      83                 :            : 
      84                 :            :         if constexpr (std::is_same_v<T, void*>)
      85                 :     228875 :             return gjs_arg_member<&GIArgument::v_pointer>(arg);
      86                 :            : 
      87                 :            :         if constexpr (std::is_same_v<T, std::nullptr_t>)
      88                 :          1 :             return gjs_arg_member<&GIArgument::v_pointer>(arg);
      89                 :            : 
      90                 :            :         if constexpr (std::is_pointer<T>()) {
      91                 :            :             using NonconstPtrT = std::add_pointer_t<
      92                 :            :                 std::remove_const_t<std::remove_pointer_t<T>>>;
      93                 :            :             return reinterpret_cast<NonconstPtrT&>(
      94                 :      23218 :                 gjs_arg_member<&GIArgument::v_pointer>(arg));
      95                 :            :         }
      96                 :            :     }
      97                 :            : 
      98                 :            :     if constexpr (TAG == GI_TYPE_TAG_BOOLEAN && std::is_same_v<T, gboolean>)
      99                 :       1137 :         return gjs_arg_member<&GIArgument::v_boolean>(arg);
     100                 :            : 
     101                 :            :     if constexpr (TAG == GI_TYPE_TAG_GTYPE && std::is_same_v<T, GType>) {
     102                 :            :         // GType is defined differently on 32-bit vs. 64-bit architectures.
     103                 :            :         if constexpr (std::is_same_v<GType, gsize>)
     104                 :       1858 :             return gjs_arg_member<&GIArgument::v_size>(arg);
     105                 :            :         else if constexpr (std::is_same_v<GType, gulong>)
     106                 :            :             return gjs_arg_member<&GIArgument::v_ulong>(arg);
     107                 :            :     }
     108                 :            : 
     109                 :            :     if constexpr (TAG == GI_TYPE_TAG_INTERFACE && std::is_integral_v<T>) {
     110                 :            :         if constexpr (std::is_signed_v<T>)
     111                 :       5200 :             return gjs_arg_member<&GIArgument::v_int>(arg);
     112                 :            :         else
     113                 :          4 :             return gjs_arg_member<&GIArgument::v_uint>(arg);
     114                 :            :     }
     115                 :            : }
     116                 :            : 
     117                 :            : template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
     118                 :     106319 : constexpr inline void gjs_arg_set(GIArgument* arg, T v) {
     119                 :            :     if constexpr (std::is_pointer_v<T>) {
     120                 :            :         using NonconstPtrT =
     121                 :            :             std::add_pointer_t<std::remove_const_t<std::remove_pointer_t<T>>>;
     122                 :      91867 :         gjs_arg_member<NonconstPtrT, TAG>(arg) = const_cast<NonconstPtrT>(v);
     123                 :            :     } else {
     124                 :            :         if constexpr (std::is_same_v<T, bool> || (std::is_same_v<T, gboolean> &&
     125                 :            :                                                   TAG == GI_TYPE_TAG_BOOLEAN))
     126                 :        416 :             v = !!v;
     127                 :            : 
     128                 :      14452 :         gjs_arg_member<T, TAG>(arg) = v;
     129                 :            :     }
     130                 :     106319 : }
     131                 :            : 
     132                 :            : // Store function pointers as void*. It is a requirement of GLib that your
     133                 :            : // compiler can do this
     134                 :            : template <typename ReturnT, typename... Args>
     135                 :        106 : constexpr inline void gjs_arg_set(GIArgument* arg, ReturnT (*v)(Args...)) {
     136                 :        106 :     gjs_arg_member<void*>(arg) = reinterpret_cast<void*>(v);
     137                 :        106 : }
     138                 :            : 
     139                 :            : template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
     140                 :            : constexpr inline std::enable_if_t<std::is_integral_v<T>> gjs_arg_set(
     141                 :            :     GIArgument* arg, void* v) {
     142                 :            :     gjs_arg_set<T, TAG>(arg, gjs_pointer_to_int<T>(v));
     143                 :            : }
     144                 :            : 
     145                 :            : template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
     146                 :     164036 : [[nodiscard]] constexpr inline T gjs_arg_get(GIArgument* arg) {
     147                 :            :     if constexpr (std::is_same_v<T, bool> ||
     148                 :            :                   (std::is_same_v<T, gboolean> && TAG == GI_TYPE_TAG_BOOLEAN))
     149                 :       1193 :         return T(!!gjs_arg_member<T, TAG>(arg));
     150                 :            : 
     151                 :     162843 :     return gjs_arg_member<T, TAG>(arg);
     152                 :            : }
     153                 :            : 
     154                 :            : template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
     155                 :            : [[nodiscard]] constexpr inline void* gjs_arg_get_as_pointer(GIArgument* arg) {
     156                 :            :     return gjs_int_to_pointer(gjs_arg_get<T, TAG>(arg));
     157                 :            : }
     158                 :            : 
     159                 :            : template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
     160                 :      26068 : constexpr inline void gjs_arg_unset(GIArgument* arg) {
     161                 :            :     if constexpr (std::is_pointer_v<T>)
     162                 :      25810 :         gjs_arg_set<T, TAG>(arg, nullptr);
     163                 :            :     else
     164                 :        258 :         gjs_arg_set<T, TAG>(arg, static_cast<T>(0));
     165                 :      26068 : }
     166                 :            : 
     167                 :            : template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
     168                 :      13009 : [[nodiscard]] constexpr inline T gjs_arg_steal(GIArgument* arg) {
     169                 :      13009 :     auto val = gjs_arg_get<T, TAG>(arg);
     170                 :      13009 :     gjs_arg_unset<T, TAG>(arg);
     171                 :      13009 :     return val;
     172                 :            : }
     173                 :            : 
     174                 :            : // Implementation to store rounded (u)int64_t numbers into double
     175                 :            : 
     176                 :            : template <typename BigT>
     177                 :            : [[nodiscard]] inline constexpr std::enable_if_t<
     178                 :            :     std::is_integral_v<BigT> && (std::numeric_limits<BigT>::max() >
     179                 :            :                                  std::numeric_limits<int32_t>::max()),
     180                 :            :     double>
     181                 :       1152 : gjs_arg_get_maybe_rounded(GIArgument* arg) {
     182                 :       1152 :     BigT val = gjs_arg_get<BigT>(arg);
     183                 :            : 
     184   [ +  +  +  +  :       2292 :     if (val < Gjs::min_safe_big_number<BigT>() ||
                   +  + ]
     185                 :       1140 :         val > Gjs::max_safe_big_number<BigT>()) {
     186                 :         37 :         g_warning(
     187                 :            :             "Value %s cannot be safely stored in a JS Number "
     188                 :            :             "and may be rounded",
     189                 :            :             std::to_string(val).c_str());
     190                 :            :     }
     191                 :            : 
     192                 :       1152 :     return static_cast<double>(val);
     193                 :            : }
     194                 :            : 
     195                 :            : template <typename T>
     196                 :      24588 : GJS_JSAPI_RETURN_CONVENTION inline bool gjs_arg_set_from_js_value(
     197                 :            :     JSContext* cx, const JS::HandleValue& value, GArgument* arg,
     198                 :            :     bool* out_of_range) {
     199                 :            :     if constexpr (Gjs::type_has_js_getter<T>())
     200                 :      11778 :         return Gjs::js_value_to_c(cx, value, &gjs_arg_member<T>(arg));
     201                 :            : 
     202                 :      12810 :     Gjs::JsValueHolder::Relaxed<T> val{};
     203                 :            : 
     204         [ +  + ]:      12810 :     if (!Gjs::js_value_to_c_checked<T>(cx, value, &val, out_of_range))
     205                 :         17 :         return false;
     206                 :            : 
     207         [ +  + ]:      12793 :     if (*out_of_range)
     208                 :          8 :         return false;
     209                 :            : 
     210                 :      12785 :     gjs_arg_set<T>(arg, val);
     211                 :            : 
     212                 :      12785 :     return true;
     213                 :            : }
     214                 :            : 
     215                 :            : // A helper function to retrieve array lengths from a GIArgument (letting the
     216                 :            : // compiler generate good instructions in case of big endian machines)
     217                 :        393 : [[nodiscard]] constexpr size_t gjs_g_argument_get_array_length(
     218                 :            :     GITypeTag tag, GIArgument* arg) {
     219   [ -  +  -  -  :        393 :     switch (tag) {
             +  +  +  +  
                      - ]
     220                 :          0 :         case GI_TYPE_TAG_INT8:
     221                 :          0 :             return gjs_arg_get<int8_t>(arg);
     222                 :          1 :         case GI_TYPE_TAG_UINT8:
     223                 :          1 :             return gjs_arg_get<uint8_t>(arg);
     224                 :          0 :         case GI_TYPE_TAG_INT16:
     225                 :          0 :             return gjs_arg_get<int16_t>(arg);
     226                 :          0 :         case GI_TYPE_TAG_UINT16:
     227                 :          0 :             return gjs_arg_get<uint16_t>(arg);
     228                 :        109 :         case GI_TYPE_TAG_INT32:
     229                 :        109 :             return gjs_arg_get<int32_t>(arg);
     230                 :          6 :         case GI_TYPE_TAG_UINT32:
     231                 :          6 :             return gjs_arg_get<uint32_t>(arg);
     232                 :         14 :         case GI_TYPE_TAG_INT64:
     233                 :         14 :             return gjs_arg_get<int64_t>(arg);
     234                 :        263 :         case GI_TYPE_TAG_UINT64:
     235                 :        263 :             return gjs_arg_get<uint64_t>(arg);
     236                 :          0 :         default:
     237                 :            :             g_assert_not_reached();
     238                 :            :     }
     239                 :            : }

Generated by: LCOV version 1.14