Branch data Line data Source code
1 : : /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
2 : : // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
3 : : // SPDX-FileCopyrightText: 2020 Marco Trevisan <marco.trevisan@canonical.com>
4 : :
5 : : #pragma once
6 : :
7 : : #include <config.h>
8 : :
9 : : #include <stdint.h>
10 : :
11 : : #include <limits>
12 : : #include <type_traits>
13 : :
14 : : #include <girepository.h>
15 : : #include <glib-object.h> // for GValue
16 : : #include <glib.h> // for gboolean
17 : :
18 : : namespace Gjs {
19 : :
20 : : template <typename T>
21 : : struct TypeWrapper {
22 : : constexpr TypeWrapper() : m_value(0) {}
23 : 1627 : explicit constexpr TypeWrapper(T v) : m_value(v) {}
24 : : constexpr operator T() const { return m_value; }
25 : 1623 : constexpr operator T() { return m_value; }
26 : :
27 : : private:
28 : : T m_value;
29 : : };
30 : :
31 : : template <typename T1, typename T2>
32 : : constexpr bool comparable_types() {
33 : : return std::is_arithmetic_v<T1> == std::is_arithmetic_v<T2> &&
34 : : std::is_integral_v<T1> == std::is_integral_v<T2> &&
35 : : std::is_signed_v<T1> == std::is_signed_v<T2>;
36 : : }
37 : :
38 : : template <typename T, typename Container>
39 : : constexpr bool type_fits() {
40 : : if constexpr (comparable_types<T, Container>()) {
41 : : return (std::numeric_limits<T>::max() <=
42 : : std::numeric_limits<Container>::max() &&
43 : : std::numeric_limits<T>::lowest() >=
44 : : std::numeric_limits<Container>::lowest());
45 : : }
46 : :
47 : : return false;
48 : : }
49 : :
50 : : // These tags are used to disambiguate types such as gboolean and GType which
51 : : // are in fact typedefs of other generic types. Using the tag instead of the
52 : : // type directly allows performing proper specialization. See also arg-inl.h.
53 : : namespace Tag {
54 : : struct GBoolean {};
55 : : struct GType {};
56 : : struct Long {};
57 : : struct UnsignedLong {};
58 : : struct Enum {};
59 : : struct UnsignedEnum {};
60 : : } // namespace Tag
61 : :
62 : : template <typename TAG>
63 : : struct MarshallingInfo {};
64 : :
65 : : template <>
66 : : struct MarshallingInfo<bool> {
67 : : using real_type = bool;
68 : : using containing_tag = bool;
69 : : using jsvalue_pack_type = int32_t;
70 : : static constexpr const char* name = "bool";
71 : : };
72 : :
73 : : template <>
74 : : struct MarshallingInfo<int8_t> {
75 : : using real_type = int8_t;
76 : : using containing_tag = int32_t;
77 : : using jsvalue_pack_type = int32_t;
78 : : static constexpr GITypeTag gi_tag = GI_TYPE_TAG_INT8;
79 : : static constexpr const char* name = "int8";
80 : : };
81 : :
82 : : template <>
83 : : struct MarshallingInfo<uint8_t> {
84 : : using real_type = uint8_t;
85 : : using containing_tag = uint32_t;
86 : : using jsvalue_pack_type = int32_t;
87 : : static constexpr GITypeTag gi_tag = GI_TYPE_TAG_UINT8;
88 : : static constexpr const char* name = "uint8";
89 : : };
90 : :
91 : : template <>
92 : : struct MarshallingInfo<int16_t> {
93 : : using real_type = int16_t;
94 : : using containing_tag = int32_t;
95 : : using jsvalue_pack_type = int32_t;
96 : : static constexpr GITypeTag gi_tag = GI_TYPE_TAG_INT16;
97 : : static constexpr const char* name = "int16";
98 : : };
99 : :
100 : : template <>
101 : : struct MarshallingInfo<uint16_t> {
102 : : using real_type = uint16_t;
103 : : using containing_tag = uint32_t;
104 : : using jsvalue_pack_type = int32_t;
105 : : static constexpr GITypeTag gi_tag = GI_TYPE_TAG_UINT16;
106 : : static constexpr const char* name = "uint16";
107 : : };
108 : :
109 : : template <>
110 : : struct MarshallingInfo<int32_t> {
111 : : using real_type = int32_t;
112 : : using containing_tag = int32_t;
113 : : using jsvalue_pack_type = int32_t;
114 : : static constexpr GITypeTag gi_tag = GI_TYPE_TAG_INT32;
115 : : static constexpr const char* name = "int32";
116 : : };
117 : :
118 : : template <>
119 : : struct MarshallingInfo<uint32_t> {
120 : : using real_type = uint32_t;
121 : : using containing_tag = uint32_t;
122 : : using jsvalue_pack_type = double;
123 : : static constexpr GITypeTag gi_tag = GI_TYPE_TAG_UINT32;
124 : : static constexpr const char* name = "uint32";
125 : : };
126 : :
127 : : template <>
128 : : struct MarshallingInfo<char32_t> {
129 : : using real_type = char32_t;
130 : : using containing_tag = char32_t;
131 : : using jsvalue_pack_type = double;
132 : : static constexpr const char* name = "char32";
133 : : };
134 : :
135 : : template <>
136 : : struct MarshallingInfo<int64_t> {
137 : : using real_type = int64_t;
138 : : using containing_tag = int64_t;
139 : : using jsvalue_pack_type = TypeWrapper<int64_t>;
140 : : static constexpr GITypeTag gi_tag = GI_TYPE_TAG_INT64;
141 : : static constexpr const char* name = "int64";
142 : : };
143 : :
144 : : template <>
145 : : struct MarshallingInfo<uint64_t> {
146 : : using real_type = uint64_t;
147 : : using containing_tag = uint64_t;
148 : : using jsvalue_pack_type = TypeWrapper<uint64_t>;
149 : : static constexpr GITypeTag gi_tag = GI_TYPE_TAG_UINT64;
150 : : static constexpr const char* name = "uint64";
151 : : };
152 : :
153 : : template <>
154 : : struct MarshallingInfo<float> {
155 : : using real_type = float;
156 : : using containing_tag = double;
157 : : using jsvalue_pack_type = double;
158 : : static constexpr GITypeTag gi_tag = GI_TYPE_TAG_FLOAT;
159 : : static constexpr const char* name = "float";
160 : : };
161 : :
162 : : template <>
163 : : struct MarshallingInfo<double> {
164 : : using real_type = double;
165 : : using containing_tag = double;
166 : : using jsvalue_pack_type = double;
167 : : static constexpr GITypeTag gi_tag = GI_TYPE_TAG_DOUBLE;
168 : : static constexpr const char* name = "double";
169 : : };
170 : :
171 : : template <typename T>
172 : : struct MarshallingInfo<T*> {
173 : : using real_type = T*;
174 : : static constexpr GITypeTag gi_tag = GI_TYPE_TAG_VOID;
175 : : static constexpr const char* name = "pointer";
176 : : };
177 : :
178 : : template <>
179 : : struct MarshallingInfo<Tag::GType> {
180 : : using real_type = GType;
181 : : using containing_tag = Tag::GType;
182 : : using jsvalue_pack_type = TypeWrapper<uint64_t>;
183 : : static constexpr GITypeTag gi_tag = GI_TYPE_TAG_GTYPE;
184 : : static constexpr const char* name = "GType";
185 : : };
186 : :
187 : : template <>
188 : : struct MarshallingInfo<Tag::GBoolean> {
189 : : using real_type = gboolean;
190 : : using containing_tag = Tag::GBoolean;
191 : : using jsvalue_pack_type = int32_t;
192 : : static constexpr GITypeTag gi_tag = GI_TYPE_TAG_BOOLEAN;
193 : : static constexpr const char* name = "boolean";
194 : : };
195 : :
196 : : template <>
197 : : struct MarshallingInfo<GValue*> {
198 : : using real_type = GValue*;
199 : : static constexpr const char* name = "GValue";
200 : : };
201 : :
202 : : template <>
203 : : struct MarshallingInfo<GValue> {
204 : : using real_type = GValue;
205 : : using containing_tag = GValue;
206 : : static constexpr const char* name = "flat GValue";
207 : : };
208 : :
209 : : template <>
210 : : struct MarshallingInfo<char*> {
211 : : using real_type = char*;
212 : : using containing_tag = char*;
213 : : using jsvalue_pack_type = char*;
214 : : static constexpr const char* name = "string";
215 : : };
216 : :
217 : : template <>
218 : : struct MarshallingInfo<const char*> {
219 : : using real_type = const char*;
220 : : static constexpr const char* name = "constant string";
221 : : };
222 : :
223 : : template <>
224 : : struct MarshallingInfo<Tag::Long> {
225 : : static constexpr bool is_32 =
226 : : type_fits<long, int32_t>(); // NOLINT(runtime/int)
227 : : using real_type = long; // NOLINT(runtime/int)
228 : : using containing_tag = std::conditional_t<is_32, int32_t, int64_t>;
229 : : using jsvalue_pack_type =
230 : : std::conditional_t<is_32, int32_t, TypeWrapper<int64_t>>;
231 : : static constexpr const char* name = "long";
232 : : };
233 : :
234 : : template <>
235 : : struct MarshallingInfo<Tag::UnsignedLong> {
236 : : static constexpr bool is_32 =
237 : : type_fits<unsigned long, uint32_t>(); // NOLINT(runtime/int)
238 : : using real_type = unsigned long; // NOLINT(runtime/int)
239 : : using containing_tag = std::conditional_t<is_32, uint32_t, uint64_t>;
240 : : using jsvalue_pack_type =
241 : : std::conditional_t<is_32, double, TypeWrapper<uint64_t>>;
242 : : static constexpr const char* name = "unsigned long";
243 : : };
244 : :
245 : : template <>
246 : : struct MarshallingInfo<Tag::Enum> {
247 : : using real_type = int;
248 : : using containing_tag = int32_t;
249 : : using jsvalue_pack_type = int32_t;
250 : : };
251 : :
252 : : template <>
253 : : struct MarshallingInfo<Tag::UnsignedEnum> {
254 : : using real_type = unsigned int;
255 : : using containing_tag = uint32_t;
256 : : using jsvalue_pack_type = double;
257 : : };
258 : :
259 : : template <>
260 : : struct MarshallingInfo<void> {
261 : : using real_type = void;
262 : : };
263 : :
264 : : namespace Tag {
265 : : template <typename TAG>
266 : : using RealT = typename MarshallingInfo<TAG>::real_type;
267 : :
268 : : // There are two ways you can unpack a C value from a JSValue.
269 : : // The containing type is the most appropriate C type that can contain the
270 : : // unpacked value. Implicit conversion may be performed and the value may need
271 : : // to be checked to make sure it is in range.
272 : : // The JSValue pack type, on the other hand, is the C type that is exactly
273 : : // equivalent to how JSValue stores the value, so no implicit conversion is
274 : : // performed unless the JSValue contains a pointer to a GC-thing, like BigInt.
275 : : template <typename TAG>
276 : : using JSValueContainingT = RealT<typename MarshallingInfo<TAG>::containing_tag>;
277 : :
278 : : template <typename TAG>
279 : : using JSValueContainingTag = typename MarshallingInfo<TAG>::containing_tag;
280 : :
281 : : template <typename TAG>
282 : : using JSValuePackT = typename MarshallingInfo<TAG>::jsvalue_pack_type;
283 : :
284 : : template <typename TAG>
285 : : using JSValuePackTag = std::conditional_t<
286 : : std::is_same_v<JSValuePackT<TAG>, TypeWrapper<int64_t>>, int64_t,
287 : : std::conditional_t<std::is_same_v<JSValuePackT<TAG>, TypeWrapper<uint64_t>>,
288 : : uint64_t, JSValuePackT<TAG>>>;
289 : : } // namespace Tag
290 : :
291 : : template <typename TAG>
292 : 26 : constexpr inline const char* static_type_name() {
293 : 26 : return MarshallingInfo<TAG>::name;
294 : : }
295 : :
296 : : } // namespace Gjs
|