pygi-cache.c 42.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/* -*- Mode: C; c-basic-offset: 4 -*-
 * vim: tabstop=4 shiftwidth=4 expandtab
 *
 * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
 * USA
 */
21 22

#include "pygi-info.h"
23
#include "pygi-cache.h"
24 25
#include "pygi-marshal-to-py.h"
#include "pygi-marshal-from-py.h"
26
#include "pygi-marshal-cleanup.h"
27
#include "pygi-type.h"
28
#include <girepository.h>
29

30 31 32 33
PyGIArgCache * _arg_cache_new (GITypeInfo *type_info,
                               PyGICallableCache *callable_cache,
                               GIArgInfo *arg_info,
                               GITransfer transfer,
34
                               PyGIDirection direction,
35 36 37 38 39 40 41
                               gssize c_arg_index,
                               gssize py_arg_index);

PyGIArgCache * _arg_cache_new_for_interface (GIInterfaceInfo *iface_info,
                                             PyGICallableCache *callable_cache,
                                             GIArgInfo *arg_info,
                                             GITransfer transfer,
42
                                             PyGIDirection direction,
43 44
                                             gssize c_arg_index,
                                             gssize py_arg_index);
45

46
/* cleanup */
Martin Pitt's avatar
Martin Pitt committed
47
static void
48
_pygi_arg_cache_free (PyGIArgCache *cache)
John (J5) Palmieri's avatar
John (J5) Palmieri committed
49 50 51 52
{
    if (cache == NULL)
        return;

53
    if (cache->type_info != NULL)
54
        g_base_info_unref ( (GIBaseInfo *)cache->type_info);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
55
    if (cache->destroy_notify)
56
        cache->destroy_notify (cache);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
57
    else
58
        g_slice_free (PyGIArgCache, cache);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
59 60 61
}

static void
62
_interface_cache_free_func (PyGIInterfaceCache *cache)
63 64
{
    if (cache != NULL) {
65
        Py_XDECREF (cache->py_type);
66
        if (cache->type_name != NULL)
67
            g_free (cache->type_name);
68
        if (cache->interface_info != NULL)
69 70
            g_base_info_unref ( (GIBaseInfo *)cache->interface_info);
        g_slice_free (PyGIInterfaceCache, cache);
71 72 73
    }
}

John (J5) Palmieri's avatar
John (J5) Palmieri committed
74
static void
75
_hash_cache_free_func (PyGIHashCache *cache)
76
{
John (J5) Palmieri's avatar
John (J5) Palmieri committed
77
    if (cache != NULL) {
78 79 80
        _pygi_arg_cache_free (cache->key_cache);
        _pygi_arg_cache_free (cache->value_cache);
        g_slice_free (PyGIHashCache, cache);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
81
    }
82 83
}

84
static void
85
_sequence_cache_free_func (PyGISequenceCache *cache)
86
{
John (J5) Palmieri's avatar
John (J5) Palmieri committed
87
    if (cache != NULL) {
88 89
        _pygi_arg_cache_free (cache->item_cache);
        g_slice_free (PyGISequenceCache, cache);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
90
    }
91 92
}

93
static void
94
_callback_cache_free_func (PyGICallbackCache *cache)
95
{
96 97
    if (cache != NULL) {
        if (cache->interface_info != NULL)
98
            g_base_info_unref ( (GIBaseInfo *)cache->interface_info);
99

100
        g_slice_free (PyGICallbackCache, cache);
101
    }
102 103 104
}

void
105
_pygi_callable_cache_free (PyGICallableCache *cache)
106
{
107 108 109
    if (cache == NULL)
        return;

110
    g_slist_free (cache->to_py_args);
111 112
    g_slist_free (cache->arg_name_list);
    g_hash_table_destroy (cache->arg_name_hash);
113
    g_ptr_array_unref (cache->args_cache);
114

115
    if (cache->return_cache != NULL)
116
        _pygi_arg_cache_free (cache->return_cache);
117

118
    g_slice_free (PyGICallableCache, cache);
119 120 121 122
}

/* cache generation */

123 124
static PyGIInterfaceCache *
_interface_cache_new (GIInterfaceInfo *iface_info)
125 126
{
    PyGIInterfaceCache *ic;
John (J5) Palmieri's avatar
John (J5) Palmieri committed
127

128 129
    ic = g_slice_new0 (PyGIInterfaceCache);
    ( (PyGIArgCache *)ic)->destroy_notify = (GDestroyNotify)_interface_cache_free_func;
130
    ic->g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *)iface_info);
131
    ic->py_type = _pygi_type_import_by_gi_info ( (GIBaseInfo *) iface_info);
132 133 134 135

    if (ic->py_type == NULL)
        return NULL;

136
    ic->type_name = _pygi_g_base_info_get_fullname (iface_info);
137 138 139
    return ic;
}

140 141 142 143 144
static PyGISequenceCache *
_sequence_cache_new (GITypeInfo *type_info,
                     GIDirection direction,
                     GITransfer transfer,
                     gssize child_offset)
145 146 147
{
    PyGISequenceCache *sc;
    GITypeInfo *item_type_info;
148
    GITransfer item_transfer;
149

150 151
    sc = g_slice_new0 (PyGISequenceCache);
    ( (PyGIArgCache *)sc)->destroy_notify = (GDestroyNotify)_sequence_cache_free_func;
152

153
    sc->is_zero_terminated = g_type_info_is_zero_terminated (type_info);
154 155 156 157
    sc->fixed_size = g_type_info_get_array_fixed_size (type_info);
    sc->len_arg_index = g_type_info_get_array_length (type_info);
    if (sc->len_arg_index >= 0)
        sc->len_arg_index += child_offset;
158

159 160
    item_type_info = g_type_info_get_param_type (type_info, 0);

161 162
    item_transfer =
        transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
163

164 165 166 167 168 169
    sc->item_cache = _arg_cache_new (item_type_info,
                                     NULL,
                                     NULL,
                                     item_transfer,
                                     direction,
                                     0, 0);
170

171
    if (sc->item_cache == NULL) {
172
        _pygi_arg_cache_free ( (PyGIArgCache *)sc);
173 174
        return NULL;
    }
John (J5) Palmieri's avatar
John (J5) Palmieri committed
175

176 177
    sc->item_size = _pygi_g_type_info_size (item_type_info);
    g_base_info_unref ( (GIBaseInfo *)item_type_info);
178

179
    return sc;
180
}
181 182 183 184
static PyGIHashCache *
_hash_cache_new (GITypeInfo *type_info,
                 GIDirection direction,
                 GITransfer transfer)
John (J5) Palmieri's avatar
John (J5) Palmieri committed
185 186 187 188
{
    PyGIHashCache *hc;
    GITypeInfo *key_type_info;
    GITypeInfo *value_type_info;
189
    GITransfer item_transfer;
John (J5) Palmieri's avatar
John (J5) Palmieri committed
190

191 192
    hc = g_slice_new0 (PyGIHashCache);
    ( (PyGIArgCache *)hc)->destroy_notify = (GDestroyNotify)_hash_cache_free_func;
John (J5) Palmieri's avatar
John (J5) Palmieri committed
193 194 195
    key_type_info = g_type_info_get_param_type (type_info, 0);
    value_type_info = g_type_info_get_param_type (type_info, 1);

196 197
    item_transfer =
        transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
198

199 200 201 202 203 204
    hc->key_cache = _arg_cache_new (key_type_info,
                                    NULL,
                                    NULL,
                                    item_transfer,
                                    direction,
                                    0, 0);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
205 206

    if (hc->key_cache == NULL) {
207
        _pygi_arg_cache_free ( (PyGIArgCache *)hc);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
208 209 210
        return NULL;
    }

211 212 213 214 215 216
    hc->value_cache = _arg_cache_new (value_type_info,
                                      NULL,
                                      NULL,
                                      item_transfer,
                                      direction,
                                      0, 0);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
217 218

    if (hc->value_cache == NULL) {
219
        _pygi_arg_cache_free ( (PyGIArgCache *)hc);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
220 221 222 223 224 225 226 227
        return NULL;
    }

    g_base_info_unref( (GIBaseInfo *)key_type_info);
    g_base_info_unref( (GIBaseInfo *)value_type_info);

    return hc;
}
228

229 230 231 232
static PyGICallbackCache *
_callback_cache_new (GIArgInfo *arg_info,
                     GIInterfaceInfo *iface_info,
                     gssize child_offset)
John (J5) Palmieri's avatar
John (J5) Palmieri committed
233 234 235
{
   PyGICallbackCache *cc;

236
   cc = g_slice_new0 (PyGICallbackCache);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
237 238
   ( (PyGIArgCache *)cc)->destroy_notify = (GDestroyNotify)_callback_cache_free_func;

239
   cc->user_data_index = g_arg_info_get_closure (arg_info);
240
   if (cc->user_data_index != -1)
241
       cc->user_data_index += child_offset;
242
   cc->destroy_notify_index = g_arg_info_get_destroy (arg_info);
243
   if (cc->destroy_notify_index != -1)
244
       cc->destroy_notify_index += child_offset;
245
   cc->scope = g_arg_info_get_scope (arg_info);
246 247
   g_base_info_ref( (GIBaseInfo *)iface_info);
   cc->interface_info = iface_info;
John (J5) Palmieri's avatar
John (J5) Palmieri committed
248 249 250
   return cc;
}

251 252
static PyGIArgCache *
_arg_cache_alloc (void)
253
{
254
    return g_slice_new0 (PyGIArgCache);
255
}
256

257 258 259 260 261 262
static void
_arg_cache_from_py_basic_type_setup (PyGIArgCache *arg_cache)
{
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_basic_type_cache_adapter;
}

263 264 265
static void
_arg_cache_to_py_basic_type_setup (PyGIArgCache *arg_cache)
{
266
    arg_cache->to_py_marshaller = _pygi_marshal_to_py_basic_type_cache_adapter;
267 268
}

269
static void
270
_arg_cache_from_py_void_setup (PyGIArgCache *arg_cache)
271
{
272
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_void;
273
}
274

275
static void
276
_arg_cache_to_py_void_setup (PyGIArgCache *arg_cache)
277
{
278
    arg_cache->to_py_marshaller = _pygi_marshal_to_py_void;
279 280
}

281
static void
282 283
_arg_cache_from_py_utf8_setup (PyGIArgCache *arg_cache,
                               GITransfer transfer)
284
{
285
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_basic_type_cache_adapter;
286
    arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_utf8;
287
}
288

289
static void
290 291
_arg_cache_to_py_utf8_setup (PyGIArgCache *arg_cache,
                               GITransfer transfer)
292
{
293
    arg_cache->to_py_marshaller = _pygi_marshal_to_py_basic_type_cache_adapter;
294
    arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_utf8;
295 296
}

297 298
static PyGIArgCache*
_arg_cache_array_len_arg_setup (PyGIArgCache *arg_cache,
299
                                PyGICallableCache *callable_cache,
300
                                PyGIDirection direction,
301 302
                                gssize arg_index,
                                gssize *py_arg_index)
303
{
John (J5) Palmieri's avatar
John (J5) Palmieri committed
304
    PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
305
    if (seq_cache->len_arg_index >= 0) {
306
        PyGIArgCache *child_cache = NULL;
307

308 309
        child_cache = _pygi_callable_cache_get_arg (callable_cache,
                                                    seq_cache->len_arg_index);
310
        if (child_cache == NULL) {
311
            child_cache = _arg_cache_alloc ();
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
        } else {
            /* If the "length" arg cache already exists (the length comes before
             * the array in the argument list), remove it from the to_py_args list
             * because it does not belong in "to python" return tuple. The length
             * will implicitly be a part of the returned Python list.
             */
            if (direction & PYGI_DIRECTION_TO_PYTHON) {
                callable_cache->to_py_args =
                    g_slist_remove (callable_cache->to_py_args, child_cache);
            }

            /* This is a case where the arg cache already exists and has been
             * setup by another array argument sharing the same length argument.
             * See: gi_marshalling_tests_multi_array_key_value_in
             */
            if (child_cache->meta_type == PYGI_META_ARG_TYPE_CHILD)
                return child_cache;
329 330
        }

331 332 333 334 335
        /* There is a length argument for this array, so increment the number
         * of "to python" child arguments when applicable.
         */
        if (direction & PYGI_DIRECTION_TO_PYTHON)
             callable_cache->n_to_py_child_args++;
336

337
        child_cache->meta_type = PYGI_META_ARG_TYPE_CHILD;
338
        child_cache->direction = direction;
339 340
        child_cache->to_py_marshaller = NULL;
        child_cache->from_py_marshaller = NULL;
341

342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
        /* ugly edge case code:
         *
         * When the length comes before the array parameter we need to update
         * indexes of arguments after the index argument.
         */
        if (seq_cache->len_arg_index < arg_index && direction & PYGI_DIRECTION_FROM_PYTHON) {
            gssize i;
            (*py_arg_index) -= 1;
            callable_cache->n_py_args -= 1;

            for (i = seq_cache->len_arg_index + 1;
                   i < _pygi_callable_cache_args_len (callable_cache); i++) {
                PyGIArgCache *update_cache = _pygi_callable_cache_get_arg (callable_cache, i);
                if (update_cache == NULL)
                    break;

                update_cache->py_arg_index -= 1;
            }
        }

362
        _pygi_callable_cache_set_arg (callable_cache, seq_cache->len_arg_index, child_cache);
363
        return child_cache;
364 365
    }

366 367
    return NULL;
}
368

369 370 371 372 373 374 375 376 377 378 379 380
static gboolean
_arg_cache_from_py_array_setup (PyGIArgCache *arg_cache,
                                PyGICallableCache *callable_cache,
                                GITypeInfo *type_info,
                                GITransfer transfer,
                                PyGIDirection direction,
                                gssize arg_index)
{
    PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
    seq_cache->array_type = g_type_info_get_array_type (type_info);
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_array;
    arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_array;
381
    return TRUE;
382 383
}

384
static gboolean
385 386 387 388 389 390
_arg_cache_to_py_array_setup (PyGIArgCache *arg_cache,
                              PyGICallableCache *callable_cache,
                              GITypeInfo *type_info,
                              GITransfer transfer,
                              PyGIDirection direction,
                              gssize arg_index)
391
{
John (J5) Palmieri's avatar
John (J5) Palmieri committed
392
    PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
393
    seq_cache->array_type = g_type_info_get_array_type (type_info);
394 395
    arg_cache->to_py_marshaller = _pygi_marshal_to_py_array;
    arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_array;
396 397 398
    return TRUE;
}

399
static void
400 401
_arg_cache_from_py_glist_setup (PyGIArgCache *arg_cache,
                                GITransfer transfer)
402
{
403 404
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_glist;
    arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_glist;
405
}
406

407
static void
408 409
_arg_cache_to_py_glist_setup (PyGIArgCache *arg_cache,
                              GITransfer transfer)
410
{
411 412
    arg_cache->to_py_marshaller = _pygi_marshal_to_py_glist;
    arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_glist;
413 414
}

415
static void
416 417
_arg_cache_from_py_gslist_setup (PyGIArgCache *arg_cache,
                                 GITransfer transfer)
418
{
419 420
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_gslist;
    arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_glist;
421
}
422

423
static void
424 425
_arg_cache_to_py_gslist_setup (PyGIArgCache *arg_cache,
                                 GITransfer transfer)
426
{
427 428
    arg_cache->to_py_marshaller = _pygi_marshal_to_py_gslist;
    arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_glist;
429 430
}

431
static void
432
_arg_cache_from_py_ghash_setup (PyGIArgCache *arg_cache)
433
{
434 435
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_ghash;
    arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_ghash;
436 437
}

438
static void
439
_arg_cache_to_py_ghash_setup (PyGIArgCache *arg_cache)
440
{
441 442
    arg_cache->to_py_marshaller = _pygi_marshal_to_py_ghash;
    arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_ghash;
443 444
}

445
static void
446
_arg_cache_from_py_gerror_setup (PyGIArgCache *arg_cache)
447
{
448
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_gerror;
449
    arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD;
450 451
}

452
static void
453
_arg_cache_to_py_gerror_setup (PyGIArgCache *arg_cache)
454
{
455
    arg_cache->to_py_marshaller = _pygi_marshal_to_py_gerror;
456
    arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD;
457 458
}

459
static void
460 461
_arg_cache_from_py_interface_union_setup (PyGIArgCache *arg_cache,
                                          GITransfer transfer)
462
{
463
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_struct_cache_adapter;
464 465
}

466
static void
467 468
_arg_cache_to_py_interface_union_setup (PyGIArgCache *arg_cache,
                                        GITransfer transfer)
469
{
470
    arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_struct_cache_adapter;
471 472
}

473
static void
474 475 476
_arg_cache_from_py_interface_struct_setup (PyGIArgCache *arg_cache,
                                           GIInterfaceInfo *iface_info,
                                           GITransfer transfer)
477
{
478
    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
479
    iface_cache->is_foreign = g_struct_info_is_foreign ( (GIStructInfo*)iface_info);
480
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_struct_cache_adapter;
481 482

    if (iface_cache->g_type == G_TYPE_VALUE)
483
        arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_struct_gvalue;
484
    else if (iface_cache->is_foreign)
485
        arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_struct_foreign;
486
}
487

488
static void
489 490 491
_arg_cache_to_py_interface_struct_setup (PyGIArgCache *arg_cache,
                                         GIInterfaceInfo *iface_info,
                                         GITransfer transfer)
492 493
{
    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
494
    iface_cache->is_foreign = g_struct_info_is_foreign ( (GIStructInfo*)iface_info);
495
    arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_struct_cache_adapter;
496 497

    if (iface_cache->is_foreign)
498
        arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_interface_struct_foreign;
499 500
}

501
static void
502 503
_arg_cache_from_py_interface_object_setup (PyGIArgCache *arg_cache,
                                           GITransfer transfer)
504
{
505 506
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_object;
    arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_object;
507 508
}

509
static void
510 511
_arg_cache_to_py_interface_object_setup (PyGIArgCache *arg_cache,
                                         GITransfer transfer)
512
{
513
    arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_object_cache_adapter;
514
    arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_interface_object;
515 516
}

517
static void
518 519
_arg_cache_from_py_interface_callback_setup (PyGIArgCache *arg_cache,
                                             PyGICallableCache *callable_cache)
John (J5) Palmieri's avatar
John (J5) Palmieri committed
520
{
521
    PyGICallbackCache *callback_cache = (PyGICallbackCache *)arg_cache;
John (J5) Palmieri's avatar
John (J5) Palmieri committed
522
    if (callback_cache->user_data_index >= 0) {
523
        PyGIArgCache *user_data_arg_cache = _arg_cache_alloc ();
524
        user_data_arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD_WITH_PYARG;
525
        user_data_arg_cache->direction = PYGI_DIRECTION_FROM_PYTHON;
526
        user_data_arg_cache->has_default = TRUE; /* always allow user data with a NULL default. */
527 528
        _pygi_callable_cache_set_arg (callable_cache, callback_cache->user_data_index,
                                      user_data_arg_cache);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
529
    }
530 531

    if (callback_cache->destroy_notify_index >= 0) {
532
        PyGIArgCache *destroy_arg_cache = _arg_cache_alloc ();
533
        destroy_arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD;
534
        destroy_arg_cache->direction = PYGI_DIRECTION_FROM_PYTHON;
535 536
        _pygi_callable_cache_set_arg (callable_cache, callback_cache->destroy_notify_index,
                                      destroy_arg_cache);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
537
    }
538
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_callback;
539
    arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_callback;
540 541
}

542
static void
543
_arg_cache_to_py_interface_callback_setup (void)
544
{
545 546 547
    PyErr_Format(PyExc_NotImplementedError,
                 "Callback returns are not supported");
}
548

549
static void
550 551
_arg_cache_from_py_interface_enum_setup (PyGIArgCache *arg_cache,
                                         GITransfer transfer)
552
{
553
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_enum;
554 555
}

556
static void
557 558
_arg_cache_to_py_interface_enum_setup (PyGIArgCache *arg_cache,
                                       GITransfer transfer)
559
{
560
    arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_enum;
561
}
562

563
static void
564 565
_arg_cache_from_py_interface_flags_setup (PyGIArgCache *arg_cache,
                                          GITransfer transfer)
566
{
567
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_flags;
568 569
}

570
static void
571 572
_arg_cache_to_py_interface_flags_setup (PyGIArgCache *arg_cache,
                                        GITransfer transfer)
573
{
574
    arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_flags;
575 576
}

577 578 579 580 581
PyGIArgCache *
_arg_cache_new_for_interface (GIInterfaceInfo *iface_info,
                              PyGICallableCache *callable_cache,
                              GIArgInfo *arg_info,
                              GITransfer transfer,
582
                              PyGIDirection direction,
583 584
                              gssize c_arg_index,
                              gssize py_arg_index)
585 586
{
    PyGIInterfaceCache *iface_cache = NULL;
587
    PyGIArgCache *arg_cache = NULL;
588
    gssize child_offset = 0;
589
    GIInfoType info_type;
590 591 592 593 594

    if (callable_cache != NULL)
        child_offset =
            (callable_cache->function_type == PYGI_FUNCTION_TYPE_METHOD ||
                 callable_cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) ? 1: 0;
595

596 597
    info_type = g_base_info_get_type ( (GIBaseInfo *)iface_info);

598 599
    /* Callbacks are special cased */
    if (info_type != GI_INFO_TYPE_CALLBACK) {
600
        iface_cache = _interface_cache_new (iface_info);
601 602 603 604 605 606

        arg_cache = (PyGIArgCache *)iface_cache;
        if (arg_cache == NULL)
            return NULL;
    }

607 608
    switch (info_type) {
        case GI_INFO_TYPE_UNION:
609
            if (direction & PYGI_DIRECTION_FROM_PYTHON)
610
               _arg_cache_from_py_interface_union_setup (arg_cache, transfer);
611

612
            if (direction & PYGI_DIRECTION_TO_PYTHON)
613
               _arg_cache_to_py_interface_union_setup (arg_cache, transfer);
614

615
            break;
616
        case GI_INFO_TYPE_BOXED:
617
        case GI_INFO_TYPE_STRUCT:
618
            if (direction & PYGI_DIRECTION_FROM_PYTHON)
619 620 621 622
               _arg_cache_from_py_interface_struct_setup (arg_cache,
                                                          iface_info,
                                                          transfer);

623
            if (direction & PYGI_DIRECTION_TO_PYTHON)
624 625 626
               _arg_cache_to_py_interface_struct_setup (arg_cache,
                                                        iface_info,
                                                        transfer);
627 628 629
            break;
        case GI_INFO_TYPE_OBJECT:
        case GI_INFO_TYPE_INTERFACE:
630
            if (direction & PYGI_DIRECTION_FROM_PYTHON)
631
               _arg_cache_from_py_interface_object_setup (arg_cache, transfer);
632

633
            if (direction & PYGI_DIRECTION_TO_PYTHON)
634
               _arg_cache_to_py_interface_object_setup (arg_cache, transfer);
635

636 637
            break;
        case GI_INFO_TYPE_CALLBACK:
638 639 640
            {
                PyGICallbackCache *callback_cache;

641
                if (direction & PYGI_DIRECTION_TO_PYTHON) {
642
                    _arg_cache_to_py_interface_callback_setup ();
643 644 645
                    return NULL;
                }

John (J5) Palmieri's avatar
John (J5) Palmieri committed
646
                callback_cache =
647 648 649
                    _callback_cache_new (arg_info,
                                         iface_info,
                                         child_offset);
650 651 652 653 654

                arg_cache = (PyGIArgCache *)callback_cache;
                if (arg_cache == NULL)
                    return NULL;

655
                if (direction & PYGI_DIRECTION_FROM_PYTHON)
656
                    _arg_cache_from_py_interface_callback_setup (arg_cache, callable_cache);
657 658 659

                break;
            }
660
        case GI_INFO_TYPE_ENUM:
661
            if (direction & PYGI_DIRECTION_FROM_PYTHON)
662
               _arg_cache_from_py_interface_enum_setup (arg_cache, transfer);
663

664
            if (direction & PYGI_DIRECTION_TO_PYTHON)
665
               _arg_cache_to_py_interface_enum_setup (arg_cache, transfer);
666

667 668
            break;
        case GI_INFO_TYPE_FLAGS:
669
            if (direction & PYGI_DIRECTION_FROM_PYTHON)
670
               _arg_cache_from_py_interface_flags_setup (arg_cache, transfer);
671

672
            if (direction & PYGI_DIRECTION_TO_PYTHON)
673
               _arg_cache_to_py_interface_flags_setup (arg_cache, transfer);
674

675 676
            break;
        default:
677
            g_assert_not_reached ();
678 679 680 681 682 683 684 685
    }

    if (arg_cache != NULL) {
        arg_cache->direction = direction;
        arg_cache->transfer = transfer;
        arg_cache->type_tag = GI_TYPE_TAG_INTERFACE;
        arg_cache->py_arg_index = py_arg_index;
        arg_cache->c_arg_index = c_arg_index;
686

687
        if (iface_cache != NULL) {
688
            g_base_info_ref ( (GIBaseInfo *)iface_info);
689 690
            iface_cache->interface_info = iface_info;
        }
691
    }
692 693

    return arg_cache;
694 695
}

696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715
/* _arg_info_default_value
 * info:
 * arg: (out): GIArgument to fill in with default value.
 *
 * This is currently a place holder API which only supports "allow-none" pointer args.
 * Once defaults are part of the GI API, we can replace this with: g_arg_info_default_value
 * https://bugzilla.gnome.org/show_bug.cgi?id=558620
 *
 * Returns: TRUE if the given argument supports a default value and was filled in.
 */
static gboolean
_arg_info_default_value (GIArgInfo *info, GIArgument *arg)
{
    if (g_arg_info_may_be_null (info)) {
        arg->v_pointer = NULL;
        return TRUE;
    }
    return FALSE;
}

716
PyGIArgCache *
717 718
_arg_cache_new (GITypeInfo *type_info,
                PyGICallableCache *callable_cache,
719
                GIArgInfo *arg_info,     /* may be null */
720
                GITransfer transfer,
721
                PyGIDirection direction,
722 723
                gssize c_arg_index,
                gssize py_arg_index)
724
{
725
    PyGIArgCache *arg_cache = NULL;
726
    gssize child_offset = 0;
727
    GITypeTag type_tag;
728

729 730
    type_tag = g_type_info_get_tag (type_info);

731 732 733 734
    if (callable_cache != NULL)
        child_offset =
            (callable_cache->function_type == PYGI_FUNCTION_TYPE_METHOD ||
                callable_cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) ? 1: 0;
735

736 737
    switch (type_tag) {
       case GI_TYPE_TAG_VOID:
738
           arg_cache = _arg_cache_alloc ();
739 740
           if (arg_cache == NULL)
               break;
741

742
           if (direction & PYGI_DIRECTION_FROM_PYTHON)
743 744
               _arg_cache_from_py_void_setup (arg_cache);

745
           if (direction & PYGI_DIRECTION_TO_PYTHON)
746
               _arg_cache_to_py_void_setup (arg_cache);
747

748 749 750 751 752 753 754 755 756 757 758 759 760 761
           break;
       case GI_TYPE_TAG_BOOLEAN:
       case GI_TYPE_TAG_INT8:
       case GI_TYPE_TAG_UINT8:
       case GI_TYPE_TAG_INT16:
       case GI_TYPE_TAG_UINT16:
       case GI_TYPE_TAG_INT32:
       case GI_TYPE_TAG_UINT32:
       case GI_TYPE_TAG_INT64:
       case GI_TYPE_TAG_UINT64:
       case GI_TYPE_TAG_FLOAT:
       case GI_TYPE_TAG_DOUBLE:
       case GI_TYPE_TAG_UNICHAR:
       case GI_TYPE_TAG_GTYPE:
762
           arg_cache = _arg_cache_alloc ();
763 764
           if (arg_cache == NULL)
               break;
765

766
           if (direction &