LCOV - code coverage report
Current view: top level - gi - info.h (source / functions) Coverage Total Hit
Test: gjs-1.87.1 Code Coverage Lines: 98.6 % 507 500
Test Date: 2026-01-05 03:41:30 Functions: 96.7 % 703 680
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 73.7 % 156 115

             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: 2024 Philip Chimento <philip.chimento@gmail.com>
       4                 :             : 
       5                 :             : #pragma once
       6                 :             : 
       7                 :             : #include <config.h>
       8                 :             : 
       9                 :             : #include <limits.h>  // for INT_MAX
      10                 :             : #include <stdint.h>
      11                 :             : #include <string.h>
      12                 :             : 
      13                 :             : #include <cstddef>  // for nullptr_t
      14                 :             : #include <iterator>
      15                 :             : #include <utility>  // for pair, make_pair, move
      16                 :             : 
      17                 :             : #if GJS_VERBOSE_ENABLE_GI_USAGE
      18                 :             : #    include <sstream>
      19                 :             : #    include <string>
      20                 :             : #endif
      21                 :             : 
      22                 :             : #include <ffi.h>
      23                 :             : #include <girepository/girepository.h>
      24                 :             : #include <girepository/girffi.h>
      25                 :             : #include <glib-object.h>
      26                 :             : #include <glib.h>
      27                 :             : 
      28                 :             : #include <js/GCPolicyAPI.h>  // for IgnoreGCPolicy
      29                 :             : #include <mozilla/Maybe.h>
      30                 :             : #include <mozilla/Result.h>
      31                 :             : #include <mozilla/ResultVariant.h>
      32                 :             : #include <mozilla/Span.h>
      33                 :             : 
      34                 :             : #include "gjs/auto.h"
      35                 :             : #include "gjs/gerror-result.h"
      36                 :             : #include "util/log.h"
      37                 :             : 
      38                 :             : // This file is a C++ wrapper for libgirepository that attempts to be more
      39                 :             : // null-safe and type-safe.
      40                 :             : // Each introspection info type has the methods of the C API's GIFooInfo, but
      41                 :             : // indicates whether the return value is owned by the caller (GI::AutoFooInfo)
      42                 :             : // or unowned (GI::FooInfo), and uses Maybe to indicate when it is nullable.
      43                 :             : // There are also GI::StackArgInfo and GI::StackTypeInfo for use with the
      44                 :             : // CallableInfo.load_arg(), CallableInfo.load_return_type(), and
      45                 :             : // ArgInfo.load_type() methods, for performance.
      46                 :             : 
      47                 :             : // COMPAT: We use Mozilla's Maybe, Result, and Span types because they are more
      48                 :             : // complete than the C++ standard library types.
      49                 :             : // std::optional does not have transform(), and_then(), etc., until C++23.
      50                 :             : // std::expected does not appear until C++23.
      51                 :             : // std::span does not appear until C++20.
      52                 :             : 
      53                 :             : // Note, only the methods actually needed in GJS are wrapped here. So if one is
      54                 :             : // missing, that's not for any particular reason unless noted otherwise; it just
      55                 :             : // was never needed yet.
      56                 :             : 
      57                 :             : using BoolResult = mozilla::Result<mozilla::Ok, mozilla::Nothing>;
      58                 :             : 
      59                 :             : namespace GI {
      60                 :             : 
      61                 :             : enum class InfoTag : unsigned {
      62                 :             :     ARG,
      63                 :             :     BASE,
      64                 :             :     CALLABLE,
      65                 :             :     CALLBACK,
      66                 :             :     CONSTANT,
      67                 :             :     ENUM,
      68                 :             :     FIELD,
      69                 :             :     FLAGS,
      70                 :             :     FUNCTION,
      71                 :             :     INTERFACE,
      72                 :             :     OBJECT,
      73                 :             :     PROPERTY,
      74                 :             :     REGISTERED_TYPE,
      75                 :             :     SIGNAL,
      76                 :             :     STRUCT,
      77                 :             :     TYPE,
      78                 :             :     UNION,
      79                 :             :     VALUE,
      80                 :             :     VFUNC,
      81                 :             : };
      82                 :             : 
      83                 :             : namespace detail {
      84                 :             : template <InfoTag TAG>
      85                 :             : struct InfoTraits {};
      86                 :             : template <>
      87                 :             : struct InfoTraits<InfoTag::ARG> {
      88                 :             :     using CStruct = GIArgInfo;
      89                 :             : };
      90                 :             : template <>
      91                 :             : struct InfoTraits<InfoTag::BASE> {
      92                 :             :     using CStruct = GIBaseInfo;
      93                 :             : };
      94                 :             : template <>
      95                 :             : struct InfoTraits<InfoTag::CALLABLE> {
      96                 :             :     using CStruct = GICallableInfo;
      97                 :             : };
      98                 :             : template <>
      99                 :             : struct InfoTraits<InfoTag::CALLBACK> {
     100                 :             :     using CStruct = GICallbackInfo;
     101                 :             : };
     102                 :             : template <>
     103                 :             : struct InfoTraits<InfoTag::CONSTANT> {
     104                 :             :     using CStruct = GIConstantInfo;
     105                 :             : };
     106                 :             : template <>
     107                 :             : struct InfoTraits<InfoTag::ENUM> {
     108                 :             :     using CStruct = GIEnumInfo;
     109                 :             : };
     110                 :             : template <>
     111                 :             : struct InfoTraits<InfoTag::FIELD> {
     112                 :             :     using CStruct = GIFieldInfo;
     113                 :             : };
     114                 :             : template <>
     115                 :             : struct InfoTraits<InfoTag::FLAGS> {
     116                 :             :     using CStruct = GIFlagsInfo;
     117                 :             : };
     118                 :             : template <>
     119                 :             : struct InfoTraits<InfoTag::FUNCTION> {
     120                 :             :     using CStruct = GIFunctionInfo;
     121                 :             : };
     122                 :             : template <>
     123                 :             : struct InfoTraits<InfoTag::INTERFACE> {
     124                 :             :     using CStruct = GIInterfaceInfo;
     125                 :             : };
     126                 :             : template <>
     127                 :             : struct InfoTraits<InfoTag::OBJECT> {
     128                 :             :     using CStruct = GIObjectInfo;
     129                 :             : };
     130                 :             : template <>
     131                 :             : struct InfoTraits<InfoTag::PROPERTY> {
     132                 :             :     using CStruct = GIPropertyInfo;
     133                 :             : };
     134                 :             : template <>
     135                 :             : struct InfoTraits<InfoTag::REGISTERED_TYPE> {
     136                 :             :     using CStruct = GIRegisteredTypeInfo;
     137                 :             : };
     138                 :             : template <>
     139                 :             : struct InfoTraits<InfoTag::SIGNAL> {
     140                 :             :     using CStruct = GISignalInfo;
     141                 :             : };
     142                 :             : template <>
     143                 :             : struct InfoTraits<InfoTag::STRUCT> {
     144                 :             :     using CStruct = GIStructInfo;
     145                 :             : };
     146                 :             : template <>
     147                 :             : struct InfoTraits<InfoTag::TYPE> {
     148                 :             :     using CStruct = GITypeInfo;
     149                 :             : };
     150                 :             : template <>
     151                 :             : struct InfoTraits<InfoTag::UNION> {
     152                 :             :     using CStruct = GIUnionInfo;
     153                 :             : };
     154                 :             : template <>
     155                 :             : struct InfoTraits<InfoTag::VALUE> {
     156                 :             :     using CStruct = GIValueInfo;
     157                 :             : };
     158                 :             : template <>
     159                 :             : struct InfoTraits<InfoTag::VFUNC> {
     160                 :             :     using CStruct = GIVFuncInfo;
     161                 :             : };
     162                 :             : 
     163                 :             : using GTypeFunc = GType (*)();
     164                 :             : static constexpr const GTypeFunc gtype_funcs[] = {
     165                 :             :     gi_arg_info_get_type,
     166                 :             :     gi_base_info_get_type,
     167                 :             :     gi_callable_info_get_type,
     168                 :             :     gi_callback_info_get_type,
     169                 :             :     gi_constant_info_get_type,
     170                 :             :     gi_enum_info_get_type,
     171                 :             :     gi_field_info_get_type,
     172                 :             :     gi_flags_info_get_type,
     173                 :             :     gi_function_info_get_type,
     174                 :             :     gi_interface_info_get_type,
     175                 :             :     gi_object_info_get_type,
     176                 :             :     gi_property_info_get_type,
     177                 :             :     gi_registered_type_info_get_type,
     178                 :             :     gi_signal_info_get_type,
     179                 :             :     gi_struct_info_get_type,
     180                 :             :     gi_type_info_get_type,
     181                 :             :     gi_union_info_get_type,
     182                 :             :     gi_value_info_get_type,
     183                 :             :     gi_vfunc_info_get_type,
     184                 :             : };
     185                 :             : 
     186                 :     1392329 : constexpr GTypeFunc gtype_func(InfoTag tag) { return gtype_funcs[size_t(tag)]; }
     187                 :             : 
     188                 :             : }  // namespace detail
     189                 :             : 
     190                 :             : template <typename Wrapper, InfoTag TAG>
     191                 :             : class InfoOperations {};
     192                 :             : 
     193                 :             : class StackArgInfo;
     194                 :             : class StackTypeInfo;
     195                 :             : 
     196                 :             : template <InfoTag TAG>
     197                 :             : class OwnedInfo;
     198                 :             : 
     199                 :             : template <InfoTag TAG>
     200                 :             : class UnownedInfo;
     201                 :             : 
     202                 :             : namespace detail {
     203                 :             : // We want the underlying pointer to be inaccessible. However, the three storage
     204                 :             : // classes sometimes have to interact with each others' pointers. It's easier to
     205                 :             : // put all of those operations into detail::Pointer and have the classes be
     206                 :             : // friends of it, than it is to expose all the pointer operations via friend
     207                 :             : // declarations individually.
     208                 :             : struct Pointer {
     209                 :             :     template <InfoTag TAG>
     210                 :             :     using CStruct = typename InfoTraits<TAG>::CStruct;
     211                 :             : 
     212                 :             :     template <InfoTag TAG>
     213                 :             :     [[nodiscard]]
     214                 :             :     static constexpr
     215                 :      198891 :         typename detail::InfoTraits<TAG>::CStruct* cast(GIBaseInfo* ptr) {
     216                 :             :         // (the following is a GI_TAG_INFO() cast but written out)
     217                 :             :         return reinterpret_cast<typename detail::InfoTraits<TAG>::CStruct*>(
     218                 :      198891 :             g_type_check_instance_cast(reinterpret_cast<GTypeInstance*>(ptr),
     219                 :      397782 :                                        gtype_func(TAG)()));
     220                 :             :     }
     221                 :             : 
     222                 :             :     template <InfoTag TAG>
     223                 :      966065 :     static constexpr CStruct<TAG>* get_from(const OwnedInfo<TAG>& owned) {
     224                 :      966065 :         return const_cast<CStruct<TAG>*>(owned.m_info);
     225                 :             :     }
     226                 :             : 
     227                 :             :     template <InfoTag TAG>
     228                 :     1378815 :     static constexpr CStruct<TAG>* get_from(const UnownedInfo<TAG>& unowned) {
     229                 :     1378815 :         return const_cast<CStruct<TAG>*>(unowned.m_info);
     230                 :             :     }
     231                 :             : 
     232                 :             :     // Defined out-of-line because they are not templates and so StackArgInfo
     233                 :             :     // and StackTypeInfo need to be complete types.
     234                 :             :     static constexpr GIArgInfo* get_from(const StackArgInfo& stack);
     235                 :             :     static constexpr GITypeInfo* get_from(const StackTypeInfo& stack);
     236                 :             : 
     237                 :             :     template <InfoTag TAG>
     238                 :      273588 :     static constexpr OwnedInfo<TAG> to_owned(CStruct<TAG>* ptr) {
     239                 :      273588 :         return OwnedInfo<TAG>{ptr};
     240                 :             :     }
     241                 :             : 
     242                 :             :     template <InfoTag TAG>
     243                 :      212537 :     static constexpr UnownedInfo<TAG> to_unowned(CStruct<TAG>* ptr) {
     244                 :      212537 :         return UnownedInfo<TAG>{ptr};
     245                 :             :     }
     246                 :             : 
     247                 :             :     // Same, defined out of line so StackTypeInfo is not incomplete.
     248                 :             :     static void to_stack(GITypeInfo* ptr, StackTypeInfo* stack);
     249                 :             : 
     250                 :             :     template <InfoTag TAG>
     251                 :       37969 :     static constexpr mozilla::Maybe<OwnedInfo<TAG>> nullable(
     252                 :             :         CStruct<TAG>* ptr) {
     253   [ +  +  +  + ]:       75938 :         return ptr ? mozilla::Some(OwnedInfo<TAG>{ptr}) : mozilla::Nothing{};
     254                 :             :     }
     255                 :             : 
     256                 :             :     template <InfoTag TAG>
     257                 :        4071 :     static constexpr mozilla::Maybe<UnownedInfo<TAG>> nullable_unowned(
     258                 :             :         CStruct<TAG>* ptr) {
     259         [ +  + ]:        4071 :         return ptr ? mozilla::Some(UnownedInfo<TAG>{ptr}) : mozilla::Nothing{};
     260                 :             :     }
     261                 :             : 
     262                 :             :     template <InfoTag TAG>
     263                 :             :     [[nodiscard]]
     264                 :     1193438 :     static constexpr bool typecheck(GIBaseInfo* ptr) {
     265   [ -  +  +  -  :     1193438 :         return G_TYPE_CHECK_INSTANCE_TYPE(ptr, gtype_func(TAG)());
                   +  + ]
     266                 :             :     }
     267                 :             : };
     268                 :             : }  // namespace detail
     269                 :             : 
     270                 :             : ///// UNOWNED INTROSPECTION INFO ///////////////////////////////////////////////
     271                 :             : 
     272                 :             : template <InfoTag TAG>
     273                 :             : class UnownedInfo : public InfoOperations<UnownedInfo<TAG>, TAG> {
     274                 :             :     friend struct detail::Pointer;
     275                 :             : 
     276                 :             :     using CStruct = typename detail::InfoTraits<TAG>::CStruct;
     277                 :             :     CStruct* m_info;
     278                 :             :     UnownedInfo() = delete;
     279                 :             :     UnownedInfo(std::nullptr_t) = delete;  // NOLINT(runtime/explicit)
     280                 :             :     // https://github.com/cpplint/cpplint/issues/386
     281                 :             :     // No need to delete move constructor; declaring a copy constructor prevents
     282                 :             :     // it from being generated.
     283                 :             : 
     284                 :      572324 :     explicit UnownedInfo(CStruct* info) : m_info(info) { validate(); }
     285                 :             :     [[nodiscard]] CStruct* ptr() const { return m_info; }
     286                 :             : 
     287                 :      572324 :     void validate() const {
     288                 :             :         static_assert(sizeof(CStruct*) == sizeof(UnownedInfo<TAG>),
     289                 :             :                       "UnownedInfo<T> should be byte-compatible with T*");
     290                 :             : 
     291                 :             : #ifndef G_DISABLE_CAST_CHECKS
     292                 :      572324 :         g_assert(m_info && "Info pointer cannot be null");
     293                 :      572324 :         g_assert(detail::Pointer::typecheck<TAG>(GI_BASE_INFO(m_info)) &&
     294                 :             :                  "Info type must match");
     295                 :             : #endif  // G_DISABLE_CAST_CHECKS
     296                 :      572324 :     }
     297                 :             : 
     298                 :             :  public:
     299                 :             :     // Copying is cheap, UnownedInfo just consists of a pointer.
     300                 :      700782 :     constexpr UnownedInfo(const UnownedInfo& other) : m_info(other.m_info) {}
     301                 :             :     UnownedInfo& operator=(const UnownedInfo& other) {
     302                 :             :         m_info = other.m_info;
     303                 :             :         return *this;
     304                 :             :     }
     305                 :             : 
     306                 :             :     // Caller must take care that the lifetime of UnownedInfo does not exceed
     307                 :             :     // the lifetime of the StackInfo. Do not store the UnownedInfo, or try to
     308                 :             :     // take ownership.
     309                 :       24405 :     UnownedInfo(const StackArgInfo& other)  // NOLINT(runtime/explicit)
     310                 :       24405 :         : UnownedInfo(detail::Pointer::get_from(other)) {
     311                 :             :         static_assert(TAG == InfoTag::ARG);
     312                 :       24405 :     }
     313                 :      100628 :     UnownedInfo(const StackTypeInfo& other)  // NOLINT(runtime/explicit)
     314                 :      100628 :         : UnownedInfo(detail::Pointer::get_from(other)) {
     315                 :             :         static_assert(TAG == InfoTag::TYPE);
     316                 :      100628 :     }
     317                 :             : 
     318                 :             :     // Caller must take care that the lifetime of UnownedInfo does not exceed
     319                 :             :     // the lifetime of the originating OwnedInfo. That means, if you store it,
     320                 :             :     // only store it as an OwnedInfo, adding another reference.
     321                 :      230685 :     UnownedInfo(const OwnedInfo<TAG>& other)  // NOLINT(runtime/explicit)
     322                 :      230685 :         : UnownedInfo(detail::Pointer::get_from(other)) {}
     323                 :             : };
     324                 :             : 
     325                 :             : using ArgInfo = UnownedInfo<InfoTag::ARG>;
     326                 :             : using BaseInfo = UnownedInfo<InfoTag::BASE>;
     327                 :             : using CallableInfo = UnownedInfo<InfoTag::CALLABLE>;
     328                 :             : using CallbackInfo = UnownedInfo<InfoTag::CALLBACK>;
     329                 :             : using ConstantInfo = UnownedInfo<InfoTag::CONSTANT>;
     330                 :             : using EnumInfo = UnownedInfo<InfoTag::ENUM>;
     331                 :             : using FieldInfo = UnownedInfo<InfoTag::FIELD>;
     332                 :             : using FlagsInfo = UnownedInfo<InfoTag::FLAGS>;
     333                 :             : using FunctionInfo = UnownedInfo<InfoTag::FUNCTION>;
     334                 :             : using InterfaceInfo = UnownedInfo<InfoTag::INTERFACE>;
     335                 :             : using ObjectInfo = UnownedInfo<InfoTag::OBJECT>;
     336                 :             : using RegisteredTypeInfo = UnownedInfo<InfoTag::REGISTERED_TYPE>;
     337                 :             : using StructInfo = UnownedInfo<InfoTag::STRUCT>;
     338                 :             : using TypeInfo = UnownedInfo<InfoTag::TYPE>;
     339                 :             : using UnionInfo = UnownedInfo<InfoTag::UNION>;
     340                 :             : using ValueInfo = UnownedInfo<InfoTag::VALUE>;
     341                 :             : using VFuncInfo = UnownedInfo<InfoTag::VFUNC>;
     342                 :             : 
     343                 :             : ///// OWNED INTROSPECTION INFO /////////////////////////////////////////////////
     344                 :             : 
     345                 :             : template <InfoTag TAG>
     346                 :             : class OwnedInfo : public InfoOperations<OwnedInfo<TAG>, TAG> {
     347                 :             :     friend struct detail::Pointer;
     348                 :             : 
     349                 :             :     using CStruct = typename detail::InfoTraits<TAG>::CStruct;
     350                 :             :     CStruct* m_info;
     351                 :             : 
     352                 :             :     OwnedInfo() = delete;
     353                 :             :     OwnedInfo(std::nullptr_t) = delete;  // NOLINT(runtime/explicit)
     354                 :             :     // https://github.com/cpplint/cpplint/issues/386
     355                 :      352033 :     explicit OwnedInfo(CStruct* info) : m_info(info) {
     356                 :             :         static_assert(sizeof(CStruct*) == sizeof(OwnedInfo<TAG>),
     357                 :             :                       "OwnedInfo<T> should be byte-compatible with T*");
     358                 :             : #ifndef G_DISABLE_CAST_CHECKS
     359                 :      352033 :         g_assert(m_info && "Info pointer cannot be null");
     360                 :      352033 :         g_assert(detail::Pointer::typecheck<TAG>(GI_BASE_INFO(m_info)) &&
     361                 :             :                  "Info type must match");
     362                 :             : #endif  // G_DISABLE_CAST_CHECKS
     363                 :      352033 :     }
     364                 :             : 
     365                 :             :     [[nodiscard]] CStruct* ptr() const { return m_info; }
     366                 :             : 
     367                 :             :  public:
     368                 :             :     // Copy OwnedInfo from another OwnedInfo. Explicit because it takes a
     369                 :             :     // reference.
     370                 :       10282 :     explicit OwnedInfo(const OwnedInfo& other) : OwnedInfo(other.m_info) {
     371                 :       10282 :         gi_base_info_ref(m_info);
     372                 :       10282 :     }
     373                 :             :     // Move another OwnedInfo into this one
     374                 :       29887 :     OwnedInfo(OwnedInfo&& other) : OwnedInfo(other.m_info) {
     375                 :       29887 :         other.m_info = nullptr;
     376                 :       29887 :     }
     377                 :             :     OwnedInfo& operator=(const OwnedInfo& other) {
     378                 :             :         m_info = other.m_info;
     379                 :             :         gi_base_info_ref(m_info);
     380                 :             :         return *this;
     381                 :             :     }
     382                 :          31 :     OwnedInfo& operator=(OwnedInfo&& other) {
     383                 :          31 :         std::swap(m_info, other.m_info);
     384                 :          31 :         return *this;
     385                 :             :     }
     386         [ +  + ]:      351794 :     ~OwnedInfo() { g_clear_pointer(&m_info, gi_base_info_unref); }
     387                 :             : 
     388                 :             :     // Copy OwnedInfo from UnownedInfo, which also comes down to just taking a
     389                 :             :     // reference. Explicit because it takes a reference. However, make sure the
     390                 :             :     // UnownedInfo is not borrowed from a StackInfo!
     391                 :       17929 :     explicit OwnedInfo(const UnownedInfo<TAG>& other)
     392                 :       17929 :         : OwnedInfo(detail::Pointer::get_from(other)) {
     393                 :       17929 :         gi_base_info_ref(m_info);
     394                 :       17929 :     }
     395                 :             : 
     396                 :             :     // Do not try to take ownership of a StackInfo.
     397                 :             :     // (cpplint false positive: https://github.com/cpplint/cpplint/issues/386)
     398                 :             :     OwnedInfo(const StackArgInfo& other) = delete;   // NOLINT(runtime/explicit)
     399                 :             :     OwnedInfo(const StackTypeInfo& other) = delete;  // NOLINT(runtime/explicit)
     400                 :             : };
     401                 :             : 
     402                 :             : using AutoArgInfo = OwnedInfo<InfoTag::ARG>;
     403                 :             : using AutoBaseInfo = OwnedInfo<InfoTag::BASE>;
     404                 :             : using AutoCallableInfo = OwnedInfo<InfoTag::CALLABLE>;
     405                 :             : using AutoCallbackInfo = OwnedInfo<InfoTag::CALLBACK>;
     406                 :             : using AutoEnumInfo = OwnedInfo<InfoTag::ENUM>;
     407                 :             : using AutoFieldInfo = OwnedInfo<InfoTag::FIELD>;
     408                 :             : using AutoFunctionInfo = OwnedInfo<InfoTag::FUNCTION>;
     409                 :             : using AutoInterfaceInfo = OwnedInfo<InfoTag::INTERFACE>;
     410                 :             : using AutoObjectInfo = OwnedInfo<InfoTag::OBJECT>;
     411                 :             : using AutoPropertyInfo = OwnedInfo<InfoTag::PROPERTY>;
     412                 :             : using AutoRegisteredTypeInfo = OwnedInfo<InfoTag::REGISTERED_TYPE>;
     413                 :             : using AutoSignalInfo = OwnedInfo<InfoTag::SIGNAL>;
     414                 :             : using AutoStructInfo = OwnedInfo<InfoTag::STRUCT>;
     415                 :             : using AutoTypeInfo = OwnedInfo<InfoTag::TYPE>;
     416                 :             : using AutoUnionInfo = OwnedInfo<InfoTag::UNION>;
     417                 :             : using AutoValueInfo = OwnedInfo<InfoTag::VALUE>;
     418                 :             : using AutoVFuncInfo = OwnedInfo<InfoTag::VFUNC>;
     419                 :             : 
     420                 :             : // The various specializations of InfoOperations are used to ensure that the
     421                 :             : // OwnedInfo and UnownedInfo specializations for a particular GIFooInfo type
     422                 :             : // (and the stack-allocated class, if applicable) have the same methods. So, for
     423                 :             : // example, AutoTypeInfo, TypeInfo, and StackTypeInfo all inherit from
     424                 :             : // InfoOperations<T, InfoTag::TYPE>.
     425                 :             : 
     426                 :             : template <class Wrapper>
     427                 :             : class InfoOperations<Wrapper, InfoTag::BASE> {
     428                 :             :  protected:
     429                 :             :     [[nodiscard]]
     430                 :      833838 :     GIBaseInfo* ptr() const {
     431                 :      833838 :         return GI_BASE_INFO(
     432                 :             :             detail::Pointer::get_from(*static_cast<const Wrapper*>(this)));
     433                 :             :     }
     434                 :             : 
     435                 :             :     // Helper for adapting GLib-style error reporting into GErrorResult
     436                 :             :     [[nodiscard]]
     437                 :       13981 :     static Gjs::GErrorResult<> bool_gerror(bool ok, GError* error) {
     438         [ -  + ]:       13981 :         if (!ok)
     439                 :           0 :             return mozilla::Err(error);
     440                 :       13981 :         return mozilla::Ok{};
     441                 :             :     }
     442                 :             : 
     443                 :             :     // Helper for adapting C-style success/failure result into mozilla::Result.
     444                 :             :     // Used when there is no GError out parameter.
     445                 :             :     [[nodiscard]]
     446                 :        2782 :     static BoolResult bool_to_result(bool ok) {
     447         [ +  + ]:        2782 :         if (!ok)
     448                 :          23 :             return Err(mozilla::Nothing{});
     449                 :        2759 :         return mozilla::Ok{};
     450                 :             :     }
     451                 :             : 
     452                 :             :  public:
     453                 :             :     template <InfoTag TAG>
     454                 :          22 :     bool operator==(const OwnedInfo<TAG>& other) const {
     455                 :          22 :         return gi_base_info_equal(
     456                 :          44 :             ptr(), GI_BASE_INFO(detail::Pointer::get_from(other)));
     457                 :             :     }
     458                 :             :     template <InfoTag TAG>
     459                 :         567 :     bool operator==(const UnownedInfo<TAG>& other) const {
     460                 :         567 :         return gi_base_info_equal(
     461                 :        1134 :             ptr(), GI_BASE_INFO(detail::Pointer::get_from(other)));
     462                 :             :     }
     463                 :             :     template <InfoTag TAG>
     464                 :             :     bool operator!=(const OwnedInfo<TAG>& other) const {
     465                 :             :         return !(*this == other);
     466                 :             :     }
     467                 :             :     template <InfoTag TAG>
     468                 :          30 :     bool operator!=(const UnownedInfo<TAG>& other) const {
     469                 :          30 :         return !(*this == other);
     470                 :             :     }
     471                 :             : 
     472                 :             :     template <InfoTag TAG = InfoTag::BASE>
     473                 :             :     [[nodiscard]]
     474                 :        4071 :     mozilla::Maybe<const UnownedInfo<TAG>> container() const {
     475                 :        8142 :         return detail::Pointer::nullable_unowned<TAG>(
     476                 :        4071 :             detail::Pointer::cast<TAG>(gi_base_info_get_container(ptr())));
     477                 :             :     }
     478                 :             :     [[nodiscard]]
     479                 :         248 :     bool is_deprecated() const {
     480                 :         248 :         return gi_base_info_is_deprecated(ptr());
     481                 :             :     }
     482                 :             :     [[nodiscard]]
     483                 :      193390 :     const char* name() const {
     484                 :      193390 :         return gi_base_info_get_name(ptr());
     485                 :             :     }
     486                 :             :     [[nodiscard]]
     487                 :       41359 :     const char* ns() const {
     488                 :       41359 :         return gi_base_info_get_namespace(ptr());
     489                 :             :     }
     490                 :             :     [[nodiscard]]
     491                 :       10850 :     const char* type_string() const {
     492                 :       10850 :         return g_type_name_from_instance(
     493                 :       21700 :             reinterpret_cast<GTypeInstance*>(ptr()));
     494                 :             :     }
     495                 :             : 
     496                 :             :     // Type-checking methods
     497                 :             : 
     498                 :             :     [[nodiscard]]
     499                 :         356 :     bool is_callback() const {
     500   [ -  +  +  -  :         356 :         return GI_IS_CALLBACK_INFO(ptr());
                   +  + ]
     501                 :             :     }
     502                 :             :     [[nodiscard]]
     503                 :       51619 :     bool is_enum_or_flags() const {
     504   [ -  +  +  -  :       51619 :         return GI_IS_ENUM_INFO(ptr());
                   +  + ]
     505                 :             :     }
     506   [ -  +  +  -  :        2876 :     [[nodiscard]] bool is_flags() const { return GI_IS_FLAGS_INFO(ptr()); }
                   +  + ]
     507                 :             :     [[nodiscard]]
     508                 :       13778 :     bool is_function() const {
     509   [ -  +  +  -  :       13778 :         return GI_IS_FUNCTION_INFO(ptr());
                   +  + ]
     510                 :             :     }
     511                 :             :     [[nodiscard]]
     512                 :        3730 :     bool is_interface() const {
     513   [ -  +  +  -  :        3730 :         return GI_IS_INTERFACE_INFO(ptr());
                   +  - ]
     514                 :             :     }
     515   [ -  +  +  -  :        9591 :     [[nodiscard]] bool is_object() const { return GI_IS_OBJECT_INFO(ptr()); }
                   +  + ]
     516                 :             :     [[nodiscard]]
     517                 :             :     bool is_registered_type() const {
     518                 :             :         return GI_IS_REGISTERED_TYPE_INFO(ptr());
     519                 :             :     }
     520   [ -  +  +  -  :         540 :     [[nodiscard]] bool is_struct() const { return GI_IS_STRUCT_INFO(ptr()); }
                   +  + ]
     521   [ -  +  +  -  :        2691 :     [[nodiscard]] bool is_union() const { return GI_IS_UNION_INFO(ptr()); }
                   +  + ]
     522                 :             :     [[nodiscard]]
     523                 :       24685 :     bool is_unresolved() const {
     524                 :             :         // We don't have a wrapper for GIUnresolvedInfo because it has no
     525                 :             :         // methods, but you can check whether a BaseInfo is one.
     526   [ -  +  +  -  :       24685 :         return GI_IS_UNRESOLVED_INFO(ptr());
                   -  + ]
     527                 :             :     }
     528   [ -  +  +  -  :           2 :     [[nodiscard]] bool is_vfunc() const { return GI_IS_VFUNC_INFO(ptr()); }
                   +  - ]
     529                 :             :     // Don't enumerate types which GJS doesn't define on namespaces.
     530                 :             :     // See gjs_define_info().
     531                 :             :     [[nodiscard]]
     532                 :       11251 :     bool is_enumerable() const {
     533   [ -  +  +  -  :       11251 :         return GI_IS_REGISTERED_TYPE_INFO(ptr()) ||
                   -  + ]
     534   [ +  +  -  +  :       11251 :                GI_IS_FUNCTION_INFO(ptr()) || GI_IS_CONSTANT_INFO(ptr());
          +  -  +  +  +  
          +  -  +  +  -  
             +  +  +  + ]
     535                 :             :     }
     536                 :             : 
     537                 :             :     // Having this casting function be a template is slightly inconsistent with
     538                 :             :     // all the is_X() type-checking methods above. But if we were to make
     539                 :             :     // separate as_X() methods, C++ can't easily deal with all the forward decls
     540                 :             :     // of UnownedInfo<T> instantiating the template.
     541                 :             :     template <InfoTag TAG2>
     542                 :             :     [[nodiscard]]
     543                 :      269081 :     mozilla::Maybe<const UnownedInfo<TAG2>> as() const {
     544         [ +  + ]:      269081 :         if (!detail::Pointer::typecheck<TAG2>(ptr()))
     545                 :       95562 :             return {};
     546                 :      173519 :         auto* checked_ptr = detail::Pointer::cast<TAG2>(ptr());
     547                 :      173519 :         return mozilla::Some(detail::Pointer::to_unowned<TAG2>(checked_ptr));
     548                 :             :     }
     549                 :             : 
     550                 :       10842 :     void log_usage() const {
     551                 :             : #if GJS_VERBOSE_ENABLE_GI_USAGE
     552                 :             :         mozilla::Maybe<GI::BaseInfo> parent = container();
     553                 :             :         gjs_debug_gi_usage(
     554                 :             :             "{ GIInfoType %s, \"%s\", \"%s\", \"%s\" }", type_string(), ns(),
     555                 :             :             parent.map(std::mem_fn(&GI::BaseInfo::name)).valueOr(""), name());
     556                 :             : #endif  // GJS_VERBOSE_ENABLE_GI_USAGE
     557                 :       10842 :     }
     558                 :             : };
     559                 :             : 
     560                 :             : template <typename Wrapper>
     561                 :             : using BaseInfoOperations = InfoOperations<Wrapper, InfoTag::BASE>;
     562                 :             : 
     563                 :             : // The following InfoIterator class is a C++ iterator implementation that's used
     564                 :             : // to implement the C iteration pattern:
     565                 :             : //
     566                 :             : // unsigned n_bars = gi_foo_info_get_n_bars(info);
     567                 :             : // for (unsigned ix = 0; ix < n_bars; ix++) {
     568                 :             : //   GIBarInfo* bar = gi_foo_info_get_bar(info, ix);
     569                 :             : //   do_stuff(bar);
     570                 :             : //   gi_base_info_unref(bar);
     571                 :             : // }
     572                 :             : //
     573                 :             : // as a more idiomatic C++ pattern:
     574                 :             : //
     575                 :             : // for (AutoBarInfo bar : info.bars())
     576                 :             : //   do_stuff(bar);
     577                 :             : 
     578                 :             : template <typename T>
     579                 :             : using NInfosFunc = unsigned (*)(T);
     580                 :             : 
     581                 :             : template <typename T, InfoTag TAG>
     582                 :             : using GetInfoFunc = typename detail::InfoTraits<TAG>::CStruct* (*)(T, unsigned);
     583                 :             : 
     584                 :             : template <typename T, InfoTag TAG, NInfosFunc<T> get_n_infos,
     585                 :             :           GetInfoFunc<T, TAG> get_info>
     586                 :             : class InfoIterator {
     587                 :             :     T m_obj;
     588                 :             :     int m_ix;
     589                 :             : 
     590                 :       78370 :     InfoIterator(T obj, int ix) : m_obj(obj), m_ix(ix) {}
     591                 :             : 
     592                 :             :  public:
     593                 :             :     using iterator_category = std::forward_iterator_tag;
     594                 :             :     using difference_type = int;
     595                 :             :     using value_type = OwnedInfo<TAG>;
     596                 :             :     using pointer = value_type*;
     597                 :             :     using reference = value_type&;
     598                 :             : 
     599                 :       28486 :     explicit InfoIterator(T info) : InfoIterator(info, 0) {}
     600                 :             : 
     601                 :      163986 :     OwnedInfo<TAG> operator*() const {
     602                 :      163986 :         return detail::Pointer::to_owned<TAG>(get_info(m_obj, m_ix));
     603                 :             :     }
     604                 :      160875 :     InfoIterator& operator++() {
     605                 :      160875 :         m_ix++;
     606                 :      160875 :         return *this;
     607                 :             :     }
     608                 :             :     InfoIterator operator++(int) {
     609                 :             :         InfoIterator tmp = *this;
     610                 :             :         m_ix++;
     611                 :             :         return tmp;
     612                 :             :     }
     613                 :        3867 :     bool operator==(const InfoIterator& other) const {
     614   [ +  -  +  + ]:        3867 :         return m_obj == other.m_obj && m_ix == other.m_ix;
     615                 :             :     }
     616                 :      185817 :     bool operator!=(const InfoIterator& other) const {
     617   [ +  -  +  + ]:      185817 :         return m_obj != other.m_obj || m_ix != other.m_ix;
     618                 :             :     }
     619                 :             : 
     620                 :             :     [[nodiscard]]
     621                 :        2843 :     mozilla::Maybe<OwnedInfo<TAG>> operator[](size_t ix) const {
     622                 :        2843 :         return detail::Pointer::nullable<TAG>(get_info(m_obj, ix));
     623                 :             :     }
     624                 :             : 
     625                 :       24942 :     [[nodiscard]] InfoIterator begin() const { return InfoIterator{m_obj, 0}; }
     626                 :             :     [[nodiscard]]
     627                 :       24942 :     InfoIterator end() const {
     628                 :       49857 :         int n_fields = get_n_infos(m_obj);
     629                 :       24942 :         return InfoIterator{m_obj, n_fields};
     630                 :             :     }
     631                 :        2071 :     [[nodiscard]] size_t size() const { return get_n_infos(m_obj); }
     632                 :             : };
     633                 :             : 
     634                 :             : // These are used to delete the type-checking and casting methods from
     635                 :             : // InfoOperations specializations for subtypes of GIBaseInfo, as appropriate.
     636                 :             : // So, for example, if you have AutoCallableInfo, you still want to be able to
     637                 :             : // check is_callback, is_function, and is_vfunc, but not is_boxed etc.
     638                 :             : 
     639                 :             : #define DELETE_CALLABLE_TYPECHECK_METHODS \
     640                 :             :     bool is_callback() const = delete;    \
     641                 :             :     bool is_function() const = delete;    \
     642                 :             :     bool is_vfunc() const = delete;
     643                 :             : 
     644                 :             : #define DELETE_REGISTERED_TYPE_TYPECHECK_METHODS \
     645                 :             :     bool is_boxed() const = delete;              \
     646                 :             :     bool is_enum_or_flags() const = delete;      \
     647                 :             :     bool is_flags() const = delete;              \
     648                 :             :     bool is_interface() const = delete;          \
     649                 :             :     bool is_object() const = delete;             \
     650                 :             :     bool is_struct() const = delete;             \
     651                 :             :     bool is_union() const = delete;
     652                 :             : 
     653                 :             : #define DELETE_SUPERCLASS_TYPECHECK_METHODS   \
     654                 :             :     bool is_registered_type() const = delete; \
     655                 :             :     bool is_unresolved() const = delete;
     656                 :             : 
     657                 :             : #define DELETE_CAST_METHOD  \
     658                 :             :     template <InfoTag TAG2> \
     659                 :             :     mozilla::Maybe<const UnownedInfo<TAG2>> as() const = delete;
     660                 :             : 
     661                 :             : #define DELETE_ALL_TYPECHECK_METHODS         \
     662                 :             :     DELETE_SUPERCLASS_TYPECHECK_METHODS      \
     663                 :             :     DELETE_CALLABLE_TYPECHECK_METHODS        \
     664                 :             :     DELETE_REGISTERED_TYPE_TYPECHECK_METHODS \
     665                 :             :     DELETE_CAST_METHOD
     666                 :             : 
     667                 :             : // Needs to come first, because InfoOperations<ARG> and InfoOperations<CALLABLE>
     668                 :             : // instantiate the template by having methods with GI::StackTypeInfo* parameters
     669                 :             : template <class Wrapper>
     670                 :             : class InfoOperations<Wrapper, InfoTag::TYPE>
     671                 :             :     : public BaseInfoOperations<Wrapper> {
     672                 :             :     DELETE_ALL_TYPECHECK_METHODS;
     673                 :             : 
     674                 :             :     [[nodiscard]]
     675                 :      453093 :     GITypeInfo* ptr() const {
     676                 :      453093 :         return detail::Pointer::get_from(*static_cast<const Wrapper*>(this));
     677                 :             :     }
     678                 :             :     // Private, because we don't use this directly. Use the more semantic
     679                 :             :     // versions below (element_type() for GSLIST, GLIST, and ARRAY type tags;
     680                 :             :     // key_type() and value_type() for GHASH.)
     681                 :             :     [[nodiscard]]
     682                 :        5252 :     AutoTypeInfo param_type(int n) const {
     683                 :             :         return detail::Pointer::to_owned<InfoTag::TYPE>(
     684                 :        5252 :             gi_type_info_get_param_type(ptr(), n));
     685                 :             :     }
     686                 :             : 
     687                 :             :  public:
     688                 :             :     [[nodiscard]]
     689                 :        2681 :     mozilla::Maybe<unsigned> array_length_index() const {
     690                 :             :         unsigned out;
     691         [ +  + ]:        2681 :         if (!gi_type_info_get_array_length_index(ptr(), &out))
     692                 :        1426 :             return {};
     693                 :        1255 :         return mozilla::Some(out);
     694                 :             :     }
     695                 :             :     [[nodiscard]]
     696                 :          97 :     mozilla::Maybe<size_t> array_fixed_size() const {
     697                 :             :         size_t out;
     698         [ +  + ]:          97 :         if (!gi_type_info_get_array_fixed_size(ptr(), &out))
     699                 :          10 :             return {};
     700                 :          87 :         return mozilla::Some(out);
     701                 :             :     }
     702                 :             :     [[nodiscard]]
     703                 :        4174 :     GIArrayType array_type() const {
     704                 :        4174 :         return gi_type_info_get_array_type(ptr());
     705                 :             :     }
     706                 :         248 :     void argument_from_hash_pointer(void* hash_pointer, GIArgument* arg) const {
     707                 :         248 :         gi_type_info_argument_from_hash_pointer(ptr(), hash_pointer, arg);
     708                 :         248 :     }
     709                 :             :     [[nodiscard]]
     710                 :           3 :     void* hash_pointer_from_argument(GIArgument* arg) const {
     711                 :           3 :         return gi_type_info_hash_pointer_from_argument(ptr(), arg);
     712                 :             :     }
     713                 :             :     // Unlike the libgirepository API, this doesn't return null. Only call it on
     714                 :             :     // TypeInfo with GI_TYPE_TAG_INTERFACE tag.
     715                 :             :     [[nodiscard]]
     716                 :       84681 :     AutoBaseInfo interface() const {
     717                 :       84681 :         g_assert(tag() == GI_TYPE_TAG_INTERFACE);
     718                 :             :         return detail::Pointer::to_owned<InfoTag::BASE>(
     719                 :       84681 :             gi_type_info_get_interface(ptr()));
     720                 :             :     }
     721                 :             :     [[nodiscard]]
     722                 :       37812 :     bool is_pointer() const {
     723                 :       37812 :         return gi_type_info_is_pointer(ptr());
     724                 :             :     }
     725                 :             :     [[nodiscard]]
     726                 :        1041 :     bool is_zero_terminated() const {
     727                 :        1041 :         return gi_type_info_is_zero_terminated(ptr());
     728                 :             :     }
     729                 :             :     [[nodiscard]]
     730                 :         347 :     GITypeTag storage_type() const {
     731                 :         347 :         return gi_type_info_get_storage_type(ptr());
     732                 :             :     }
     733                 :      316757 :     [[nodiscard]] GITypeTag tag() const { return gi_type_info_get_tag(ptr()); }
     734                 :             :     void extract_ffi_return_value(GIFFIReturnValue* ffi_value,
     735                 :             :                                   GIArgument* arg) const {
     736                 :             :         gi_type_info_extract_ffi_return_value(ptr(), ffi_value, arg);
     737                 :             :     }
     738                 :             : 
     739                 :             :     // Methods not present in GIRepository
     740                 :             : 
     741                 :             :     [[nodiscard]] bool can_be_allocated_directly() const;
     742                 :             :     [[nodiscard]] bool direct_allocation_has_pointers() const;
     743                 :             :     [[nodiscard]]
     744                 :           2 :     const char* display_string() const {
     745                 :           2 :         GITypeTag type_tag = tag();
     746         [ +  - ]:           2 :         if (type_tag == GI_TYPE_TAG_INTERFACE)
     747                 :           2 :             return interface().type_string();
     748                 :           0 :         return gi_type_tag_to_string(type_tag);
     749                 :             :     }
     750                 :             : 
     751                 :             :     [[nodiscard]]
     752                 :             :     bool is_string_type() const {
     753                 :             :         GITypeTag t = tag();
     754                 :             :         return t == GI_TYPE_TAG_FILENAME || t == GI_TYPE_TAG_UTF8;
     755                 :             :     }
     756                 :             : 
     757                 :             :     [[nodiscard]]
     758                 :       62232 :     bool is_basic() const {
     759                 :       62232 :         GITypeTag t = tag();
     760   [ +  +  +  -  :       62232 :         if (t == GI_TYPE_TAG_VOID && is_pointer())
                   +  + ]
     761                 :         280 :             return false;  // void* is not a basic type
     762   [ +  +  +  + ]:       61952 :         return GI_TYPE_TAG_IS_BASIC(t);
     763                 :             :     }
     764                 :             : 
     765                 :             :     // More semantic versions of param_type(), that are only intended to be
     766                 :             :     // called on TypeInfos where the result is known not to be null
     767                 :             : 
     768                 :             :     [[nodiscard]]
     769                 :        5056 :     AutoTypeInfo element_type() const {
     770                 :        5056 :         g_assert(tag() == GI_TYPE_TAG_ARRAY || tag() == GI_TYPE_TAG_GLIST ||
     771                 :             :                  tag() == GI_TYPE_TAG_GSLIST);
     772                 :        5056 :         return param_type(0);
     773                 :             :     }
     774                 :             : 
     775                 :             :     [[nodiscard]]
     776                 :          98 :     AutoTypeInfo key_type() const {
     777                 :          98 :         g_assert(tag() == GI_TYPE_TAG_GHASH);
     778                 :          98 :         return param_type(0);
     779                 :             :     }
     780                 :             : 
     781                 :             :     [[nodiscard]]
     782                 :          98 :     AutoTypeInfo value_type() const {
     783                 :          98 :         g_assert(tag() == GI_TYPE_TAG_GHASH);
     784                 :          98 :         return param_type(1);
     785                 :             :     }
     786                 :             : };
     787                 :             : 
     788                 :             : // Needs to come after InfoOperations<TYPE> but before InfoOperations<CALLABLE>
     789                 :             : // since this class instantiates the GI::StackTypeInfo template, but
     790                 :             : // InfoOperations<CALLABLE> instantiates this one.
     791                 :             : template <class Wrapper>
     792                 :             : class InfoOperations<Wrapper, InfoTag::ARG>
     793                 :             :     : public BaseInfoOperations<Wrapper> {
     794                 :             :     DELETE_ALL_TYPECHECK_METHODS;
     795                 :             : 
     796                 :             :     [[nodiscard]]
     797                 :      155384 :     GIArgInfo* ptr() const {
     798                 :      155384 :         return detail::Pointer::get_from(*static_cast<const Wrapper*>(this));
     799                 :             :     }
     800                 :             : 
     801                 :             :  public:
     802                 :             :     [[nodiscard]]
     803                 :       23623 :     bool caller_allocates() const {
     804                 :       23623 :         return gi_arg_info_is_caller_allocates(ptr());
     805                 :             :     }
     806                 :             :     [[nodiscard]]
     807                 :        1078 :     mozilla::Maybe<unsigned> closure_index() const {
     808                 :             :         unsigned out;
     809         [ +  + ]:        1078 :         if (!gi_arg_info_get_closure_index(ptr(), &out))
     810                 :         416 :             return {};
     811                 :         662 :         return mozilla::Some(out);
     812                 :             :     }
     813                 :             :     [[nodiscard]]
     814                 :        1078 :     mozilla::Maybe<unsigned> destroy_index() const {
     815                 :             :         unsigned out;
     816         [ +  + ]:        1078 :         if (!gi_arg_info_get_destroy_index(ptr(), &out))
     817                 :         913 :             return {};
     818                 :         165 :         return mozilla::Some(out);
     819                 :             :     }
     820                 :             :     [[nodiscard]]
     821                 :       28557 :     GIDirection direction() const {
     822                 :       28557 :         return gi_arg_info_get_direction(ptr());
     823                 :             :     }
     824                 :       27459 :     void load_type(StackTypeInfo* type) const {
     825                 :       27459 :         gi_arg_info_load_type_info(ptr(), detail::Pointer::get_from(*type));
     826                 :       27459 :     }
     827                 :             :     [[nodiscard]]
     828                 :        1330 :     bool is_optional() const {
     829                 :        1330 :         return gi_arg_info_is_optional(ptr());
     830                 :             :     }
     831                 :             :     [[nodiscard]]
     832                 :          35 :     bool is_return_value() const {
     833                 :          35 :         return gi_arg_info_is_return_value(ptr());
     834                 :             :     }
     835                 :             :     [[nodiscard]]
     836                 :       23582 :     bool may_be_null() const {
     837                 :       23582 :         return gi_arg_info_may_be_null(ptr());
     838                 :             :     }
     839                 :             :     [[nodiscard]]
     840                 :       47565 :     GITransfer ownership_transfer() const {
     841                 :       47565 :         return gi_arg_info_get_ownership_transfer(ptr());
     842                 :             :     }
     843                 :             :     [[nodiscard]]
     844                 :        1077 :     GIScopeType scope() const {
     845                 :        1077 :         return gi_arg_info_get_scope(ptr());
     846                 :             :     }
     847                 :             : };
     848                 :             : 
     849                 :             : template <class Wrapper>
     850                 :             : class InfoOperations<Wrapper, InfoTag::CALLABLE>
     851                 :             :     : public BaseInfoOperations<Wrapper> {
     852                 :             :     DELETE_SUPERCLASS_TYPECHECK_METHODS;
     853                 :             :     DELETE_REGISTERED_TYPE_TYPECHECK_METHODS;
     854                 :             : 
     855                 :             :     [[nodiscard]]
     856                 :      384109 :     GICallableInfo* ptr() const {
     857                 :      384109 :         return GI_CALLABLE_INFO(
     858                 :             :             detail::Pointer::get_from(*static_cast<const Wrapper*>(this)));
     859                 :             :     }
     860                 :             : 
     861                 :             :  public:
     862                 :             :     using ArgsIterator =
     863                 :             :         InfoIterator<GICallableInfo*, InfoTag::ARG, gi_callable_info_get_n_args,
     864                 :             :                      gi_callable_info_get_arg>;
     865                 :             :     [[nodiscard]]
     866                 :             :     ArgsIterator args() const {
     867                 :             :         return ArgsIterator{ptr()};
     868                 :             :     }
     869                 :             :     [[nodiscard]]
     870                 :          11 :     AutoArgInfo arg(unsigned n) const {
     871                 :          11 :         g_assert(n < n_args());
     872                 :             :         return detail::Pointer::to_owned<InfoTag::ARG>(
     873                 :          11 :             gi_callable_info_get_arg(ptr(), n));
     874                 :             :     }
     875                 :             :     [[nodiscard]]
     876                 :      135712 :     unsigned n_args() const {
     877                 :      135712 :         return gi_callable_info_get_n_args(ptr());
     878                 :             :     }
     879                 :             : 
     880                 :             :     [[nodiscard]]
     881                 :       11655 :     GITransfer caller_owns() const {
     882                 :       11655 :         return gi_callable_info_get_caller_owns(ptr());
     883                 :             :     }
     884                 :             :     [[nodiscard]]
     885                 :       76930 :     bool can_throw_gerror() const {
     886                 :       76930 :         return gi_callable_info_can_throw_gerror(ptr());
     887                 :             :     }
     888                 :             :     [[nodiscard]]
     889                 :         343 :     void* closure_native_address(ffi_closure* closure) const {
     890                 :         343 :         return gi_callable_info_get_closure_native_address(ptr(), closure);
     891                 :             :     }
     892                 :             :     [[nodiscard]]
     893                 :         343 :     ffi_closure* create_closure(ffi_cif* cif, GIFFIClosureCallback callback,
     894                 :             :                                 void* user_data) const {
     895                 :         343 :         return gi_callable_info_create_closure(ptr(), cif, callback, user_data);
     896                 :             :     }
     897                 :         331 :     void destroy_closure(ffi_closure* closure) const {
     898                 :         331 :         gi_callable_info_destroy_closure(ptr(), closure);
     899                 :         331 :     }
     900                 :             :     [[nodiscard]]
     901                 :           2 :     Gjs::GErrorResult<> init_function_invoker(
     902                 :             :         void* address, GIFunctionInvoker* invoker) const {
     903                 :           2 :         GError* error = nullptr;
     904                 :           2 :         return this->bool_gerror(gi_function_invoker_new_for_address(
     905                 :             :                                      address, ptr(), invoker, &error),
     906                 :           4 :                                  error);
     907                 :             :     }
     908                 :             :     [[nodiscard]]
     909                 :        4000 :     GITransfer instance_ownership_transfer() const {
     910                 :        4000 :         return gi_callable_info_get_instance_ownership_transfer(ptr());
     911                 :             :     }
     912                 :             :     [[nodiscard]]
     913                 :       90778 :     bool is_method() const {
     914                 :       90778 :         return gi_callable_info_is_method(ptr());
     915                 :             :     }
     916                 :       27479 :     void load_arg(unsigned n, StackArgInfo* arg) const {
     917                 :       27479 :         g_assert(n < n_args());
     918                 :       27479 :         gi_callable_info_load_arg(ptr(), n, detail::Pointer::get_from(*arg));
     919                 :       27479 :     }
     920                 :       25468 :     void load_return_type(StackTypeInfo* type) const {
     921                 :       25468 :         gi_callable_info_load_return_type(ptr(),
     922                 :             :                                           detail::Pointer::get_from(*type));
     923                 :       25468 :     }
     924                 :             :     [[nodiscard]]
     925                 :       11000 :     bool may_return_null() const {
     926                 :       11000 :         return gi_callable_info_may_return_null(ptr());
     927                 :             :     }
     928                 :             :     [[nodiscard]]
     929                 :          57 :     bool skip_return() const {
     930                 :          57 :         return gi_callable_info_skip_return(ptr());
     931                 :             :     }
     932                 :             : 
     933                 :             :     // Methods not in GIRepository
     934                 :             : 
     935                 :        3287 :     void log_usage() {
     936                 :             : #if GJS_VERBOSE_ENABLE_GI_USAGE
     937                 :             :         std::ostringstream out;
     938                 :             : 
     939                 :             : #    define DIRECTION_STRING(d)              \
     940                 :             :         (((d) == GI_DIRECTION_IN)    ? "IN"  \
     941                 :             :          : ((d) == GI_DIRECTION_OUT) ? "OUT" \
     942                 :             :                                      : "INOUT")
     943                 :             : #    define TRANSFER_STRING(t)                          \
     944                 :             :         (((t) == GI_TRANSFER_NOTHING)     ? "NOTHING"   \
     945                 :             :          : ((t) == GI_TRANSFER_CONTAINER) ? "CONTAINER" \
     946                 :             :                                           : "EVERYTHING")
     947                 :             : 
     948                 :             :         out << ".details = { .func = { .retval_transfer = GI_TRANSFER_"
     949                 :             :             << TRANSFER_STRING(caller_owns()) << ", .n_args = " << n_args()
     950                 :             :             << ", .args = { ";
     951                 :             : 
     952                 :             :         ArgsIterator iter = args();
     953                 :             :         std::for_each(iter.begin(), iter.end(), [&out](AutoArgInfo arg_info) {
     954                 :             :             out << "{ GI_DIRECTION_" << DIRECTION_STRING(arg_info.direction())
     955                 :             :                 << ", GI_TRANSFER_"
     956                 :             :                 << TRANSFER_STRING(arg_info.ownership_transfer()) << " }, ";
     957                 :             :         });
     958                 :             :         out.seekp(-2, std::ios_base::end);  // Erase trailing comma
     959                 :             : 
     960                 :             : #    undef DIRECTION_STRING
     961                 :             : #    undef TRANSFER_STRING
     962                 :             : 
     963                 :             :         out << " } } }";
     964                 :             :         std::string details{out.str()};
     965                 :             : 
     966                 :             :         using Base = BaseInfoOperations<Wrapper>;
     967                 :             :         mozilla::Maybe<GI::BaseInfo> parent = Base::container();
     968                 :             :         gjs_debug_gi_usage(
     969                 :             :             "{ GIInfoType %s, \"%s\", \"%s\", \"%s\", %s }",
     970                 :             :             Base::type_string(), Base::ns(),
     971                 :             :             parent.map(std::mem_fn(&GI::BaseInfo::name)).valueOr(""),
     972                 :             :             Base::name(), details.c_str());
     973                 :             : #endif  // GJS_VERBOSE_ENABLE_GI_USAGE
     974                 :        3287 :     }
     975                 :             : };
     976                 :             : 
     977                 :             : template <class Wrapper>
     978                 :             : using CallableInfoOperations = InfoOperations<Wrapper, InfoTag::CALLABLE>;
     979                 :             : 
     980                 :             : template <class Wrapper>
     981                 :             : class InfoOperations<Wrapper, InfoTag::REGISTERED_TYPE>
     982                 :             :     : public BaseInfoOperations<Wrapper> {
     983                 :             :     DELETE_SUPERCLASS_TYPECHECK_METHODS;
     984                 :             :     DELETE_CALLABLE_TYPECHECK_METHODS;
     985                 :             : 
     986                 :             :     [[nodiscard]]
     987                 :       69271 :     GIRegisteredTypeInfo* ptr() const {
     988                 :       69271 :         return GI_REGISTERED_TYPE_INFO(
     989                 :             :             detail::Pointer::get_from(*static_cast<const Wrapper*>(this)));
     990                 :             :     }
     991                 :             : 
     992                 :             :  public:
     993                 :             :     [[nodiscard]]
     994                 :       67224 :     GType gtype() const {
     995                 :       67224 :         return gi_registered_type_info_get_g_type(ptr());
     996                 :             :     }
     997                 :             : 
     998                 :             :     // Methods not in GIRepository
     999                 :             : 
    1000                 :             :     [[nodiscard]]
    1001                 :       29987 :     bool is_gdk_atom() const {
    1002         [ +  + ]:       30022 :         return strcmp("Atom", this->name()) == 0 &&
    1003         [ +  - ]:       30022 :                strcmp("Gdk", this->ns()) == 0;
    1004                 :             :     }
    1005                 :             :     [[nodiscard]]
    1006                 :           9 :     bool is_g_value() const {
    1007   [ +  +  -  + ]:           9 :         return g_type_is_a(gtype(), G_TYPE_VALUE);
    1008                 :             :     }
    1009                 :             : 
    1010                 :        2047 :     operator const BaseInfo() const {
    1011                 :        2047 :         return detail::Pointer::to_unowned<InfoTag::BASE>(GI_BASE_INFO(ptr()));
    1012                 :             :     }
    1013                 :             : };
    1014                 :             : 
    1015                 :             : template <class Wrapper>
    1016                 :             : using RegisteredTypeInfoOperations =
    1017                 :             :     InfoOperations<Wrapper, InfoTag::REGISTERED_TYPE>;
    1018                 :             : 
    1019                 :             : template <class Wrapper>
    1020                 :             : class InfoOperations<Wrapper, InfoTag::CALLBACK>
    1021                 :             :     : public CallableInfoOperations<Wrapper> {
    1022                 :             :     DELETE_ALL_TYPECHECK_METHODS;
    1023                 :             : 
    1024                 :             :     [[nodiscard]]
    1025                 :         277 :     GICallbackInfo* ptr() const {
    1026                 :         277 :         return detail::Pointer::get_from(*static_cast<const Wrapper*>(this));
    1027                 :             :     }
    1028                 :             : 
    1029                 :             :  public:
    1030                 :             :     operator const BaseInfo() const {
    1031                 :             :         return detail::Pointer::to_unowned<InfoTag::BASE>(GI_BASE_INFO(ptr()));
    1032                 :             :     }
    1033                 :             : 
    1034                 :         277 :     operator const CallableInfo() const {
    1035                 :             :         return detail::Pointer::to_unowned<InfoTag::CALLABLE>(
    1036                 :         277 :             GI_CALLABLE_INFO(ptr()));
    1037                 :             :     }
    1038                 :             : };
    1039                 :             : 
    1040                 :             : template <class Wrapper>
    1041                 :             : class InfoOperations<Wrapper, InfoTag::CONSTANT>
    1042                 :             :     : public BaseInfoOperations<Wrapper> {
    1043                 :             :     DELETE_ALL_TYPECHECK_METHODS;
    1044                 :             : 
    1045                 :             :     [[nodiscard]]
    1046                 :       14235 :     GIConstantInfo* ptr() const {
    1047                 :       14235 :         return detail::Pointer::get_from(*static_cast<const Wrapper*>(this));
    1048                 :             :     }
    1049                 :             : 
    1050                 :             :  public:
    1051                 :        4745 :     void free_value(GIArgument* arg) const {
    1052                 :        4745 :         gi_constant_info_free_value(ptr(), arg);
    1053                 :        4745 :     }
    1054                 :        4745 :     int load_value(GIArgument* arg) const {
    1055                 :        4745 :         return gi_constant_info_get_value(ptr(), arg);
    1056                 :             :     }
    1057                 :             :     [[nodiscard]]
    1058                 :        4745 :     AutoTypeInfo type_info() const {
    1059                 :             :         return detail::Pointer::to_owned<InfoTag::TYPE>(
    1060                 :        4745 :             gi_constant_info_get_type_info(ptr()));
    1061                 :             :     }
    1062                 :             : };
    1063                 :             : 
    1064                 :             : // Must come before any use of MethodsIterator
    1065                 :             : template <class Wrapper>
    1066                 :             : class InfoOperations<Wrapper, InfoTag::FUNCTION>
    1067                 :             :     : public CallableInfoOperations<Wrapper> {
    1068                 :             :     DELETE_ALL_TYPECHECK_METHODS;
    1069                 :             : 
    1070                 :             :     [[nodiscard]]
    1071                 :       93806 :     GIFunctionInfo* ptr() const {
    1072                 :       93806 :         return detail::Pointer::get_from(*static_cast<const Wrapper*>(this));
    1073                 :             :     }
    1074                 :             : 
    1075                 :             :     [[nodiscard]]
    1076                 :       64941 :     GIFunctionInfoFlags flags() const {
    1077                 :       64941 :         return gi_function_info_get_flags(ptr());
    1078                 :             :     }
    1079                 :             : 
    1080                 :             :  public:
    1081                 :             :     [[nodiscard]]
    1082                 :          93 :     Gjs::GErrorResult<> invoke(const mozilla::Span<const GIArgument>& in_args,
    1083                 :             :                                const mozilla::Span<GIArgument>& out_args,
    1084                 :             :                                GIArgument* return_value) const {
    1085                 :          93 :         g_assert(in_args.size() <= INT_MAX);
    1086                 :          93 :         g_assert(out_args.size() <= INT_MAX);
    1087                 :          93 :         GError* error = nullptr;
    1088                 :             :         return this->bool_gerror(
    1089                 :          93 :             gi_function_info_invoke(ptr(), in_args.data(), in_args.size(),
    1090                 :             :                                     out_args.data(), out_args.size(),
    1091                 :             :                                     return_value, &error),
    1092                 :         186 :             error);
    1093                 :             :     }
    1094                 :             :     [[nodiscard]]
    1095                 :       13886 :     Gjs::GErrorResult<> prep_invoker(GIFunctionInvoker* invoker) const {
    1096                 :       13886 :         GError* error = nullptr;
    1097                 :             :         return this->bool_gerror(
    1098                 :       13886 :             gi_function_info_prep_invoker(ptr(), invoker, &error), error);
    1099                 :             :     }
    1100                 :             :     [[nodiscard]]
    1101                 :         844 :     const char* symbol() const {
    1102                 :         844 :         return gi_function_info_get_symbol(ptr());
    1103                 :             :     }
    1104                 :             : 
    1105                 :             :     // Has to be defined later because there's a chicken-and-egg loop between
    1106                 :             :     // AutoPropertyInfo and AutoFunctionInfo
    1107                 :             :     [[nodiscard]]
    1108                 :             :     mozilla::Maybe<GI::AutoPropertyInfo> property() const;
    1109                 :             : 
    1110                 :             :     // Methods not in GIRepository
    1111                 :             : 
    1112                 :             :     [[nodiscard]]
    1113                 :       46161 :     bool is_method() const {
    1114                 :       46161 :         return flags() & GI_FUNCTION_IS_METHOD;
    1115                 :             :     }
    1116                 :             :     [[nodiscard]]
    1117                 :       18780 :     bool is_constructor() const {
    1118                 :       18780 :         return flags() & GI_FUNCTION_IS_CONSTRUCTOR;
    1119                 :             :     }
    1120                 :             : 
    1121                 :       13796 :     operator const CallableInfo() const {
    1122                 :             :         return detail::Pointer::to_unowned<InfoTag::CALLABLE>(
    1123                 :       13796 :             GI_CALLABLE_INFO(ptr()));
    1124                 :             :     }
    1125                 :             : };
    1126                 :             : 
    1127                 :             : template <class Wrapper>
    1128                 :             : class InfoOperations<Wrapper, InfoTag::ENUM>
    1129                 :             :     : public RegisteredTypeInfoOperations<Wrapper> {
    1130                 :             :     DELETE_REGISTERED_TYPE_TYPECHECK_METHODS;
    1131                 :             : 
    1132                 :             :     [[nodiscard]]
    1133                 :        7292 :     GIEnumInfo* ptr() const {
    1134                 :        7292 :         return GI_ENUM_INFO(
    1135                 :             :             detail::Pointer::get_from(*static_cast<const Wrapper*>(this)));
    1136                 :             :     }
    1137                 :             : 
    1138                 :             :  public:
    1139                 :             :     using ValuesIterator =
    1140                 :             :         InfoIterator<GIEnumInfo*, InfoTag::VALUE, gi_enum_info_get_n_values,
    1141                 :        4392 :                      gi_enum_info_get_value>;
    1142                 :             :     [[nodiscard]]
    1143                 :        4392 :     ValuesIterator values() const {
    1144                 :        4392 :         return ValuesIterator{ptr()};
    1145                 :             :     }
    1146                 :             : 
    1147                 :             :     using MethodsIterator =
    1148                 :             :         InfoIterator<GIEnumInfo*, InfoTag::FUNCTION, gi_enum_info_get_n_methods,
    1149                 :         250 :                      gi_enum_info_get_method>;
    1150                 :             :     [[nodiscard]]
    1151                 :         250 :     MethodsIterator methods() const {
    1152                 :         250 :         return MethodsIterator{ptr()};
    1153                 :             :     }
    1154                 :             :     [[nodiscard]]
    1155                 :             :     mozilla::Maybe<AutoFunctionInfo> method(const char* name) const {
    1156                 :             :         return detail::Pointer::nullable<InfoTag::FUNCTION>(
    1157                 :             :             gi_enum_info_find_method(ptr(), name));
    1158                 :             :     }
    1159                 :             : 
    1160                 :             :     [[nodiscard]]
    1161                 :         157 :     const char* error_domain() const {
    1162                 :         157 :         return gi_enum_info_get_error_domain(ptr());
    1163                 :             :     }
    1164                 :             :     [[nodiscard]]
    1165                 :        2493 :     GITypeTag storage_type() const {
    1166                 :        2493 :         return gi_enum_info_get_storage_type(ptr());
    1167                 :             :     }
    1168                 :             : 
    1169                 :             :     // Methods not in GIRepository
    1170                 :             : 
    1171                 :             :     [[nodiscard]]
    1172                 :        2492 :     bool uses_signed_type() const {
    1173         [ +  + ]:        2492 :         switch (storage_type()) {
    1174                 :         104 :             case GI_TYPE_TAG_INT8:
    1175                 :             :             case GI_TYPE_TAG_INT16:
    1176                 :             :             case GI_TYPE_TAG_INT32:
    1177                 :             :             case GI_TYPE_TAG_INT64:
    1178                 :         104 :                 return true;
    1179                 :        2388 :             default:
    1180                 :        2388 :                 return false;
    1181                 :             :         }
    1182                 :             :     }
    1183                 :             : 
    1184                 :             :     // This is hacky - gi_function_info_invoke() and
    1185                 :             :     // gi_field_info_get/set_field() expect the enum value in
    1186                 :             :     // gjs_arg_member<int>(arg) and depend on all flags and enumerations being
    1187                 :             :     // passed on the stack in a 32-bit field. See FIXME comment in
    1188                 :             :     // gi_field_info_get_field(). The same assumption of enums cast to 32-bit
    1189                 :             :     // signed integers is found in g_value_set_enum() / g_value_set_flags().
    1190                 :             :     [[nodiscard]]
    1191                 :        2492 :     int64_t enum_from_int(int int_value) const {
    1192         [ +  + ]:        2492 :         if (uses_signed_type())
    1193                 :         104 :             return int64_t{int_value};
    1194                 :             :         else
    1195                 :        2388 :             return int64_t{static_cast<uint32_t>(int_value)};
    1196                 :             :     }
    1197                 :             : 
    1198                 :             :     // Here for symmetry, but result is the same for the two cases
    1199                 :             :     [[nodiscard]]
    1200                 :         146 :     int enum_to_int(int64_t value) const {
    1201                 :         146 :         return static_cast<int>(value);
    1202                 :             :     }
    1203                 :             : };
    1204                 :             : 
    1205                 :             : template <class Wrapper>
    1206                 :             : using EnumInfoOperations = InfoOperations<Wrapper, InfoTag::ENUM>;
    1207                 :             : 
    1208                 :             : template <class Wrapper>
    1209                 :             : class InfoOperations<Wrapper, InfoTag::FLAGS>
    1210                 :             :     : public EnumInfoOperations<Wrapper> {
    1211                 :             :     DELETE_ALL_TYPECHECK_METHODS;
    1212                 :             : };
    1213                 :             : 
    1214                 :             : template <class Wrapper>
    1215                 :             : class InfoOperations<Wrapper, InfoTag::FIELD>
    1216                 :             :     : public BaseInfoOperations<Wrapper> {
    1217                 :             :     DELETE_ALL_TYPECHECK_METHODS;
    1218                 :             : 
    1219                 :             :     [[nodiscard]]
    1220                 :       13242 :     GIFieldInfo* ptr() const {
    1221                 :       13242 :         return detail::Pointer::get_from(*static_cast<const Wrapper*>(this));
    1222                 :             :     }
    1223                 :             : 
    1224                 :             :     // Use the various is_FLAG() methods instead.
    1225                 :             :     [[nodiscard]]
    1226                 :           6 :     GIFieldInfoFlags flags() const {
    1227                 :           6 :         return gi_field_info_get_flags(ptr());
    1228                 :             :     }
    1229                 :             : 
    1230                 :             :  public:
    1231                 :         201 :     [[nodiscard]] size_t offset() const {
    1232                 :         201 :         return gi_field_info_get_offset(ptr());
    1233                 :             :     }
    1234                 :             :     [[nodiscard]]
    1235                 :        2535 :     BoolResult read(void* blob, GIArgument* value_out) const {
    1236                 :        2535 :         return this->bool_to_result(
    1237                 :        5070 :             gi_field_info_get_field(ptr(), blob, value_out));
    1238                 :             :     }
    1239                 :             :     [[nodiscard]]
    1240                 :       10253 :     AutoTypeInfo type_info() const {
    1241                 :             :         return detail::Pointer::to_owned<InfoTag::TYPE>(
    1242                 :       10253 :             gi_field_info_get_type_info(ptr()));
    1243                 :             :     }
    1244                 :             :     [[nodiscard]]
    1245                 :         247 :     BoolResult write(void* blob, const GIArgument* value) const {
    1246                 :         247 :         return this->bool_to_result(
    1247                 :         494 :             gi_field_info_set_field(ptr(), blob, value));
    1248                 :             :     }
    1249                 :             : 
    1250                 :             :     // Methods not in GIRepository
    1251                 :             : 
    1252                 :             :     [[nodiscard]]
    1253                 :             :     bool is_readable() const {
    1254                 :             :         return flags() & GI_FIELD_IS_READABLE;
    1255                 :             :     }
    1256                 :             :     [[nodiscard]]
    1257                 :           6 :     bool is_writable() const {
    1258                 :           6 :         return flags() & GI_FIELD_IS_WRITABLE;
    1259                 :             :     }
    1260                 :             : };
    1261                 :             : 
    1262                 :             : template <class Wrapper>
    1263                 :             : class InfoOperations<Wrapper, InfoTag::SIGNAL>
    1264                 :             :     : public CallableInfoOperations<Wrapper> {
    1265                 :             :     DELETE_ALL_TYPECHECK_METHODS;
    1266                 :             : 
    1267                 :             :     [[nodiscard]]
    1268                 :             :     GISignalInfo* ptr() const {
    1269                 :             :         return detail::Pointer::get_from(*static_cast<const Wrapper*>(this));
    1270                 :             :     }
    1271                 :             : };
    1272                 :             : 
    1273                 :             : template <class Wrapper>
    1274                 :             : class InfoOperations<Wrapper, InfoTag::STRUCT>
    1275                 :             :     : public RegisteredTypeInfoOperations<Wrapper> {
    1276                 :             :     DELETE_ALL_TYPECHECK_METHODS;
    1277                 :             : 
    1278                 :             :     [[nodiscard]]
    1279                 :      103045 :     GIStructInfo* ptr() const {
    1280                 :      103045 :         return detail::Pointer::get_from(*static_cast<const Wrapper*>(this));
    1281                 :             :     }
    1282                 :             : 
    1283                 :             :  public:
    1284                 :             :     using FieldsIterator =
    1285                 :             :         InfoIterator<GIStructInfo*, InfoTag::FIELD, gi_struct_info_get_n_fields,
    1286                 :        4580 :                      gi_struct_info_get_field>;
    1287                 :             :     [[nodiscard]]
    1288                 :        6022 :     FieldsIterator fields() const {
    1289                 :        6022 :         return FieldsIterator{ptr()};
    1290                 :             :     }
    1291                 :             : 
    1292                 :             :     using MethodsIterator =
    1293                 :             :         InfoIterator<GIStructInfo*, InfoTag::FUNCTION,
    1294                 :        2879 :                      gi_struct_info_get_n_methods, gi_struct_info_get_method>;
    1295                 :             :     [[nodiscard]]
    1296                 :        2966 :     MethodsIterator methods() const {
    1297                 :        2966 :         return MethodsIterator{ptr()};
    1298                 :             :     }
    1299                 :             :     [[nodiscard]]
    1300                 :        6836 :     mozilla::Maybe<AutoFunctionInfo> method(const char* name) const {
    1301                 :             :         return detail::Pointer::nullable<InfoTag::FUNCTION>(
    1302                 :        6836 :             gi_struct_info_find_method(ptr(), name));
    1303                 :             :     }
    1304                 :             : 
    1305                 :             :     [[nodiscard]]
    1306                 :       42594 :     bool is_foreign() const {
    1307                 :       42594 :         return gi_struct_info_is_foreign(ptr());
    1308                 :             :     }
    1309                 :             :     [[nodiscard]]
    1310                 :       23822 :     bool is_gtype_struct() const {
    1311                 :       23822 :         return gi_struct_info_is_gtype_struct(ptr());
    1312                 :             :     }
    1313                 :         519 :     [[nodiscard]] size_t size() const { return gi_struct_info_get_size(ptr()); }
    1314                 :             : 
    1315                 :       20286 :     operator const BaseInfo() const {
    1316                 :       20286 :         return detail::Pointer::to_unowned<InfoTag::BASE>(GI_BASE_INFO(ptr()));
    1317                 :             :     }
    1318                 :             : };
    1319                 :             : 
    1320                 :             : template <class Wrapper>
    1321                 :             : class InfoOperations<Wrapper, InfoTag::UNION>
    1322                 :             :     : public RegisteredTypeInfoOperations<Wrapper> {
    1323                 :             :     DELETE_ALL_TYPECHECK_METHODS;
    1324                 :             : 
    1325                 :             :     [[nodiscard]]
    1326                 :         532 :     GIUnionInfo* ptr() const {
    1327                 :         532 :         return detail::Pointer::get_from(*static_cast<const Wrapper*>(this));
    1328                 :             :     }
    1329                 :             : 
    1330                 :             :  public:
    1331                 :             :     using FieldsIterator =
    1332                 :             :         InfoIterator<GIUnionInfo*, InfoTag::FIELD, gi_union_info_get_n_fields,
    1333                 :         114 :                      gi_union_info_get_field>;
    1334                 :             :     [[nodiscard]]
    1335                 :         205 :     FieldsIterator fields() const {
    1336                 :         205 :         return FieldsIterator{ptr()};
    1337                 :             :     }
    1338                 :             : 
    1339                 :             :     using MethodsIterator =
    1340                 :             :         InfoIterator<GIUnionInfo*, InfoTag::FUNCTION,
    1341                 :          14 :                      gi_union_info_get_n_methods, gi_union_info_get_method>;
    1342                 :             :     [[nodiscard]]
    1343                 :          14 :     MethodsIterator methods() const {
    1344                 :          14 :         return MethodsIterator{ptr()};
    1345                 :             :     }
    1346                 :             :     [[nodiscard]]
    1347                 :         271 :     mozilla::Maybe<AutoFunctionInfo> method(const char* name) const {
    1348                 :             :         return detail::Pointer::nullable<InfoTag::FUNCTION>(
    1349                 :         271 :             gi_union_info_find_method(ptr(), name));
    1350                 :             :     }
    1351                 :             : 
    1352                 :          42 :     [[nodiscard]] size_t size() const { return gi_union_info_get_size(ptr()); }
    1353                 :             : };
    1354                 :             : 
    1355                 :             : template <class Wrapper>
    1356                 :             : class InfoOperations<Wrapper, InfoTag::VFUNC>
    1357                 :             :     : public CallableInfoOperations<Wrapper> {
    1358                 :             :     DELETE_ALL_TYPECHECK_METHODS;
    1359                 :             : 
    1360                 :             :     [[nodiscard]]
    1361                 :          75 :     GIVFuncInfo* ptr() const {
    1362                 :          75 :         return detail::Pointer::get_from(*static_cast<const Wrapper*>(this));
    1363                 :             :     }
    1364                 :             : 
    1365                 :             :  public:
    1366                 :             :     [[nodiscard]]
    1367                 :           6 :     Gjs::GErrorResult<void*> address(GType implementor_gtype) const {
    1368                 :           6 :         Gjs::AutoError error;  // Cannot use GError*, distinguish from void*
    1369                 :           6 :         void* address =
    1370                 :           6 :             gi_vfunc_info_get_address(ptr(), implementor_gtype, error.out());
    1371         [ +  + ]:           6 :         if (!address)
    1372                 :           1 :             return mozilla::Err(std::move(error));
    1373                 :           5 :         return address;
    1374                 :           6 :     }
    1375                 :             : 
    1376                 :          69 :     [[nodiscard]] operator const CallableInfo() const {
    1377                 :             :         return detail::Pointer::to_unowned<InfoTag::CALLABLE>(
    1378                 :          69 :             GI_CALLABLE_INFO(ptr()));
    1379                 :             :     }
    1380                 :             : };
    1381                 :             : 
    1382                 :             : template <class Wrapper>
    1383                 :             : class InfoOperations<Wrapper, InfoTag::INTERFACE>
    1384                 :             :     : public RegisteredTypeInfoOperations<Wrapper> {
    1385                 :             :     DELETE_ALL_TYPECHECK_METHODS;
    1386                 :             : 
    1387                 :             :     [[nodiscard]]
    1388                 :        5883 :     GIInterfaceInfo* ptr() const {
    1389                 :        5883 :         return detail::Pointer::get_from(*static_cast<const Wrapper*>(this));
    1390                 :             :     }
    1391                 :             : 
    1392                 :             :  public:
    1393                 :             :     using MethodsIterator = InfoIterator<GIInterfaceInfo*, InfoTag::FUNCTION,
    1394                 :             :                                          gi_interface_info_get_n_methods,
    1395                 :         311 :                                          gi_interface_info_get_method>;
    1396                 :             :     [[nodiscard]]
    1397                 :         283 :     MethodsIterator methods() const {
    1398                 :         283 :         return MethodsIterator{ptr()};
    1399                 :             :     }
    1400                 :             :     [[nodiscard]]
    1401                 :        3777 :     mozilla::Maybe<AutoFunctionInfo> method(const char* name) const {
    1402                 :             :         return detail::Pointer::nullable<InfoTag::FUNCTION>(
    1403                 :        3777 :             gi_interface_info_find_method(ptr(), name));
    1404                 :             :     }
    1405                 :             : 
    1406                 :             :     using PropertiesIterator = InfoIterator<GIInterfaceInfo*, InfoTag::PROPERTY,
    1407                 :             :                                             gi_interface_info_get_n_properties,
    1408                 :        1534 :                                             gi_interface_info_get_property>;
    1409                 :             :     [[nodiscard]]
    1410                 :        1534 :     PropertiesIterator properties() const {
    1411                 :        1534 :         return PropertiesIterator{ptr()};
    1412                 :             :     }
    1413                 :             : 
    1414                 :             :     [[nodiscard]]
    1415                 :         268 :     mozilla::Maybe<AutoStructInfo> iface_struct() const {
    1416                 :             :         return detail::Pointer::nullable<InfoTag::STRUCT>(
    1417                 :         268 :             gi_interface_info_get_iface_struct(ptr()));
    1418                 :             :     }
    1419                 :             :     [[nodiscard]]
    1420                 :           2 :     mozilla::Maybe<AutoSignalInfo> signal(const char* name) const {
    1421                 :             :         return detail::Pointer::nullable<InfoTag::SIGNAL>(
    1422                 :           2 :             gi_interface_info_find_signal(ptr(), name));
    1423                 :             :     }
    1424                 :             :     [[nodiscard]]
    1425                 :          19 :     mozilla::Maybe<AutoVFuncInfo> vfunc(const char* name) const {
    1426                 :             :         return detail::Pointer::nullable<InfoTag::VFUNC>(
    1427                 :          19 :             gi_interface_info_find_vfunc(ptr(), name));
    1428                 :             :     }
    1429                 :             : };
    1430                 :             : 
    1431                 :             : template <class Wrapper>
    1432                 :             : class InfoOperations<Wrapper, InfoTag::OBJECT>
    1433                 :             :     : public RegisteredTypeInfoOperations<Wrapper> {
    1434                 :             :     DELETE_ALL_TYPECHECK_METHODS;
    1435                 :             : 
    1436                 :             :     [[nodiscard]]
    1437                 :       21561 :     GIObjectInfo* ptr() const {
    1438                 :       21561 :         return detail::Pointer::get_from(*static_cast<const Wrapper*>(this));
    1439                 :             :     }
    1440                 :             : 
    1441                 :             :  public:
    1442                 :             :     using FieldsIterator =
    1443                 :             :         InfoIterator<GIObjectInfo*, InfoTag::FIELD, gi_object_info_get_n_fields,
    1444                 :        4274 :                      gi_object_info_get_field>;
    1445                 :             :     [[nodiscard]]
    1446                 :        4274 :     FieldsIterator fields() const {
    1447                 :        4274 :         return FieldsIterator{ptr()};
    1448                 :             :     }
    1449                 :             : 
    1450                 :             :     using InterfacesIterator = InfoIterator<GIObjectInfo*, InfoTag::INTERFACE,
    1451                 :             :                                             gi_object_info_get_n_interfaces,
    1452                 :        3600 :                                             gi_object_info_get_interface>;
    1453                 :             :     [[nodiscard]]
    1454                 :        3600 :     InterfacesIterator interfaces() const {
    1455                 :        3600 :         return InterfacesIterator{ptr()};
    1456                 :             :     }
    1457                 :             : 
    1458                 :             :     using MethodsIterator =
    1459                 :             :         InfoIterator<GIObjectInfo*, InfoTag::FUNCTION,
    1460                 :         899 :                      gi_object_info_get_n_methods, gi_object_info_get_method>;
    1461                 :             :     [[nodiscard]]
    1462                 :         853 :     MethodsIterator methods() const {
    1463                 :         853 :         return MethodsIterator{ptr()};
    1464                 :             :     }
    1465                 :             :     [[nodiscard]]
    1466                 :         584 :     mozilla::Maybe<AutoFunctionInfo> method(const char* name) const {
    1467                 :             :         return detail::Pointer::nullable<InfoTag::FUNCTION>(
    1468                 :         584 :             gi_object_info_find_method(ptr(), name));
    1469                 :             :     }
    1470                 :             : 
    1471                 :             :     using PropertiesIterator = InfoIterator<GIObjectInfo*, InfoTag::PROPERTY,
    1472                 :             :                                             gi_object_info_get_n_properties,
    1473                 :        4112 :                                             gi_object_info_get_property>;
    1474                 :             :     [[nodiscard]]
    1475                 :        4066 :     PropertiesIterator properties() const {
    1476                 :        4066 :         return PropertiesIterator{ptr()};
    1477                 :             :     }
    1478                 :             : 
    1479                 :             :     [[nodiscard]]
    1480                 :         851 :     mozilla::Maybe<AutoStructInfo> class_struct() const {
    1481                 :             :         return detail::Pointer::nullable<InfoTag::STRUCT>(
    1482                 :         851 :             gi_object_info_get_class_struct(ptr()));
    1483                 :             :     }
    1484                 :             :     [[nodiscard]]
    1485                 :             :     mozilla::Maybe<std::pair<AutoFunctionInfo, AutoRegisteredTypeInfo>>
    1486                 :        4259 :     find_method_using_interfaces(const char* name) const {
    1487                 :        4259 :         GIBaseInfo* declarer_ptr = nullptr;
    1488                 :             :         GIFunctionInfo* method_ptr =
    1489                 :        4259 :             gi_object_info_find_method_using_interfaces(ptr(), name,
    1490                 :             :                                                         &declarer_ptr);
    1491                 :             : 
    1492         [ +  + ]:        4259 :         if (!method_ptr) {
    1493                 :        1975 :             g_assert(!declarer_ptr);
    1494                 :        1975 :             return {};
    1495                 :             :         }
    1496                 :             : 
    1497                 :        2284 :         AutoFunctionInfo method{
    1498                 :             :             detail::Pointer::to_owned<InfoTag::FUNCTION>(method_ptr)};
    1499                 :        2284 :         AutoRegisteredTypeInfo declarer{
    1500                 :             :             detail::Pointer::to_owned<InfoTag::REGISTERED_TYPE>(
    1501                 :        2284 :                 GI_REGISTERED_TYPE_INFO(declarer_ptr))};
    1502                 :        2284 :         g_assert(declarer.is_object() || declarer.is_interface());
    1503                 :        2284 :         return mozilla::Some(std::make_pair(method, declarer));
    1504                 :        2284 :     }
    1505                 :             :     [[nodiscard]]
    1506                 :             :     mozilla::Maybe<std::pair<AutoVFuncInfo, AutoRegisteredTypeInfo>>
    1507                 :          20 :     find_vfunc_using_interfaces(const char* name) const {
    1508                 :          20 :         GIBaseInfo* declarer_ptr = nullptr;
    1509                 :          20 :         GIVFuncInfo* vfunc_ptr = gi_object_info_find_vfunc_using_interfaces(
    1510                 :             :             ptr(), name, &declarer_ptr);
    1511                 :             : 
    1512         [ +  + ]:          20 :         if (!vfunc_ptr) {
    1513                 :          19 :             g_assert(!declarer_ptr);
    1514                 :          19 :             return {};
    1515                 :             :         }
    1516                 :             : 
    1517                 :           1 :         AutoVFuncInfo vfunc{
    1518                 :             :             detail::Pointer::to_owned<InfoTag::VFUNC>(vfunc_ptr)};
    1519                 :           1 :         AutoRegisteredTypeInfo declarer{
    1520                 :             :             detail::Pointer::to_owned<InfoTag::REGISTERED_TYPE>(
    1521                 :           1 :                 GI_REGISTERED_TYPE_INFO(declarer_ptr))};
    1522                 :           1 :         g_assert(declarer.is_object() || declarer.is_interface());
    1523                 :           1 :         return mozilla::Some(std::make_pair(vfunc, declarer));
    1524                 :           1 :     }
    1525                 :             :     [[nodiscard]]
    1526                 :          10 :     GIObjectInfoGetValueFunction get_value_function_pointer() const {
    1527                 :          10 :         return gi_object_info_get_get_value_function_pointer(ptr());
    1528                 :             :     }
    1529                 :             :     [[nodiscard]]
    1530                 :          36 :     mozilla::Maybe<AutoObjectInfo> parent() const {
    1531                 :             :         return detail::Pointer::nullable<InfoTag::OBJECT>(
    1532                 :          36 :             gi_object_info_get_parent(ptr()));
    1533                 :             :     }
    1534                 :             :     [[nodiscard]]
    1535                 :          10 :     GIObjectInfoRefFunction ref_function_pointer() const {
    1536                 :          10 :         return gi_object_info_get_ref_function_pointer(ptr());
    1537                 :             :     }
    1538                 :             :     [[nodiscard]]
    1539                 :          10 :     GIObjectInfoSetValueFunction set_value_function_pointer() const {
    1540                 :          10 :         return gi_object_info_get_set_value_function_pointer(ptr());
    1541                 :             :     }
    1542                 :             :     [[nodiscard]]
    1543                 :         331 :     mozilla::Maybe<AutoSignalInfo> signal(const char* name) const {
    1544                 :             :         return detail::Pointer::nullable<InfoTag::SIGNAL>(
    1545                 :         331 :             gi_object_info_find_signal(ptr(), name));
    1546                 :             :     }
    1547                 :             :     [[nodiscard]]
    1548                 :          10 :     GIObjectInfoUnrefFunction unref_function_pointer() const {
    1549                 :          10 :         return gi_object_info_get_unref_function_pointer(ptr());
    1550                 :             :     }
    1551                 :             :     [[nodiscard]]
    1552                 :         104 :     mozilla::Maybe<AutoVFuncInfo> vfunc(const char* name) const {
    1553                 :             :         return detail::Pointer::nullable<InfoTag::VFUNC>(
    1554                 :         104 :             gi_object_info_find_vfunc(ptr(), name));
    1555                 :             :     }
    1556                 :             : 
    1557                 :        2543 :     [[nodiscard]] operator const BaseInfo() const {
    1558                 :        2543 :         return detail::Pointer::to_unowned<InfoTag::BASE>(GI_BASE_INFO(ptr()));
    1559                 :             :     }
    1560                 :             : };
    1561                 :             : 
    1562                 :             : template <class Wrapper>
    1563                 :             : class InfoOperations<Wrapper, InfoTag::PROPERTY>
    1564                 :             :     : public BaseInfoOperations<Wrapper> {
    1565                 :             :     DELETE_ALL_TYPECHECK_METHODS;
    1566                 :             : 
    1567                 :             :     [[nodiscard]]
    1568                 :         642 :     GIPropertyInfo* ptr() const {
    1569                 :         642 :         return detail::Pointer::get_from(*static_cast<const Wrapper*>(this));
    1570                 :             :     }
    1571                 :             : 
    1572                 :             :     [[nodiscard]]
    1573                 :         123 :     GParamFlags flags() const {
    1574                 :         123 :         return gi_property_info_get_flags(ptr());
    1575                 :             :     }
    1576                 :             : 
    1577                 :             :  public:
    1578                 :             :     [[nodiscard]]
    1579                 :         239 :     mozilla::Maybe<AutoFunctionInfo> getter() const {
    1580                 :             :         return detail::Pointer::nullable<InfoTag::FUNCTION>(
    1581                 :         239 :             gi_property_info_get_getter(ptr()));
    1582                 :             :     }
    1583                 :             :     [[nodiscard]]
    1584                 :         190 :     mozilla::Maybe<AutoFunctionInfo> setter() const {
    1585                 :             :         return detail::Pointer::nullable<InfoTag::FUNCTION>(
    1586                 :         190 :             gi_property_info_get_setter(ptr()));
    1587                 :             :     }
    1588                 :             :     [[nodiscard]]
    1589                 :          90 :     AutoTypeInfo type_info() const {
    1590                 :             :         return detail::Pointer::to_owned<InfoTag::TYPE>(
    1591                 :          90 :             gi_property_info_get_type_info(ptr()));
    1592                 :             :     }
    1593                 :             : 
    1594                 :             :     // Methods not in GIRepository
    1595                 :             : 
    1596                 :             :     [[nodiscard]]
    1597                 :         123 :     bool has_deprecated_param_flag() const {
    1598                 :             :         // Note, different from is_deprecated(). It's possible that the property
    1599                 :             :         // has the deprecated GParamSpec flag, but is not marked deprecated in
    1600                 :             :         // the GIR doc comment.
    1601                 :         123 :         return flags() & G_PARAM_DEPRECATED;
    1602                 :             :     }
    1603                 :             : };
    1604                 :             : 
    1605                 :             : // Out-of-line definition to avoid chicken-and-egg loop between AutoFunctionInfo
    1606                 :             : // and AutoPropertyInfo
    1607                 :             : template <class Wrapper>
    1608                 :             : inline mozilla::Maybe<AutoPropertyInfo>
    1609                 :         246 : InfoOperations<Wrapper, InfoTag::FUNCTION>::property() const {
    1610                 :             :     return detail::Pointer::nullable<InfoTag::PROPERTY>(
    1611                 :         246 :         gi_function_info_get_property(ptr()));
    1612                 :             : }
    1613                 :             : 
    1614                 :             : template <class Wrapper>
    1615                 :             : class InfoOperations<Wrapper, InfoTag::VALUE>
    1616                 :             :     : public BaseInfoOperations<Wrapper> {
    1617                 :             :     DELETE_ALL_TYPECHECK_METHODS;
    1618                 :             : 
    1619                 :             :     [[nodiscard]]
    1620                 :       51517 :     GIValueInfo* ptr() const {
    1621                 :       51517 :         return detail::Pointer::get_from(*static_cast<const Wrapper*>(this));
    1622                 :             :     }
    1623                 :             : 
    1624                 :             :  public:
    1625                 :             :     [[nodiscard]]
    1626                 :       51517 :     int64_t value() const {
    1627                 :       51517 :         return gi_value_info_get_value(ptr());
    1628                 :             :     }
    1629                 :             : };
    1630                 :             : 
    1631                 :             : // In order to avoid having to create an OwnedInfo or UnownedInfo from a pointer
    1632                 :             : // anywhere except in these wrappers, we also wrap GIRepository.
    1633                 :             : // (ArgCache::HasTypeInfo is the one exception.)
    1634                 :             : class Repository {
    1635                 :             :     Gjs::AutoUnref<GIRepository> m_ptr = gi_repository_dup_default();
    1636                 :             : 
    1637                 :             :     // Helper object for iterating the introspection info objects of a
    1638                 :             :     // namespace. Unlike the other introspection info iterators, this requires
    1639                 :             :     // two parameters, the GIRepository* and the namespace string, so we need
    1640                 :             :     // this helper object to adapt InfoIterator.
    1641                 :             :     struct IterableNamespace {
    1642                 :             :         GIRepository* repo;
    1643                 :             :         const char* ns;
    1644                 :             : 
    1645                 :          54 :         static unsigned get_n_infos(const IterableNamespace obj) {
    1646                 :          54 :             return gi_repository_get_n_infos(obj.repo, obj.ns);
    1647                 :             :         }
    1648                 :             : 
    1649                 :       11251 :         static GIBaseInfo* get_info(const IterableNamespace obj, unsigned ix) {
    1650                 :       11251 :             return gi_repository_get_info(obj.repo, obj.ns, ix);
    1651                 :             :         }
    1652                 :             : 
    1653                 :       11278 :         bool operator==(const IterableNamespace& other) const {
    1654   [ +  -  +  - ]:       11278 :             return repo == other.repo && strcmp(ns, other.ns) == 0;
    1655                 :             :         }
    1656                 :             : 
    1657                 :       11278 :         bool operator!=(const IterableNamespace& other) const {
    1658                 :       11278 :             return !(*this == other);
    1659                 :             :         }
    1660                 :             :     };
    1661                 :             : 
    1662                 :             :  public:
    1663                 :             :     using Iterator = InfoIterator<IterableNamespace, InfoTag::BASE,
    1664                 :          54 :                                   &IterableNamespace::get_n_infos,
    1665                 :             :                                   &IterableNamespace::get_info>;
    1666                 :             :     [[nodiscard]]
    1667                 :          27 :     Iterator infos(const char* ns) const {
    1668                 :          27 :         return Iterator{{m_ptr, ns}};
    1669                 :             :     }
    1670                 :             : 
    1671                 :             :     [[nodiscard]]
    1672                 :         290 :     Gjs::AutoStrv enumerate_versions(const char* ns, size_t* n_versions) const {
    1673                 :         290 :         return gi_repository_enumerate_versions(m_ptr, ns, n_versions);
    1674                 :             :     }
    1675                 :             :     [[nodiscard]]
    1676                 :          71 :     mozilla::Maybe<AutoEnumInfo> find_by_error_domain(GQuark domain) const {
    1677                 :             :         return detail::Pointer::nullable<InfoTag::ENUM>(
    1678                 :          71 :             gi_repository_find_by_error_domain(m_ptr, domain));
    1679                 :             :     }
    1680                 :             :     template <InfoTag TAG = InfoTag::REGISTERED_TYPE>
    1681                 :             :     [[nodiscard]]
    1682                 :        3762 :     mozilla::Maybe<OwnedInfo<TAG>> find_by_gtype(GType gtype) const {
    1683                 :             :         return detail::Pointer::nullable<TAG>(detail::Pointer::cast<TAG>(
    1684                 :        3762 :             gi_repository_find_by_gtype(m_ptr, gtype)));
    1685                 :             :     }
    1686                 :             :     template <InfoTag TAG = InfoTag::BASE>
    1687                 :             :     [[nodiscard]]
    1688                 :       17539 :     mozilla::Maybe<OwnedInfo<TAG>> find_by_name(const char* ns,
    1689                 :             :                                                 const char* name) const {
    1690                 :             :         return detail::Pointer::nullable<TAG>(detail::Pointer::cast<TAG>(
    1691                 :       17539 :             gi_repository_find_by_name(m_ptr, ns, name)));
    1692                 :             :     }
    1693                 :             :     [[nodiscard]]
    1694                 :          15 :     const char* get_version(const char* ns) const {
    1695                 :          15 :         return gi_repository_get_version(m_ptr, ns);
    1696                 :             :     }
    1697                 :             :     [[nodiscard]]
    1698                 :           0 :     bool is_registered(const char* ns, const char* version) const {
    1699                 :           0 :         return gi_repository_is_registered(m_ptr, ns, version);
    1700                 :             :     }
    1701                 :             :     [[nodiscard]]
    1702                 :        2345 :     mozilla::Span<const InterfaceInfo> object_get_gtype_interfaces(
    1703                 :             :         GType gtype) const {
    1704                 :             :         InterfaceInfo* interfaces;
    1705                 :             :         size_t n_interfaces;
    1706                 :        2345 :         gi_repository_get_object_gtype_interfaces(
    1707                 :             :             m_ptr, gtype, &n_interfaces,
    1708                 :             :             reinterpret_cast<GIInterfaceInfo***>(&interfaces));
    1709                 :        2345 :         return {interfaces, n_interfaces};
    1710                 :             :     }
    1711                 :           0 :     void prepend_search_path(const char* path) {
    1712                 :           0 :         gi_repository_prepend_search_path(m_ptr, path);
    1713                 :           0 :     }
    1714                 :             :     [[nodiscard]]
    1715                 :         365 :     Gjs::GErrorResult<GITypelib*> require(
    1716                 :             :         const char* ns, const char* version,
    1717                 :             :         GIRepositoryLoadFlags flags = {}) const {
    1718                 :         365 :         GError* error = nullptr;
    1719                 :             :         GITypelib* typelib =
    1720                 :         365 :             gi_repository_require(m_ptr, ns, version, flags, &error);
    1721         [ +  + ]:         365 :         if (!typelib)
    1722                 :           3 :             return mozilla::Err(error);
    1723                 :         362 :         return typelib;
    1724                 :             :     }
    1725                 :             : };
    1726                 :             : 
    1727                 :             : ///// STACK-ALLOCATED INTROSPECTION INFO ///////////////////////////////////////
    1728                 :             : 
    1729                 :             : // Introspection info allocated directly on the stack. This is used only in a
    1730                 :             : // few cases, for performance reasons. In C, the stack-allocated struct is
    1731                 :             : // filled in by a function such as gi_arg_info_load_type_info().
    1732                 :             : // Needs to appear at the end, due to FIXME.
    1733                 :             : 
    1734                 :             : class StackArgInfo : public InfoOperations<StackArgInfo, InfoTag::ARG> {
    1735                 :             :     friend struct detail::Pointer;
    1736                 :             : 
    1737                 :             :     GIArgInfo m_info = {};
    1738                 :             : 
    1739                 :             :     [[nodiscard]]
    1740                 :             :     constexpr GIArgInfo* ptr() const {
    1741                 :             :         return detail::Pointer::get_from(*this);
    1742                 :             :     }
    1743                 :             : 
    1744                 :             :  public:
    1745                 :         429 :     constexpr StackArgInfo() {}
    1746                 :       29345 :     ~StackArgInfo() { gi_base_info_clear(&m_info); }
    1747                 :             :     // Moving is okay, we copy the contents of the GIArgInfo struct and reset
    1748                 :             :     // the existing one
    1749                 :           1 :     StackArgInfo(StackArgInfo&& other) : m_info(other.m_info) {
    1750                 :           1 :         gi_base_info_clear(&other.m_info);
    1751                 :           1 :     }
    1752                 :             :     StackArgInfo& operator=(StackArgInfo&& other) {
    1753                 :             :         m_info = other.m_info;
    1754                 :             :         gi_base_info_clear(&other.m_info);
    1755                 :             :         return *this;
    1756                 :             :     }
    1757                 :             :     // Prefer moving to copying
    1758                 :             :     StackArgInfo(const StackArgInfo&) = delete;
    1759                 :             :     StackArgInfo& operator=(const StackArgInfo&) = delete;
    1760                 :             : };
    1761                 :             : 
    1762                 :             : class StackTypeInfo : public InfoOperations<StackTypeInfo, InfoTag::TYPE> {
    1763                 :             :     friend struct detail::Pointer;
    1764                 :             : 
    1765                 :             :     GITypeInfo m_info = {};
    1766                 :             : 
    1767                 :             :     [[nodiscard]]
    1768                 :             :     constexpr GITypeInfo* ptr() const {
    1769                 :             :         return detail::Pointer::get_from(*this);
    1770                 :             :     }
    1771                 :             : 
    1772                 :             :  public:
    1773                 :        7054 :     constexpr StackTypeInfo() {}
    1774                 :       59452 :     ~StackTypeInfo() { gi_base_info_clear(&m_info); }
    1775                 :             :     // Moving is okay, we copy the contents of the GITypeInfo struct and reset
    1776                 :             :     // the existing one
    1777                 :             :     StackTypeInfo(StackTypeInfo&& other) : m_info(other.m_info) {
    1778                 :             :         gi_base_info_clear(&other.m_info);
    1779                 :             :     }
    1780                 :             :     StackTypeInfo& operator=(StackTypeInfo&& other) {
    1781                 :             :         m_info = other.m_info;
    1782                 :             :         gi_base_info_clear(&other.m_info);
    1783                 :             :         return *this;
    1784                 :             :     }
    1785                 :             :     // Prefer moving to copying
    1786                 :             :     StackTypeInfo(const StackTypeInfo&) = delete;
    1787                 :             :     StackTypeInfo& operator=(const StackTypeInfo&) = delete;
    1788                 :             : };
    1789                 :             : 
    1790                 :             : namespace detail {
    1791                 :       86887 : constexpr inline GIArgInfo* Pointer::get_from(const StackArgInfo& stack) {
    1792                 :       86887 :     return const_cast<GIArgInfo*>(&stack.m_info);
    1793                 :             : }
    1794                 :      237302 : constexpr inline GITypeInfo* Pointer::get_from(const StackTypeInfo& stack) {
    1795                 :      237302 :     return const_cast<GITypeInfo*>(&stack.m_info);
    1796                 :             : }
    1797                 :        6625 : inline void Pointer::to_stack(GITypeInfo* ptr, StackTypeInfo* stack) {
    1798                 :        6625 :     stack->m_info = std::move(*ptr);
    1799                 :             :     // Hacky: Reproduce gi_info_init() and mark the copied GITypeInfo as
    1800                 :             :     // stack-allocated. Unfortunately, GI_TYPE_TYPE_INFO makes this function
    1801                 :             :     // unable to be constexpr.
    1802                 :        6625 :     GIBaseInfoStack* stack_ptr = &stack->m_info.parent;
    1803                 :        6625 :     stack_ptr->parent_instance.g_class =
    1804                 :        6625 :         static_cast<GTypeClass*>(g_type_class_ref(GI_TYPE_TYPE_INFO));
    1805                 :        6625 :     stack_ptr->dummy0 = 0x7fff'ffff;
    1806                 :        6625 : }
    1807                 :             : }  // namespace detail
    1808                 :             : 
    1809                 :             : static_assert(sizeof(StackArgInfo) == sizeof(GIArgInfo),
    1810                 :             :               "StackArgInfo should be byte-compatible with GIArgInfo");
    1811                 :             : static_assert(sizeof(StackTypeInfo) == sizeof(GITypeInfo),
    1812                 :             :               "StackTypeInfo should be byte-compatible with GITypeInfo");
    1813                 :             : 
    1814                 :             : }  // namespace GI
    1815                 :             : 
    1816                 :             : // For use of GI::OwnedInfo<TAG> in GC hash maps
    1817                 :             : namespace JS {
    1818                 :             : template <GI::InfoTag TAG>
    1819                 :             : struct GCPolicy<GI::OwnedInfo<TAG>>
    1820                 :             :     : public IgnoreGCPolicy<GI::OwnedInfo<TAG>> {};
    1821                 :             : }  // namespace JS
        

Generated by: LCOV version 2.0-1