1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 * GObject introspection: Union implementation
3 *
4 * Copyright (C) 2005 Matthias Clasen
5 * Copyright (C) 2008,2009 Red Hat, Inc.
6 *
7 * SPDX-License-Identifier: LGPL-2.1-or-later
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
23 */
24
25 #include "config.h"
26
27 #include <glib.h>
28
29 #include <girepository/girepository.h>
30 #include "gibaseinfo-private.h"
31 #include "girepository-private.h"
32 #include "gitypelib-internal.h"
33 #include "giunioninfo.h"
34
35 /**
36 * GIUnionInfo:
37 *
38 * `GIUnionInfo` represents a union type.
39 *
40 * A union has methods and fields. Unions can optionally have a
41 * discriminator, which is a field deciding what type of real union
42 * fields is valid for specified instance.
43 *
44 * Since: 2.80
45 */
46
47 /**
48 * gi_union_info_get_n_fields:
49 * @info: a #GIUnionInfo
50 *
51 * Obtain the number of fields this union has.
52 *
53 * Returns: number of fields
54 * Since: 2.80
55 */
56 guint
57 gi_union_info_get_n_fields (GIUnionInfo *info)
58 {
59 GIRealInfo *rinfo = (GIRealInfo *)info;
60 UnionBlob *blob = (UnionBlob *)&rinfo->typelib->data[rinfo->offset];
61
62 return blob->n_fields;
63 }
64
65 /**
66 * gi_union_info_get_field:
67 * @info: a #GIUnionInfo
68 * @n: a field index
69 *
70 * Obtain the type information for the field with the specified index.
71 *
72 * Returns: (transfer full): the [type@GIRepository.FieldInfo], free it with
73 * [method@GIRepository.BaseInfo.unref] when done.
74 * Since: 2.80
75 */
76 GIFieldInfo *
77 gi_union_info_get_field (GIUnionInfo *info,
78 guint n)
79 {
80 GIRealInfo *rinfo = (GIRealInfo *)info;
81 Header *header = (Header *)rinfo->typelib->data;
82
83 return (GIFieldInfo *) gi_info_new (GI_INFO_TYPE_FIELD, (GIBaseInfo*)info, rinfo->typelib,
84 rinfo->offset + header->union_blob_size +
85 n * header->field_blob_size);
86 }
87
88 /**
89 * gi_union_info_get_n_methods:
90 * @info: a #GIUnionInfo
91 *
92 * Obtain the number of methods this union has.
93 *
94 * Returns: number of methods
95 * Since: 2.80
96 */
97 guint
98 gi_union_info_get_n_methods (GIUnionInfo *info)
99 {
100 GIRealInfo *rinfo = (GIRealInfo *)info;
101 UnionBlob *blob = (UnionBlob *)&rinfo->typelib->data[rinfo->offset];
102
103 return blob->n_functions;
104 }
105
106 /**
107 * gi_union_info_get_method:
108 * @info: a #GIUnionInfo
109 * @n: a method index
110 *
111 * Obtain the type information for the method with the specified index.
112 *
113 * Returns: (transfer full): the [type@GIRepository.FunctionInfo], free it
114 * with [method@GIRepository.BaseInfo.unref] when done.
115 * Since: 2.80
116 */
117 GIFunctionInfo *
118 gi_union_info_get_method (GIUnionInfo *info,
119 guint n)
120 {
121 GIRealInfo *rinfo = (GIRealInfo *)info;
122 UnionBlob *blob = (UnionBlob *)&rinfo->typelib->data[rinfo->offset];
123 Header *header = (Header *)rinfo->typelib->data;
124 gint offset;
125
126 offset = rinfo->offset + header->union_blob_size
127 + blob->n_fields * header->field_blob_size
128 + n * header->function_blob_size;
129 return (GIFunctionInfo *) gi_info_new (GI_INFO_TYPE_FUNCTION, (GIBaseInfo*)info,
130 rinfo->typelib, offset);
131 }
132
133 /**
134 * gi_union_info_is_discriminated:
135 * @info: a #GIUnionInfo
136 *
137 * Return `TRUE` if this union contains a discriminator field.
138 *
139 * Returns: `TRUE` if this is a discriminated union, `FALSE` otherwise
140 * Since: 2.80
141 */
142 gboolean
143 gi_union_info_is_discriminated (GIUnionInfo *info)
144 {
145 GIRealInfo *rinfo = (GIRealInfo *)info;
146 UnionBlob *blob = (UnionBlob *)&rinfo->typelib->data[rinfo->offset];
147
148 return blob->discriminated;
149 }
150
151 /**
152 * gi_union_info_get_discriminator_offset:
153 * @info: a #GIUnionInfo
154 *
155 * Returns the offset of the discriminator field in the structure.
156 *
157 * Returns: offset, in bytes, of the discriminator
158 * Since: 2.80
159 */
160 guint
161 gi_union_info_get_discriminator_offset (GIUnionInfo *info)
162 {
163 GIRealInfo *rinfo = (GIRealInfo *)info;
164 UnionBlob *blob = (UnionBlob *)&rinfo->typelib->data[rinfo->offset];
165
166 return blob->discriminator_offset;
167 }
168
169 /**
170 * gi_union_info_get_discriminator_type:
171 * @info: a #GIUnionInfo
172 *
173 * Obtain the type information of the union discriminator.
174 *
175 * Returns: (transfer full): the [type@GIRepository.TypeInfo], free it with
176 * [method@GIRepository.BaseInfo.unref] when done.
177 * Since: 2.80
178 */
179 GITypeInfo *
180 gi_union_info_get_discriminator_type (GIUnionInfo *info)
181 {
182 GIRealInfo *rinfo = (GIRealInfo *)info;
183
184 return gi_type_info_new ((GIBaseInfo*)info, rinfo->typelib, rinfo->offset + 24);
185 }
186
187 /**
188 * gi_union_info_get_discriminator:
189 * @info: a #GIUnionInfo
190 * @n: a union field index
191 *
192 * Obtain the discriminator value assigned for n-th union field, i.e. the n-th
193 * union field is the active one if the discriminator contains this
194 * constant.
195 *
196 * If the union is not discriminated, `NULL` is returned.
197 *
198 * Returns: (transfer full) (nullable): The [type@GIRepository.ConstantInfo], or
199 * `NULL` if the union is not discriminated. Free it with
200 * [method@GIRepository.BaseInfo.unref] when done.
201 * Since: 2.80
202 */
203 GIConstantInfo *
204 gi_union_info_get_discriminator (GIUnionInfo *info,
205 guint n)
206 {
207 GIRealInfo *rinfo = (GIRealInfo *)info;
208 UnionBlob *blob = (UnionBlob *)&rinfo->typelib->data[rinfo->offset];
209
210 if (blob->discriminated)
211 {
212 Header *header = (Header *)rinfo->typelib->data;
213 gint offset;
214
215 offset = rinfo->offset + header->union_blob_size
216 + blob->n_fields * header->field_blob_size
217 + blob->n_functions * header->function_blob_size
218 + n * header->constant_blob_size;
219
220 return (GIConstantInfo *) gi_info_new (GI_INFO_TYPE_CONSTANT, (GIBaseInfo*)info,
221 rinfo->typelib, offset);
222 }
223
224 return NULL;
225 }
226
227 /**
228 * gi_union_info_find_method:
229 * @info: a #GIUnionInfo
230 * @name: a method name
231 *
232 * Obtain the type information for the method named @name.
233 *
234 * Returns: (transfer full) (nullable): The [type@GIRepository.FunctionInfo], or
235 * `NULL` if none was found. Free it with [method@GIRepository.BaseInfo.unref]
236 * when done.
237 * Since: 2.80
238 */
239 GIFunctionInfo *
240 gi_union_info_find_method (GIUnionInfo *info,
241 const gchar *name)
242 {
243 gint offset;
244 GIRealInfo *rinfo = (GIRealInfo *)info;
245 Header *header = (Header *)rinfo->typelib->data;
246 UnionBlob *blob = (UnionBlob *)&rinfo->typelib->data[rinfo->offset];
247
248 offset = rinfo->offset + header->union_blob_size
249 + blob->n_fields * header->field_blob_size;
250
251 return gi_base_info_find_method ((GIBaseInfo*)info, offset, blob->n_functions, name);
252 }
253
254 /**
255 * gi_union_info_get_size:
256 * @info: a #GIUnionInfo
257 *
258 * Obtain the total size of the union.
259 *
260 * Returns: size of the union, in bytes
261 * Since: 2.80
262 */
263 gsize
264 gi_union_info_get_size (GIUnionInfo *info)
265 {
266 GIRealInfo *rinfo = (GIRealInfo *)info;
267 UnionBlob *blob = (UnionBlob *)&rinfo->typelib->data[rinfo->offset];
268
269 return blob->size;
270 }
271
272 /**
273 * gi_union_info_get_alignment:
274 * @info: a #GIUnionInfo
275 *
276 * Obtain the required alignment of the union.
277 *
278 * Returns: required alignment, in bytes
279 * Since: 2.80
280 */
281 gsize
282 gi_union_info_get_alignment (GIUnionInfo *info)
283 {
284 GIRealInfo *rinfo = (GIRealInfo *)info;
285 UnionBlob *blob = (UnionBlob *)&rinfo->typelib->data[rinfo->offset];
286
287 return blob->alignment;
288 }
289
290 /**
291 * gi_union_info_get_copy_function_name:
292 * @info: a union information blob
293 *
294 * Retrieves the name of the copy function for @info, if any is set.
295 *
296 * Returns: (transfer none) (nullable): the name of the copy function, or `NULL`
297 * if none is set
298 * Since: 2.80
299 */
300 const char *
301 gi_union_info_get_copy_function_name (GIUnionInfo *info)
302 {
303 GIRealInfo *rinfo = (GIRealInfo *)info;
304 UnionBlob *blob;
305
306 g_return_val_if_fail (info != NULL, NULL);
307 g_return_val_if_fail (GI_IS_UNION_INFO (info), NULL);
308
309 blob = (UnionBlob *)&rinfo->typelib->data[rinfo->offset];
310
311 if (blob->copy_func)
312 return gi_typelib_get_string (rinfo->typelib, blob->copy_func);
313
314 return NULL;
315 }
316
317 /**
318 * gi_union_info_get_free_function_name:
319 * @info: a union information blob
320 *
321 * Retrieves the name of the free function for @info, if any is set.
322 *
323 * Returns: (transfer none) (nullable): the name of the free function, or `NULL`
324 * if none is set
325 * Since: 2.80
326 */
327 const char *
328 gi_union_info_get_free_function_name (GIUnionInfo *info)
329 {
330 GIRealInfo *rinfo = (GIRealInfo *)info;
331 UnionBlob *blob;
332
333 g_return_val_if_fail (info != NULL, NULL);
334 g_return_val_if_fail (GI_IS_UNION_INFO (info), NULL);
335
336 blob = (UnionBlob *)&rinfo->typelib->data[rinfo->offset];
337
338 if (blob->free_func)
339 return gi_typelib_get_string (rinfo->typelib, blob->free_func);
340
341 return NULL;
342 }
343
344 void
345 gi_union_info_class_init (gpointer g_class,
346 gpointer class_data)
347 {
348 GIBaseInfoClass *info_class = g_class;
349
350 info_class->info_type = GI_INFO_TYPE_UNION;
351 }