arg-inl.h 6.45 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
/*
 * SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
 *
 * Copyright (c) 2020 Marco Trevisan <marco.trevisan@canonical.com>
 */

#pragma once

#include <stdint.h>

12
#include <cstddef>  // for nullptr_t
13 14 15 16 17 18 19 20
#include <type_traits>

#include <girepository.h>
#include <glib-object.h>  // for GType
#include <glib.h>         // for gboolean

#include "gjs/macros.h"

21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
// GIArgument accessor templates
//
// These are intended to make access to the GIArgument union more type-safe and
// reduce bugs that occur from assigning to one member and reading from another.
// (These bugs often work fine on one processor architecture but crash on
// another.)
//
// gjs_arg_member<T>(GIArgument*) - returns a reference to the appropriate union
//   member that would hold the type T. Rarely used, unless as a pointer to a
//   return location.
// gjs_arg_get<T>(GIArgument*) - returns the value of type T from the
//   appropriate union member.
// gjs_arg_set(GIArgument*, T) - sets the appropriate union member for type T.
// gjs_arg_unset<T>(GIArgument*) - sets the appropriate zero value in the
//   appropriate union member for type T.

37
template <typename T>
38 39
GJS_USE inline decltype(auto) gjs_arg_member(GIArgument* arg,
                                             T GIArgument::*member) {
40 41 42 43 44 45 46
    return (arg->*member);
}

/* The tag is needed to disambiguate types such as gboolean and GType
 * which are in fact typedef's of other generic types.
 * Setting a tag for a type allows to perform proper specialization. */
template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
47
GJS_USE inline decltype(auto) gjs_arg_member(GIArgument* arg) {
48 49
    static_assert(!std::is_arithmetic<T>(), "Missing declaration for type");

50 51 52
    using NonconstPtrT =
        std::add_pointer_t<std::remove_const_t<std::remove_pointer_t<T>>>;
    return reinterpret_cast<NonconstPtrT&>(
53
        gjs_arg_member(arg, &GIArgument::v_pointer));
54 55 56
}

template <>
57 58
GJS_USE inline decltype(auto) gjs_arg_member<bool>(GIArgument* arg) {
    return gjs_arg_member(arg, &GIArgument::v_boolean);
59 60 61
}

template <>
62 63 64
GJS_USE inline decltype(auto) gjs_arg_member<gboolean, GI_TYPE_TAG_BOOLEAN>(
    GIArgument* arg) {
    return gjs_arg_member(arg, &GIArgument::v_boolean);
65 66 67
}

template <>
68 69
GJS_USE inline decltype(auto) gjs_arg_member<int8_t>(GIArgument* arg) {
    return gjs_arg_member(arg, &GIArgument::v_int8);
70 71 72
}

template <>
73 74
GJS_USE inline decltype(auto) gjs_arg_member<uint8_t>(GIArgument* arg) {
    return gjs_arg_member(arg, &GIArgument::v_uint8);
75 76 77
}

template <>
78 79
GJS_USE inline decltype(auto) gjs_arg_member<int16_t>(GIArgument* arg) {
    return gjs_arg_member(arg, &GIArgument::v_int16);
80 81 82
}

template <>
83 84
GJS_USE inline decltype(auto) gjs_arg_member<uint16_t>(GIArgument* arg) {
    return gjs_arg_member(arg, &GIArgument::v_uint16);
85 86 87
}

template <>
88 89
GJS_USE inline decltype(auto) gjs_arg_member<int32_t>(GIArgument* arg) {
    return gjs_arg_member(arg, &GIArgument::v_int32);
90 91 92
}

template <>
93 94
GJS_USE inline decltype(auto) gjs_arg_member<uint32_t>(GIArgument* arg) {
    return gjs_arg_member(arg, &GIArgument::v_uint32);
95 96 97
}

template <>
98 99
GJS_USE inline decltype(auto) gjs_arg_member<int64_t>(GIArgument* arg) {
    return gjs_arg_member(arg, &GIArgument::v_int64);
100 101 102
}

template <>
103 104
GJS_USE inline decltype(auto) gjs_arg_member<uint64_t>(GIArgument* arg) {
    return gjs_arg_member(arg, &GIArgument::v_uint64);
105 106
}

107 108
// gunichar is stored in v_uint32
template <>
109 110
GJS_USE inline decltype(auto) gjs_arg_member<char32_t>(GIArgument* arg) {
    return gjs_arg_member(arg, &GIArgument::v_uint32);
111 112
}

113
template <>
114
GJS_USE inline decltype(auto) gjs_arg_member<GType, GI_TYPE_TAG_GTYPE>(
115
    GIArgument* arg) {
116
    return gjs_arg_member(arg, &GIArgument::v_size);
117 118 119
}

template <>
120 121
GJS_USE inline decltype(auto) gjs_arg_member<float>(GIArgument* arg) {
    return gjs_arg_member(arg, &GIArgument::v_float);
122 123 124
}

template <>
125 126
GJS_USE inline decltype(auto) gjs_arg_member<double>(GIArgument* arg) {
    return gjs_arg_member(arg, &GIArgument::v_double);
127 128 129
}

template <>
130 131
GJS_USE inline decltype(auto) gjs_arg_member<char*>(GIArgument* arg) {
    return gjs_arg_member(arg, &GIArgument::v_string);
132 133 134
}

template <>
135 136
GJS_USE inline decltype(auto) gjs_arg_member<void*>(GIArgument* arg) {
    return gjs_arg_member(arg, &GIArgument::v_pointer);
137
}
138

139
template <>
140 141
GJS_USE inline decltype(auto) gjs_arg_member<std::nullptr_t>(GIArgument* arg) {
    return gjs_arg_member(arg, &GIArgument::v_pointer);
142 143
}

144 145 146 147 148 149
template <>
GJS_USE inline decltype(auto) gjs_arg_member<int, GI_TYPE_TAG_INTERFACE>(
    GIArgument* arg) {
    return gjs_arg_member(arg, &GIArgument::v_int);
}

150
template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
151 152
inline std::enable_if_t<!std::is_pointer_v<T>> gjs_arg_set(GIArgument* arg,
                                                           T v) {
153
    gjs_arg_member<T, TAG>(arg) = v;
154 155
}

156
template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
157 158 159 160 161
inline std::enable_if_t<std::is_pointer_v<T>> gjs_arg_set(GIArgument* arg,
                                                          T v) {
    using NonconstPtrT =
        std::add_pointer_t<std::remove_const_t<std::remove_pointer_t<T>>>;
    gjs_arg_member<NonconstPtrT, TAG>(arg) = const_cast<NonconstPtrT>(v);
162
}
163 164 165 166

// Store function pointers as void*. It is a requirement of GLib that your
// compiler can do this
template <typename ReturnT, typename... Args>
167 168
inline void gjs_arg_set(GIArgument* arg, ReturnT (*v)(Args...)) {
    gjs_arg_member<void*>(arg) = reinterpret_cast<void*>(v);
169 170
}

171
template <>
172 173
inline void gjs_arg_set<bool>(GIArgument* arg, bool v) {
    gjs_arg_member<bool>(arg) = !!v;
174 175 176
}

template <>
177 178 179
inline void gjs_arg_set<gboolean, GI_TYPE_TAG_BOOLEAN>(GIArgument* arg,
                                                       gboolean v) {
    gjs_arg_member<bool>(arg) = !!v;
180 181
}

182
template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
183 184
GJS_USE inline T gjs_arg_get(GIArgument* arg) {
    return gjs_arg_member<T, TAG>(arg);
185
}
186 187

template <>
188 189
GJS_USE inline bool gjs_arg_get<bool>(GIArgument* arg) {
    return !!gjs_arg_member<bool>(arg);
190 191 192
}

template <>
193
GJS_USE inline gboolean gjs_arg_get<gboolean, GI_TYPE_TAG_BOOLEAN>(
194
    GIArgument* arg) {
195
    return !!gjs_arg_member<bool>(arg);
196
}
197 198

template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
199
inline std::enable_if_t<!std::is_pointer_v<T>> gjs_arg_unset(GIArgument* arg) {
200
    gjs_arg_set<T, TAG>(arg, static_cast<T>(0));
201 202 203
}

template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
204
inline std::enable_if_t<std::is_pointer_v<T>> gjs_arg_unset(GIArgument* arg) {
205
    gjs_arg_set<T, TAG>(arg, nullptr);
206
}