pygi-cache.c 45.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
#include "pygi-marshal.h"
25
#include "pygi-marshal-cleanup.h"
26
#include "pygi-type.h"
27
#include <girepository.h>
28

29
PyGIArgCache * _arg_cache_new_from_type_info (GITypeInfo *type_info,
30
                                              PyGICallableCache *callable_cache,
31 32 33 34 35 36 37
                                              GIArgInfo *arg_info,
                                              GITypeTag type_tag,
                                              GITransfer transfer,
                                              GIDirection direction,
                                              gint c_arg_index,
                                              gint py_arg_index);

38
/* cleanup */
John (J5) Palmieri's avatar
John (J5) Palmieri committed
39
void
40
_pygi_arg_cache_free (PyGIArgCache *cache)
John (J5) Palmieri's avatar
John (J5) Palmieri committed
41 42 43 44
{
    if (cache == NULL)
        return;

45
    if (cache->type_info != NULL)
46
        g_base_info_unref ( (GIBaseInfo *)cache->type_info);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
47
    if (cache->destroy_notify)
48
        cache->destroy_notify (cache);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
49
    else
50
        g_slice_free (PyGIArgCache, cache);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
51 52 53
}

static void
54
_interface_cache_free_func (PyGIInterfaceCache *cache)
55 56
{
    if (cache != NULL) {
57
        Py_XDECREF (cache->py_type);
58
        if (cache->type_name != NULL)
59
            g_free (cache->type_name);
60
        if (cache->interface_info != NULL)
61 62
            g_base_info_unref ( (GIBaseInfo *)cache->interface_info);
        g_slice_free (PyGIInterfaceCache, cache);
63 64 65
    }
}

John (J5) Palmieri's avatar
John (J5) Palmieri committed
66
static void
67
_hash_cache_free_func (PyGIHashCache *cache)
68
{
John (J5) Palmieri's avatar
John (J5) Palmieri committed
69
    if (cache != NULL) {
70 71 72
        _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
73
    }
74 75
}

76
static void
77
_sequence_cache_free_func (PyGISequenceCache *cache)
78
{
John (J5) Palmieri's avatar
John (J5) Palmieri committed
79
    if (cache != NULL) {
80 81
        _pygi_arg_cache_free (cache->item_cache);
        g_slice_free (PyGISequenceCache, cache);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
82
    }
83 84
}

85
static void
86
_callback_cache_free_func (PyGICallbackCache *cache)
87
{
88 89
    if (cache != NULL) {
        if (cache->interface_info != NULL)
90
            g_base_info_unref ( (GIBaseInfo *)cache->interface_info);
91

92
        g_slice_free (PyGICallbackCache, cache);
93
    }
94 95 96
}

void
97
_pygi_callable_cache_free (PyGICallableCache *cache)
98 99 100
{
    int i;

101 102 103
    if (cache == NULL)
        return;

104
    g_slist_free (cache->out_args);
105 106
    for (i = 0; i < cache->n_args; i++) {
        PyGIArgCache *tmp = cache->args_cache[i];
107
        _pygi_arg_cache_free (tmp);
108
    }
109
    if (cache->return_cache != NULL)
110
        _pygi_arg_cache_free (cache->return_cache);
111

112 113
    g_slice_free1 (cache->n_args * sizeof (PyGIArgCache *), cache->args_cache);
    g_slice_free (PyGICallableCache, cache);
114 115 116
}

/* cache generation */
117
static inline PyGICallableCache *
118
_callable_cache_new_from_callable_info (GICallableInfo *callable_info)
119
{
120
    PyGICallableCache *cache;
121

122
    cache = g_slice_new0 (PyGICallableCache);
123

124
    cache->name = g_base_info_get_name ((GIBaseInfo *)callable_info);
125

126 127
    if (g_base_info_get_type ( (GIBaseInfo *)callable_info) == GI_INFO_TYPE_FUNCTION) {
        GIFunctionInfoFlags flags;
128

129 130 131 132 133 134 135 136 137 138
        flags = g_function_info_get_flags ( (GIFunctionInfo *)callable_info);
        cache->is_method = flags & GI_FUNCTION_IS_METHOD;
        cache->is_constructor = flags & GI_FUNCTION_IS_CONSTRUCTOR;
    } else {
        cache->is_method = TRUE;
        cache->is_constructor = FALSE;
    }

    cache->n_args = g_callable_info_get_n_args (callable_info) + (cache->is_method ? 1: 0);
    if (cache->n_args > 0)
139
        cache->args_cache = g_slice_alloc0 (cache->n_args * sizeof (PyGIArgCache *));
140 141

    return cache;
142 143
}

144
static inline PyGIInterfaceCache *
145
_interface_cache_new_from_interface_info (GIInterfaceInfo *iface_info)
146 147
{
    PyGIInterfaceCache *ic;
John (J5) Palmieri's avatar
John (J5) Palmieri committed
148

149 150
    ic = g_slice_new0 (PyGIInterfaceCache);
    ( (PyGIArgCache *)ic)->destroy_notify = (GDestroyNotify)_interface_cache_free_func;
151 152 153 154 155 156 157 158 159 160 161
    ic->g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *)iface_info);
    if (ic->g_type != G_TYPE_NONE) {
        ic->py_type = _pygi_type_get_from_g_type (ic->g_type);
    } else {
        /* FIXME: avoid passing GI infos to noncache API */
        ic->py_type = _pygi_type_import_by_gi_info ( (GIBaseInfo *) iface_info);
    }

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

162
    ic->type_name = _pygi_g_base_info_get_fullname (iface_info);
163 164 165
    return ic;
}

166
static inline PyGISequenceCache *
167 168 169 170
_sequence_cache_new_from_type_info (GITypeInfo *type_info,
                                    GIDirection direction,
                                    GITransfer transfer,
                                    gint aux_offset)
171 172 173
{
    PyGISequenceCache *sc;
    GITypeInfo *item_type_info;
174
    GITypeTag item_type_tag;
175
    GITransfer item_transfer;
176

177 178
    sc = g_slice_new0 (PyGISequenceCache);
    ( (PyGIArgCache *)sc)->destroy_notify = (GDestroyNotify)_sequence_cache_free_func;
179 180 181

    sc->fixed_size = -1;
    sc->len_arg_index = -1;
182
    sc->is_zero_terminated = g_type_info_is_zero_terminated (type_info);
183
    if (!sc->is_zero_terminated) {
184
        sc->fixed_size = g_type_info_get_array_fixed_size (type_info);
185 186 187
        if (sc->fixed_size < 0)
            sc->len_arg_index = g_type_info_get_array_length (type_info) + aux_offset;
    }
188

189
    item_type_info = g_type_info_get_param_type (type_info, 0);
190
    item_type_tag = g_type_info_get_tag (item_type_info);
191

192 193
    item_transfer =
        transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
194

195 196 197 198 199 200 201
    sc->item_cache = _arg_cache_new_from_type_info (item_type_info,
                                                    NULL,
                                                    NULL,
                                                    item_type_tag,
                                                    item_transfer,
                                                    direction,
                                                    0, 0);
202

203
    if (sc->item_cache == NULL) {
204
        _pygi_arg_cache_free ( (PyGIArgCache *)sc);
205 206
        return NULL;
    }
John (J5) Palmieri's avatar
John (J5) Palmieri committed
207

208
    sc->item_cache->type_tag = item_type_tag;
209 210
    sc->item_size = _pygi_g_type_info_size (item_type_info);
    g_base_info_unref ( (GIBaseInfo *)item_type_info);
211

212
    return sc;
213
}
John (J5) Palmieri's avatar
John (J5) Palmieri committed
214
static inline PyGIHashCache *
215 216 217
_hash_cache_new_from_type_info (GITypeInfo *type_info,
                                GIDirection direction,
                                GITransfer transfer)
John (J5) Palmieri's avatar
John (J5) Palmieri committed
218 219 220 221 222 223
{
    PyGIHashCache *hc;
    GITypeInfo *key_type_info;
    GITypeTag key_type_tag;
    GITypeInfo *value_type_info;
    GITypeTag value_type_tag;
224
    GITransfer item_transfer;
John (J5) Palmieri's avatar
John (J5) Palmieri committed
225

226 227
    hc = g_slice_new0 (PyGIHashCache);
    ( (PyGIArgCache *)hc)->destroy_notify = (GDestroyNotify)_hash_cache_free_func;
John (J5) Palmieri's avatar
John (J5) Palmieri committed
228 229 230 231 232
    key_type_info = g_type_info_get_param_type (type_info, 0);
    key_type_tag = g_type_info_get_tag (key_type_info);
    value_type_info = g_type_info_get_param_type (type_info, 1);
    value_type_tag = g_type_info_get_tag (value_type_info);

233 234
    item_transfer =
        transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
235

236 237 238 239 240 241 242
    hc->key_cache = _arg_cache_new_from_type_info (key_type_info,
                                                   NULL,
                                                   NULL,
                                                   key_type_tag,
                                                   item_transfer,
                                                   direction,
                                                   0, 0);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
243 244

    if (hc->key_cache == NULL) {
245
        _pygi_arg_cache_free ( (PyGIArgCache *)hc);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
246 247 248
        return NULL;
    }

249 250 251 252 253 254 255
    hc->value_cache = _arg_cache_new_from_type_info (value_type_info,
                                                     NULL,
                                                     NULL,
                                                     value_type_tag,
                                                     item_transfer,
                                                     direction,
                                                     0, 0);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
256 257

    if (hc->value_cache == NULL) {
258
        _pygi_arg_cache_free ( (PyGIArgCache *)hc);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
259 260 261 262 263 264 265 266 267 268 269
        return NULL;
    }

    hc->key_cache->type_tag = key_type_tag;
    hc->value_cache->type_tag = value_type_tag;

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

    return hc;
}
270

John (J5) Palmieri's avatar
John (J5) Palmieri committed
271
static inline PyGICallbackCache *
272 273 274
_callback_cache_new_from_arg_info (GIArgInfo *arg_info,
                                   GIInterfaceInfo *iface_info,
                                   gint aux_offset)
John (J5) Palmieri's avatar
John (J5) Palmieri committed
275 276 277
{
   PyGICallbackCache *cc;

278 279
   cc = g_slice_new0 (PyGICallbackCache);
   cc->user_data_index = g_arg_info_get_closure (arg_info);
280 281
   if (cc->user_data_index != -1)
       cc->user_data_index += aux_offset;
282
   cc->destroy_notify_index = g_arg_info_get_destroy (arg_info);
283 284
   if (cc->destroy_notify_index != -1)
       cc->destroy_notify_index += aux_offset;
285
   cc->scope = g_arg_info_get_scope (arg_info);
286 287
   g_base_info_ref( (GIBaseInfo *)iface_info);
   cc->interface_info = iface_info;
John (J5) Palmieri's avatar
John (J5) Palmieri committed
288 289 290
   return cc;
}

291
static inline PyGIArgCache *
292
_arg_cache_new (void)
293
{
294
    return g_slice_new0 (PyGIArgCache);
295
}
296

John (J5) Palmieri's avatar
John (J5) Palmieri committed
297
static inline void
298
_arg_cache_in_void_setup (PyGIArgCache *arg_cache)
299
{
300 301
    arg_cache->in_marshaller = _pygi_marshal_in_void;
}
302

John (J5) Palmieri's avatar
John (J5) Palmieri committed
303
static inline void
304
_arg_cache_out_void_setup (PyGIArgCache *arg_cache)
305 306
{
    arg_cache->out_marshaller = _pygi_marshal_out_void;
307 308
}

309
static inline void
310
_arg_cache_in_boolean_setup (PyGIArgCache *arg_cache)
311
{
312
    arg_cache->in_marshaller = _pygi_marshal_in_boolean;
313 314
}

John (J5) Palmieri's avatar
John (J5) Palmieri committed
315
static inline void
316
_arg_cache_out_boolean_setup (PyGIArgCache *arg_cache)
317 318 319 320 321
{
    arg_cache->out_marshaller = _pygi_marshal_out_boolean;
}

static inline void
322
_arg_cache_in_int8_setup (PyGIArgCache *arg_cache)
323
{
324
    arg_cache->in_marshaller = _pygi_marshal_in_int8;
325 326
}

327
static inline void
328
_arg_cache_out_int8_setup (PyGIArgCache *arg_cache)
329 330 331 332 333
{
    arg_cache->out_marshaller = _pygi_marshal_out_int8;
}

static inline void
334
_arg_cache_in_uint8_setup (PyGIArgCache *arg_cache)
335
{
336
    arg_cache->in_marshaller = _pygi_marshal_in_uint8;
337 338
}

339
static inline void
340
_arg_cache_out_uint8_setup (PyGIArgCache *arg_cache)
341 342 343 344 345
{
    arg_cache->out_marshaller = _pygi_marshal_out_uint8;
}

static inline void
346
_arg_cache_in_int16_setup (PyGIArgCache *arg_cache)
347
{
348
    arg_cache->in_marshaller = _pygi_marshal_in_int16;
349 350
}

351
static inline void
352
_arg_cache_out_int16_setup (PyGIArgCache *arg_cache)
353 354 355 356 357
{
    arg_cache->out_marshaller = _pygi_marshal_out_int16;
}

static inline void
358
_arg_cache_in_uint16_setup (PyGIArgCache *arg_cache)
359
{
360
    arg_cache->in_marshaller = _pygi_marshal_in_uint16;
361 362
}

363
static inline void
364
_arg_cache_out_uint16_setup (PyGIArgCache *arg_cache)
365 366 367 368 369
{
    arg_cache->out_marshaller = _pygi_marshal_out_uint16;
}

static inline void
370
_arg_cache_in_int32_setup (PyGIArgCache *arg_cache)
371
{
372
    arg_cache->in_marshaller = _pygi_marshal_in_int32;
373 374
}

375
static inline void
376
_arg_cache_out_int32_setup (PyGIArgCache *arg_cache)
377 378 379 380 381
{
    arg_cache->out_marshaller = _pygi_marshal_out_int32;
}

static inline void
382
_arg_cache_in_uint32_setup (PyGIArgCache *arg_cache)
383
{
384
    arg_cache->in_marshaller = _pygi_marshal_in_uint32;
385 386
}

387
static inline void
388
_arg_cache_out_uint32_setup (PyGIArgCache *arg_cache)
389 390 391 392 393
{
    arg_cache->out_marshaller = _pygi_marshal_out_uint32;
}

static inline void
394
_arg_cache_in_int64_setup (PyGIArgCache *arg_cache)
395
{
396
    arg_cache->in_marshaller = _pygi_marshal_in_int64;
397 398
}

399
static inline void
400
_arg_cache_out_int64_setup (PyGIArgCache *arg_cache)
401 402 403 404 405
{
    arg_cache->out_marshaller = _pygi_marshal_out_int64;
}

static inline void
406
_arg_cache_in_uint64_setup (PyGIArgCache *arg_cache)
407
{
408
    arg_cache->in_marshaller = _pygi_marshal_in_uint64;
409 410
}

411
static inline void
412
_arg_cache_out_uint64_setup (PyGIArgCache *arg_cache)
413 414 415 416 417
{
    arg_cache->out_marshaller = _pygi_marshal_out_uint64;
}

static inline void
418
_arg_cache_in_float_setup (PyGIArgCache *arg_cache)
419
{
420
    arg_cache->in_marshaller = _pygi_marshal_in_float;
421 422
}

423
static inline void
424
_arg_cache_out_float_setup (PyGIArgCache *arg_cache)
425 426 427 428 429
{
    arg_cache->out_marshaller = _pygi_marshal_out_float;
}

static inline void
430
_arg_cache_in_double_setup (PyGIArgCache *arg_cache)
431
{
432
    arg_cache->in_marshaller = _pygi_marshal_in_double;
433 434
}

435
static inline void
436
_arg_cache_out_double_setup (PyGIArgCache *arg_cache)
437 438 439 440 441
{
    arg_cache->out_marshaller = _pygi_marshal_out_double;
}

static inline void
442
_arg_cache_in_unichar_setup (PyGIArgCache *arg_cache)
443
{
444
    arg_cache->in_marshaller = _pygi_marshal_in_unichar;
445 446
}

447
static inline void
448
_arg_cache_out_unichar_setup (PyGIArgCache *arg_cache)
449 450 451 452 453
{
    arg_cache->out_marshaller = _pygi_marshal_out_unichar;
}

static inline void
454
_arg_cache_in_gtype_setup (PyGIArgCache *arg_cache)
455
{
456
    arg_cache->in_marshaller = _pygi_marshal_in_gtype;
457 458
}

459
static inline void
460
_arg_cache_out_gtype_setup (PyGIArgCache *arg_cache)
461 462 463 464 465
{
    arg_cache->out_marshaller = _pygi_marshal_out_gtype;
}

static inline void
466 467
_arg_cache_in_utf8_setup (PyGIArgCache *arg_cache,
                          GITransfer transfer)
468
{
469
    arg_cache->in_marshaller = _pygi_marshal_in_utf8;
470
    arg_cache->cleanup = _pygi_marshal_cleanup_utf8;
471
}
472

473
static inline void
474 475
_arg_cache_out_utf8_setup (PyGIArgCache *arg_cache,
                           GITransfer transfer)
476 477
{
    arg_cache->out_marshaller = _pygi_marshal_out_utf8;
478
    arg_cache->cleanup = _pygi_marshal_cleanup_utf8;
479 480
}

481
static inline void
482 483
_arg_cache_in_filename_setup (PyGIArgCache *arg_cache,
                              GITransfer transfer)
484
{
485
    arg_cache->in_marshaller = _pygi_marshal_in_filename;
486
    arg_cache->cleanup = _pygi_marshal_cleanup_utf8;
487 488
}

489
static inline void
490 491
_arg_cache_out_filename_setup (PyGIArgCache *arg_cache,
                               GITransfer transfer)
492
{
493
    arg_cache->out_marshaller = _pygi_marshal_out_filename;
494
    arg_cache->cleanup = _pygi_marshal_cleanup_utf8;
495
}
496

497
static inline gboolean
498 499 500 501 502
_arg_cache_in_array_setup (PyGIArgCache *arg_cache,
                           PyGICallableCache *callable_cache,
                           GITypeInfo *type_info,
                           GITransfer transfer,
                           GIDirection direction)
503
{
John (J5) Palmieri's avatar
John (J5) Palmieri committed
504
    PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
505
    seq_cache->array_type = g_type_info_get_array_type (type_info);
506

507
    arg_cache->in_marshaller = _pygi_marshal_in_array;
508

509 510 511
    if (seq_cache->len_arg_index >= 0 &&
        direction == GI_DIRECTION_IN) {
        PyGIArgCache *aux_cache = 
512
            callable_cache->args_cache[seq_cache->len_arg_index];
513 514 515 516 517 518 519

        if (aux_cache == NULL) {
            aux_cache = _arg_cache_new();
        } else if (aux_cache->aux_type == PYGI_AUX_TYPE_IGNORE) {
            return TRUE;
        }

John (J5) Palmieri's avatar
John (J5) Palmieri committed
520
        aux_cache->aux_type = PYGI_AUX_TYPE_IGNORE;
521
        aux_cache->direction = direction;
522 523
        aux_cache->in_marshaller = NULL;
        aux_cache->out_marshaller = NULL;
524

525
        callable_cache->args_cache[seq_cache->len_arg_index] = aux_cache;
526 527
    }

528
    /* arg_cache->cleanup = _pygi_cleanup_array; */
529 530

    return TRUE;
531 532
}

533
static inline gboolean
534 535 536 537 538 539
_arg_cache_out_array_setup (PyGIArgCache *arg_cache,
                            PyGICallableCache *callable_cache,
                            GITypeInfo *type_info,
                            GITransfer transfer,
                            GIDirection direction,
                            gssize arg_index)
540
{
John (J5) Palmieri's avatar
John (J5) Palmieri committed
541
    PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
542 543
    arg_cache->out_marshaller = _pygi_marshal_out_array;

544
    seq_cache->array_type = g_type_info_get_array_type (type_info);
545 546

    if (seq_cache->len_arg_index >= 0) {
547
        PyGIArgCache *aux_cache = callable_cache->args_cache[seq_cache->len_arg_index];
548
        if (seq_cache->len_arg_index < arg_index)
549
             callable_cache->n_out_aux_args++;
550

551 552 553 554
        if (aux_cache != NULL) {
            if (aux_cache->aux_type == PYGI_AUX_TYPE_IGNORE)
                return TRUE;

555 556
            callable_cache->out_args = 
                g_slist_remove (callable_cache->out_args, aux_cache);
557
        } else {
558
            aux_cache = _arg_cache_new ();
559
        }
560 561

        aux_cache->aux_type = PYGI_AUX_TYPE_IGNORE;
562 563 564
        aux_cache->direction = direction;
        aux_cache->in_marshaller = NULL;
        aux_cache->out_marshaller = NULL;
565

566
        callable_cache->args_cache[seq_cache->len_arg_index] = aux_cache;
567 568 569 570 571 572 573
    }

    return TRUE;
    /* arg_cache->cleanup = _pygi_cleanup_array; */
}

static inline void
574 575
_arg_cache_in_glist_setup (PyGIArgCache *arg_cache,
                           GITransfer transfer)
576
{
577
    arg_cache->in_marshaller = _pygi_marshal_in_glist;
578
    /* arg_cache->cleanup = */
579
}
580

581
static inline void
582 583
_arg_cache_out_glist_setup (PyGIArgCache *arg_cache,
                            GITransfer transfer)
584 585 586
{
    arg_cache->out_marshaller = _pygi_marshal_out_glist;
    /* arg_cache->cleanup = */
587 588
}

589
static inline void
590 591
_arg_cache_in_gslist_setup (PyGIArgCache *arg_cache,
                            GITransfer transfer)
592
{
593
    arg_cache->in_marshaller = _pygi_marshal_in_gslist;
594
    /* arg_cache->cleanup = */
595
}
596

597
static inline void
598 599
_arg_cache_out_gslist_setup (PyGIArgCache *arg_cache,
                             GITransfer transfer)
600 601 602
{
    arg_cache->out_marshaller = _pygi_marshal_out_gslist;
    /* arg_cache->cleanup = */
603 604
}

605
static inline void
606
_arg_cache_in_ghash_setup (PyGIArgCache *arg_cache)
607
{
John (J5) Palmieri's avatar
John (J5) Palmieri committed
608
    arg_cache->in_marshaller = _pygi_marshal_in_ghash;
609 610
}

John (J5) Palmieri's avatar
John (J5) Palmieri committed
611
static inline void
612
_arg_cache_out_ghash_setup (PyGIArgCache *arg_cache)
613
{
614
    arg_cache->out_marshaller = _pygi_marshal_out_ghash;
615 616 617
}

static inline void
618
_arg_cache_in_gerror_setup (PyGIArgCache *arg_cache)
619
{
620
    arg_cache->in_marshaller = _pygi_marshal_in_gerror;
John (J5) Palmieri's avatar
John (J5) Palmieri committed
621
    arg_cache->aux_type = PYGI_AUX_TYPE_IGNORE;
622 623
}

624
static inline void
625
_arg_cache_out_gerror_setup (PyGIArgCache *arg_cache)
626 627 628 629 630 631
{
    arg_cache->out_marshaller = _pygi_marshal_out_gerror;
    arg_cache->aux_type = PYGI_AUX_TYPE_IGNORE;
}

static inline void
632 633
_arg_cache_in_interface_union_setup (PyGIArgCache *arg_cache,
                                     GITransfer transfer)
634
{
John (J5) Palmieri's avatar
John (J5) Palmieri committed
635
    arg_cache->in_marshaller = _pygi_marshal_in_interface_struct;
636 637 638
}

static inline void
639 640
_arg_cache_out_interface_union_setup (PyGIArgCache *arg_cache,
                                      GITransfer transfer)
641 642
{
    arg_cache->out_marshaller = _pygi_marshal_out_interface_struct;
643 644
}

645
static inline void
646 647 648
_arg_cache_in_interface_struct_setup (PyGIArgCache *arg_cache,
                                      GIInterfaceInfo *iface_info,
                                      GITransfer transfer)
649
{
650
    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
651
    iface_cache->is_foreign = g_struct_info_is_foreign ( (GIStructInfo*)iface_info);
652
    arg_cache->in_marshaller = _pygi_marshal_in_interface_struct;
653
}
654

655
static inline void
656 657 658
_arg_cache_out_interface_struct_setup (PyGIArgCache *arg_cache,
                                       GIInterfaceInfo *iface_info,
                                       GITransfer transfer)
659 660
{
    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
661
    iface_cache->is_foreign = g_struct_info_is_foreign ( (GIStructInfo*)iface_info);
662
    arg_cache->out_marshaller = _pygi_marshal_out_interface_struct;
663 664
}

665
static inline void
666 667
_arg_cache_in_interface_object_setup (PyGIArgCache *arg_cache,
                                      GITransfer transfer)
668 669 670 671
{
    arg_cache->in_marshaller = _pygi_marshal_in_interface_object;
}

John (J5) Palmieri's avatar
John (J5) Palmieri committed
672
static inline void
673 674
_arg_cache_out_interface_object_setup (PyGIArgCache *arg_cache,
                                       GITransfer transfer)
675
{
676 677 678 679
    arg_cache->out_marshaller = _pygi_marshal_out_interface_object;
}

static inline void
680 681
_arg_cache_in_interface_callback_setup (PyGIArgCache *arg_cache,
                                        PyGICallableCache *callable_cache)
John (J5) Palmieri's avatar
John (J5) Palmieri committed
682
{
683
    PyGICallbackCache *callback_cache = (PyGICallbackCache *)arg_cache;
John (J5) Palmieri's avatar
John (J5) Palmieri committed
684
    if (callback_cache->user_data_index >= 0) {
685
        PyGIArgCache *user_data_arg_cache = _arg_cache_new ();
John (J5) Palmieri's avatar
John (J5) Palmieri committed
686
        user_data_arg_cache->aux_type = PYGI_AUX_TYPE_HAS_PYARG;
687
        callable_cache->args_cache[callback_cache->user_data_index] = user_data_arg_cache;
John (J5) Palmieri's avatar
John (J5) Palmieri committed
688
    }
689 690

    if (callback_cache->destroy_notify_index >= 0) {
691
        PyGIArgCache *destroy_arg_cache = _arg_cache_new ();
John (J5) Palmieri's avatar
John (J5) Palmieri committed
692
        destroy_arg_cache->aux_type = PYGI_AUX_TYPE_IGNORE;
693
        callable_cache->args_cache[callback_cache->destroy_notify_index] = destroy_arg_cache;
John (J5) Palmieri's avatar
John (J5) Palmieri committed
694 695
    }
    arg_cache->in_marshaller = _pygi_marshal_in_interface_callback;
696 697
}

John (J5) Palmieri's avatar
John (J5) Palmieri committed
698
static inline void
699
_arg_cache_out_interface_callback_setup (void)
700
{
701 702 703
    PyErr_Format(PyExc_NotImplementedError,
                 "Callback returns are not supported");
}
704

John (J5) Palmieri's avatar
John (J5) Palmieri committed
705
static inline void
706 707
_arg_cache_in_interface_enum_setup (PyGIArgCache *arg_cache,
                                    GITransfer transfer)
708
{
709
    arg_cache->in_marshaller = _pygi_marshal_in_interface_enum;
710 711
}

712
static inline void
713 714
_arg_cache_out_interface_enum_setup (PyGIArgCache *arg_cache,
                                     GITransfer transfer)
715
{
716 717
    arg_cache->out_marshaller = _pygi_marshal_out_interface_enum;
}
718

John (J5) Palmieri's avatar
John (J5) Palmieri committed
719
static inline void
720 721
_arg_cache_in_interface_flags_setup (PyGIArgCache *arg_cache,
                                     GITransfer transfer)
722
{
723
    arg_cache->in_marshaller = _pygi_marshal_in_interface_flags;
724 725
}

726
static inline void
727 728
_arg_cache_out_interface_flags_setup (PyGIArgCache *arg_cache,
                                      GITransfer transfer)
729
{
730 731 732 733 734
    arg_cache->out_marshaller = _pygi_marshal_out_interface_flags;
}

static inline PyGIArgCache *
_arg_cache_new_from_interface_info (GIInterfaceInfo *iface_info,
735
                                    PyGICallableCache *callable_cache,
736 737 738 739 740 741 742 743
                                    GIArgInfo *arg_info,
                                    GIInfoType info_type,
                                    GITransfer transfer,
                                    GIDirection direction,
                                    gint c_arg_index,
                                    gint py_arg_index)
{
    PyGIInterfaceCache *iface_cache = NULL;
744 745
    PyGIArgCache *arg_cache = NULL;

746 747
    GI_IS_INTERFACE_INFO (iface_info);

748 749
    /* Callbacks are special cased */
    if (info_type != GI_INFO_TYPE_CALLBACK) {
750
        iface_cache = _interface_cache_new_from_interface_info (iface_info);
751 752 753 754 755 756

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

757 758
    switch (info_type) {
        case GI_INFO_TYPE_UNION:
759
            if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)