pygi-cache.c 45.2 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-type.h"
26
#include <girepository.h>
27

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

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

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

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

John (J5) Palmieri's avatar
John (J5) Palmieri committed
65 66
static void
_hash_cache_free_func(PyGIHashCache *cache)
67
{
John (J5) Palmieri's avatar
John (J5) Palmieri committed
68 69 70
    if (cache != NULL) {
        _pygi_arg_cache_free(cache->key_cache);
        _pygi_arg_cache_free(cache->value_cache);
71
        g_slice_free(PyGIHashCache, cache);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
72
    }
73 74
}

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

84
static void
John (J5) Palmieri's avatar
John (J5) Palmieri committed
85
_callback_cache_free_func(PyGICallbackCache *cache)
86
{
87 88 89 90
    if (cache != NULL) {
        if (cache->interface_info != NULL)
            g_base_info_unref( (GIBaseInfo *)cache->interface_info);

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

void
John (J5) Palmieri's avatar
John (J5) Palmieri committed
96
_pygi_function_cache_free(PyGIFunctionCache *cache)
97 98 99
{
    int i;

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

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

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

/* cache generation */
static inline PyGIFunctionCache *
117
_function_cache_new_from_function_info(GIFunctionInfo *function_info)
118 119 120 121 122
{
    PyGIFunctionCache *fc;
    GIFunctionInfoFlags flags;

    fc = g_slice_new0(PyGIFunctionCache);
123 124

    fc->name = g_base_info_get_name((GIBaseInfo *)function_info);
125 126 127
    flags = g_function_info_get_flags(function_info);
    fc->is_method = flags & GI_FUNCTION_IS_METHOD;
    fc->is_constructor = flags & GI_FUNCTION_IS_CONSTRUCTOR;
128

129
    fc->n_args = g_callable_info_get_n_args ( (GICallableInfo *) function_info) + (fc->is_method ? 1: 0);
130 131
    if (fc->n_args > 0)
        fc->args_cache = g_slice_alloc0(fc->n_args * sizeof(PyGIArgCache *));
132 133 134 135

    return fc;
}

136 137 138 139
static inline PyGIInterfaceCache *
_interface_cache_new_from_interface_info(GIInterfaceInfo *iface_info)
{
    PyGIInterfaceCache *ic;
John (J5) Palmieri's avatar
John (J5) Palmieri committed
140

141
    ic = g_slice_new0(PyGIInterfaceCache);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
142
    ((PyGIArgCache *)ic)->destroy_notify = (GDestroyNotify)_interface_cache_free_func;
143 144 145 146 147 148 149 150 151 152 153
    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;

154
    ic->type_name = _pygi_g_base_info_get_fullname(iface_info);
155 156 157
    return ic;
}

158
static inline PyGISequenceCache *
159
_sequence_cache_new_from_type_info(GITypeInfo *type_info,
160 161
                                   GIDirection direction,
                                   GITransfer transfer,
162
                                   gint aux_offset)
163 164 165
{
    PyGISequenceCache *sc;
    GITypeInfo *item_type_info;
166
    GITypeTag item_type_tag;
167
    GITransfer item_transfer;
168 169

    sc = g_slice_new0(PyGISequenceCache);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
170
    ((PyGIArgCache *)sc)->destroy_notify = (GDestroyNotify)_sequence_cache_free_func;
171 172 173 174

    sc->fixed_size = -1;
    sc->len_arg_index = -1;
    sc->is_zero_terminated = g_type_info_is_zero_terminated(type_info);
175
    if (!sc->is_zero_terminated)
176 177
        sc->fixed_size = g_type_info_get_array_fixed_size(type_info);
    if (sc->fixed_size < 0)
178
        sc->len_arg_index = g_type_info_get_array_length (type_info) + aux_offset;
179

180
    item_type_info = g_type_info_get_param_type (type_info, 0);
181
    item_type_tag = g_type_info_get_tag (item_type_info);
182

183 184
    item_transfer =
        transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
185

186 187 188 189 190 191 192
    sc->item_cache = _arg_cache_new_from_type_info(item_type_info,
                                                   NULL,
                                                   NULL,
                                                   item_type_tag,
                                                   item_transfer,
                                                   direction,
                                                   0, 0);
193

194 195 196 197
    if (sc->item_cache == NULL) {
        _pygi_arg_cache_free((PyGIArgCache *)sc);
        return NULL;
    }
John (J5) Palmieri's avatar
John (J5) Palmieri committed
198

199
    sc->item_cache->type_tag = item_type_tag;
200
    sc->item_size = _pygi_g_type_info_size(item_type_info);
201
    g_base_info_unref( (GIBaseInfo *) item_type_info);
202

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

    hc = g_slice_new0(PyGIHashCache);
    ((PyGIArgCache *)hc)->destroy_notify = (GDestroyNotify)_hash_cache_free_func;
    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);

224 225
    item_transfer =
        transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
226

227 228 229 230
    hc->key_cache = _arg_cache_new_from_type_info(key_type_info,
                                                  NULL,
                                                  NULL,
                                                  key_type_tag,
231 232
                                                  item_transfer,
                                                  direction,
233
                                                  0, 0);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
234 235 236 237 238 239

    if (hc->key_cache == NULL) {
        _pygi_arg_cache_free((PyGIArgCache *)hc);
        return NULL;
    }

240 241 242 243
    hc->value_cache = _arg_cache_new_from_type_info(value_type_info,
                                                    NULL,
                                                    NULL,
                                                    value_type_tag,
244 245
                                                    item_transfer,
                                                    direction,
246
                                                    0, 0);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
247 248 249 250 251 252 253 254 255 256 257 258 259 260

    if (hc->value_cache == NULL) {
        _pygi_arg_cache_free((PyGIArgCache *)hc);
        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;
}
261

John (J5) Palmieri's avatar
John (J5) Palmieri committed
262
static inline PyGICallbackCache *
263
_callback_cache_new_from_arg_info(GIArgInfo *arg_info,
264
                                  GIInterfaceInfo *iface_info,
265
                                  gint aux_offset)
John (J5) Palmieri's avatar
John (J5) Palmieri committed
266 267 268 269
{
   PyGICallbackCache *cc;

   cc = g_slice_new0(PyGICallbackCache);
270 271
   cc->user_data_index = g_arg_info_get_closure(arg_info) + aux_offset;
   cc->destroy_notify_index = g_arg_info_get_destroy(arg_info) + aux_offset;
John (J5) Palmieri's avatar
John (J5) Palmieri committed
272
   cc->scope = g_arg_info_get_scope(arg_info);
273 274
   g_base_info_ref( (GIBaseInfo *)iface_info);
   cc->interface_info = iface_info;
John (J5) Palmieri's avatar
John (J5) Palmieri committed
275 276 277
   return cc;
}

278 279 280 281 282
static inline PyGIArgCache *
_arg_cache_new(void)
{
    return g_slice_new0(PyGIArgCache);
}
283

John (J5) Palmieri's avatar
John (J5) Palmieri committed
284
static inline void
285
_arg_cache_in_void_setup(PyGIArgCache *arg_cache)
286
{
287 288
    arg_cache->in_marshaller = _pygi_marshal_in_void;
}
289

John (J5) Palmieri's avatar
John (J5) Palmieri committed
290
static inline void
291 292 293
_arg_cache_out_void_setup(PyGIArgCache *arg_cache)
{
    arg_cache->out_marshaller = _pygi_marshal_out_void;
294 295
}

296 297
static inline void
_arg_cache_in_boolean_setup(PyGIArgCache *arg_cache)
298
{
299
    arg_cache->in_marshaller = _pygi_marshal_in_boolean;
300 301
}

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

static inline void
_arg_cache_in_int8_setup(PyGIArgCache *arg_cache)
310
{
311
    arg_cache->in_marshaller = _pygi_marshal_in_int8;
312 313
}

314 315 316 317 318 319 320 321
static inline void
_arg_cache_out_int8_setup(PyGIArgCache *arg_cache)
{
    arg_cache->out_marshaller = _pygi_marshal_out_int8;
}

static inline void
_arg_cache_in_uint8_setup(PyGIArgCache *arg_cache)
322
{
323
    arg_cache->in_marshaller = _pygi_marshal_in_uint8;
324 325
}

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

static inline void
_arg_cache_in_int16_setup(PyGIArgCache *arg_cache)
334
{
335
    arg_cache->in_marshaller = _pygi_marshal_in_int16;
336 337
}

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

static inline void
_arg_cache_in_uint16_setup(PyGIArgCache *arg_cache)
346
{
347
    arg_cache->in_marshaller = _pygi_marshal_in_uint16;
348 349
}

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

static inline void
_arg_cache_in_int32_setup(PyGIArgCache *arg_cache)
358
{
359
    arg_cache->in_marshaller = _pygi_marshal_in_int32;
360 361
}

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

static inline void
_arg_cache_in_uint32_setup(PyGIArgCache *arg_cache)
370
{
371
    arg_cache->in_marshaller = _pygi_marshal_in_uint32;
372 373
}

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

static inline void
_arg_cache_in_int64_setup(PyGIArgCache *arg_cache)
382
{
383
    arg_cache->in_marshaller = _pygi_marshal_in_int64;
384 385
}

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

static inline void
_arg_cache_in_uint64_setup(PyGIArgCache *arg_cache)
394
{
395
    arg_cache->in_marshaller = _pygi_marshal_in_uint64;
396 397
}

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

static inline void
_arg_cache_in_float_setup(PyGIArgCache *arg_cache)
406
{
407
    arg_cache->in_marshaller = _pygi_marshal_in_float;
408 409
}

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

static inline void
_arg_cache_in_double_setup(PyGIArgCache *arg_cache)
418
{
419
    arg_cache->in_marshaller = _pygi_marshal_in_double;
420 421
}

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

static inline void
_arg_cache_in_unichar_setup(PyGIArgCache *arg_cache)
430
{
431
    arg_cache->in_marshaller = _pygi_marshal_in_unichar;
432 433
}

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

static inline void
_arg_cache_in_gtype_setup(PyGIArgCache *arg_cache)
442
{
443
    arg_cache->in_marshaller = _pygi_marshal_in_gtype;
444 445
}

446 447 448 449 450 451 452 453 454
static inline void
_arg_cache_out_gtype_setup(PyGIArgCache *arg_cache)
{
    arg_cache->out_marshaller = _pygi_marshal_out_gtype;
}

static inline void
_arg_cache_in_utf8_setup(PyGIArgCache *arg_cache,
                         GITransfer transfer)
455
{
456
    arg_cache->in_marshaller = _pygi_marshal_in_utf8;
457
}
458

459 460 461 462 463
static inline void
_arg_cache_out_utf8_setup(PyGIArgCache *arg_cache,
                          GITransfer transfer)
{
    arg_cache->out_marshaller = _pygi_marshal_out_utf8;
464 465
}

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

473 474 475
static inline void
_arg_cache_out_filename_setup(PyGIArgCache *arg_cache,
                              GITransfer transfer)
476
{
477 478
    arg_cache->out_marshaller = _pygi_marshal_out_filename;
}
479

480 481 482 483
static inline gboolean
_arg_cache_in_array_setup(PyGIArgCache *arg_cache,
                          PyGIFunctionCache *function_cache,
                          GITypeInfo *type_info,
484 485
                          GITransfer transfer,
                          GIDirection direction)
486
{
John (J5) Palmieri's avatar
John (J5) Palmieri committed
487
    PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
488 489
    seq_cache->array_type = g_type_info_get_array_type(type_info);

490 491 492 493 494 495 496 497 498 499 500 501 502
    arg_cache->in_marshaller = _pygi_marshal_in_array;
    
    if (seq_cache->len_arg_index >= 0 &&
        direction == GI_DIRECTION_IN) {
        PyGIArgCache *aux_cache = 
            function_cache->args_cache[seq_cache->len_arg_index];

        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
503
        aux_cache->aux_type = PYGI_AUX_TYPE_IGNORE;
504
        aux_cache->direction = direction;
505 506
        aux_cache->in_marshaller = NULL;
        aux_cache->out_marshaller = NULL;
507 508 509 510

        function_cache->args_cache[seq_cache->len_arg_index] = aux_cache;
    }

511
    /* arg_cache->cleanup = _pygi_cleanup_array; */
512 513
}

514 515 516 517
static inline gboolean
_arg_cache_out_array_setup(PyGIArgCache *arg_cache,
                           PyGIFunctionCache *function_cache,
                           GITypeInfo *type_info,
518
                           GITransfer transfer,
519
                           GIDirection direction,
520
                           gssize arg_index)
521
{
John (J5) Palmieri's avatar
John (J5) Palmieri committed
522
    PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
523 524 525 526 527 528
    arg_cache->out_marshaller = _pygi_marshal_out_array;

    seq_cache->array_type = g_type_info_get_array_type(type_info);

    if (seq_cache->len_arg_index >= 0) {
        PyGIArgCache *aux_cache = function_cache->args_cache[seq_cache->len_arg_index];
529 530 531
        if (seq_cache->len_arg_index < arg_index)
             function_cache->n_out_aux_args++;

532 533 534 535 536 537 538
        if (aux_cache != NULL) {
            if (aux_cache->aux_type == PYGI_AUX_TYPE_IGNORE)
                return TRUE;

            function_cache->out_args = 
                g_slist_remove(function_cache->out_args, aux_cache);
        } else {
539
            aux_cache = _arg_cache_new();
540
        }
541 542

        aux_cache->aux_type = PYGI_AUX_TYPE_IGNORE;
543 544 545
        aux_cache->direction = direction;
        aux_cache->in_marshaller = NULL;
        aux_cache->out_marshaller = NULL;
546

547 548 549 550 551 552 553 554 555 556
        function_cache->args_cache[seq_cache->len_arg_index] = aux_cache;
    }

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

static inline void
_arg_cache_in_glist_setup(PyGIArgCache *arg_cache,
                          GITransfer transfer)
557
{
558
    arg_cache->in_marshaller = _pygi_marshal_in_glist;
559
    /* arg_cache->cleanup = */
560
}
561

562 563 564 565 566 567
static inline void
_arg_cache_out_glist_setup(PyGIArgCache *arg_cache,
                           GITransfer transfer)
{
    arg_cache->out_marshaller = _pygi_marshal_out_glist;
    /* arg_cache->cleanup = */
568 569
}

570 571 572
static inline void
_arg_cache_in_gslist_setup(PyGIArgCache *arg_cache,
                           GITransfer transfer)
573
{
574
    arg_cache->in_marshaller = _pygi_marshal_in_gslist;
575
    /* arg_cache->cleanup = */
576
}
577

578 579 580 581 582 583
static inline void
_arg_cache_out_gslist_setup(PyGIArgCache *arg_cache,
                            GITransfer transfer)
{
    arg_cache->out_marshaller = _pygi_marshal_out_gslist;
    /* arg_cache->cleanup = */
584 585
}

586 587
static inline void
_arg_cache_in_ghash_setup(PyGIArgCache *arg_cache)
588
{
John (J5) Palmieri's avatar
John (J5) Palmieri committed
589
    arg_cache->in_marshaller = _pygi_marshal_in_ghash;
590 591
}

John (J5) Palmieri's avatar
John (J5) Palmieri committed
592
static inline void
593 594
_arg_cache_out_ghash_setup(PyGIArgCache *arg_cache)
{
595
    arg_cache->out_marshaller = _pygi_marshal_out_ghash;
596 597 598 599
}

static inline void
_arg_cache_in_gerror_setup(PyGIArgCache *arg_cache)
600
{
601
    arg_cache->in_marshaller = _pygi_marshal_in_gerror;
John (J5) Palmieri's avatar
John (J5) Palmieri committed
602
    arg_cache->aux_type = PYGI_AUX_TYPE_IGNORE;
603 604
}

605 606 607 608 609 610 611 612 613 614
static inline void
_arg_cache_out_gerror_setup(PyGIArgCache *arg_cache)
{
    arg_cache->out_marshaller = _pygi_marshal_out_gerror;
    arg_cache->aux_type = PYGI_AUX_TYPE_IGNORE;
}

static inline void
_arg_cache_in_interface_union_setup(PyGIArgCache *arg_cache,
                                    GITransfer transfer)
615
{
John (J5) Palmieri's avatar
John (J5) Palmieri committed
616
    arg_cache->in_marshaller = _pygi_marshal_in_interface_struct;
617 618 619 620 621 622 623
}

static inline void
_arg_cache_out_interface_union_setup(PyGIArgCache *arg_cache,
                                     GITransfer transfer)
{
    arg_cache->out_marshaller = _pygi_marshal_out_interface_struct;
624 625
}

John (J5) Palmieri's avatar
John (J5) Palmieri committed
626
static void
627 628 629 630
_g_slice_free_gvalue_func(GValue *value) {
    g_slice_free(GValue, value);
}

631 632 633 634
static inline void
_arg_cache_in_interface_struct_setup(PyGIArgCache *arg_cache,
                                     GIInterfaceInfo *iface_info,
                                     GITransfer transfer)
635
{
636
    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
637 638 639 640 641 642
    iface_cache->is_foreign = g_struct_info_is_foreign( (GIStructInfo*)iface_info);
    arg_cache->in_marshaller = _pygi_marshal_in_interface_struct;
    if (iface_cache->g_type == G_TYPE_VALUE)
        arg_cache->cleanup = _g_slice_free_gvalue_func;
    if (iface_cache->g_type == G_TYPE_CLOSURE)
        arg_cache->cleanup = g_closure_unref;
643
}
644

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

655 656 657
static inline void
_arg_cache_in_interface_object_setup(PyGIArgCache *arg_cache,
                                     GITransfer transfer)
658 659 660 661 662 663
{
    arg_cache->in_marshaller = _pygi_marshal_in_interface_object;
    if (transfer == GI_TRANSFER_EVERYTHING)
        arg_cache->cleanup = (GDestroyNotify)g_object_unref;
}

John (J5) Palmieri's avatar
John (J5) Palmieri committed
664
static inline void
665
_arg_cache_out_interface_object_setup(PyGIArgCache *arg_cache,
666
                                      GITransfer transfer)
667
{
668 669 670 671 672 673
    arg_cache->out_marshaller = _pygi_marshal_out_interface_object;
}

static inline void
_arg_cache_in_interface_callback_setup(PyGIArgCache *arg_cache,
                                       PyGIFunctionCache *function_cache)
John (J5) Palmieri's avatar
John (J5) Palmieri committed
674
{
675
    PyGICallbackCache *callback_cache = (PyGICallbackCache *)arg_cache;
John (J5) Palmieri's avatar
John (J5) Palmieri committed
676 677 678 679 680
    if (callback_cache->user_data_index >= 0) {
        PyGIArgCache *user_data_arg_cache = _arg_cache_new();
        user_data_arg_cache->aux_type = PYGI_AUX_TYPE_HAS_PYARG;
        function_cache->args_cache[callback_cache->user_data_index] = user_data_arg_cache;
    }
681 682

    if (callback_cache->destroy_notify_index >= 0) {
John (J5) Palmieri's avatar
John (J5) Palmieri committed
683 684 685 686 687
        PyGIArgCache *destroy_arg_cache = _arg_cache_new();
        destroy_arg_cache->aux_type = PYGI_AUX_TYPE_IGNORE;
        function_cache->args_cache[callback_cache->destroy_notify_index] = destroy_arg_cache;
    }
    arg_cache->in_marshaller = _pygi_marshal_in_interface_callback;
688 689
}

John (J5) Palmieri's avatar
John (J5) Palmieri committed
690
static inline void
691
_arg_cache_out_interface_callback_setup(void)
692
{
693 694 695
    PyErr_Format(PyExc_NotImplementedError,
                 "Callback returns are not supported");
}
696

John (J5) Palmieri's avatar
John (J5) Palmieri committed
697
static inline void
698 699 700
_arg_cache_in_interface_enum_setup(PyGIArgCache *arg_cache,
                                   GITransfer transfer)
{
701
    arg_cache->in_marshaller = _pygi_marshal_in_interface_enum;
702 703
}

704 705 706
static inline void
_arg_cache_out_interface_enum_setup(PyGIArgCache *arg_cache,
                                    GITransfer transfer)
707
{
708 709
    arg_cache->out_marshaller = _pygi_marshal_out_interface_enum;
}
710

John (J5) Palmieri's avatar
John (J5) Palmieri committed
711
static inline void
712 713 714
_arg_cache_in_interface_flags_setup(PyGIArgCache *arg_cache,
                                    GITransfer transfer)
{
715
    arg_cache->in_marshaller = _pygi_marshal_in_interface_flags;
716 717
}

718 719 720
static inline void
_arg_cache_out_interface_flags_setup(PyGIArgCache *arg_cache,
                                     GITransfer transfer)
721
{
722 723 724 725 726 727 728 729 730 731 732 733 734 735
    arg_cache->out_marshaller = _pygi_marshal_out_interface_flags;
}

static inline PyGIArgCache *
_arg_cache_new_from_interface_info (GIInterfaceInfo *iface_info,
                                    PyGIFunctionCache *function_cache,
                                    GIArgInfo *arg_info,
                                    GIInfoType info_type,
                                    GITransfer transfer,
                                    GIDirection direction,
                                    gint c_arg_index,
                                    gint py_arg_index)
{
    PyGIInterfaceCache *iface_cache = NULL;
736 737
    PyGIArgCache *arg_cache = NULL;

738 739 740 741 742 743 744 745 746
    /* Callbacks are special cased */
    if (info_type != GI_INFO_TYPE_CALLBACK) {
        iface_cache = _interface_cache_new_from_interface_info(iface_info);

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

747 748
    switch (info_type) {
        case GI_INFO_TYPE_UNION:
749 750 751 752 753 754
            if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
               _arg_cache_in_interface_union_setup(arg_cache, transfer);

            if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
               _arg_cache_out_interface_union_setup(arg_cache, transfer);

755 756
            break;
        case GI_INFO_TYPE_STRUCT:
757 758
            if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
               _arg_cache_in_interface_struct_setup(arg_cache,
John (J5) Palmieri's avatar
John (J5) Palmieri committed
759
                                                    iface_info,
760 761 762 763 764 765 766
                                                    transfer);

            if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
               _arg_cache_out_interface_struct_setup(arg_cache,
                                                     iface_info,
                                                     transfer);

767 768 769
            break;
        case GI_INFO_TYPE_OBJECT:
        case GI_INFO_TYPE_INTERFACE:
770 771 772 773 774 775
            if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
               _arg_cache_in_interface_object_setup(arg_cache, transfer);

            if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
               _arg_cache_out_interface_object_setup(arg_cache, transfer);

776 777
            break;
        case GI_INFO_TYPE_BOXED:
778
            if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
779 780 781
                _arg_cache_in_interface_struct_setup (arg_cache,
                                                                                  iface_info,
                                                                                  transfer);
782 783

            if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
784 785 786
                _arg_cache_out_interface_struct_setup (arg_cache,
                                                                                     iface_info,
                                                                                     transfer);
787

788 789
            break;
        case GI_INFO_TYPE_CALLBACK:
790 791 792 793 794 795 796 797
            {
                PyGICallbackCache *callback_cache;

                if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) {
                    _arg_cache_out_interface_callback_setup();
                    return NULL;
                }

John (J5) Palmieri's avatar
John (J5) Palmieri committed
798
                callback_cache =
799 800 801 802 803 804 805 806 807 808 809 810 811
                    _callback_cache_new_from_arg_info(arg_info,
                                                      iface_info,
                                                      function_cache->is_method ? 1: 0);

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

                if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
                    _arg_cache_in_interface_callback_setup(arg_cache, function_cache);

                break;
            }
812
        case GI_INFO_TYPE_ENUM:
813 814 815 816 817 818
            if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
               _arg_cache_in_interface_enum_setup(arg_cache, transfer);

            if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
               _arg_cache_out_interface_enum_setup(arg_cache, transfer);

819 820
            break;
        case GI_INFO_TYPE_FLAGS:
821 822 823 824 825 826
            if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
               _arg_cache_in_interface_flags_setup(arg_cache, transfer);

            if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
               _arg_cache_out_interface_flags_setup(arg_cache, transfer);

827 828 829 830 831 832 833 834 835 836 837
            break;
        default:
            g_assert_not_reached();
    }

    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;
838

839 840 841 842
        if (iface_cache != NULL) {
            g_base_info_ref( (GIBaseInfo *)iface_info);
            iface_cache->interface_info = iface_info;
        }
843
    }
844 845

    return arg_cache;
846 847
}

848 849 850 851 852 853 854 855 856
PyGIArgCache *
_arg_cache_new_from_type_info (GITypeInfo *type_info,
                               PyGIFunctionCache *function_cache,
                               GIArgInfo *arg_info,
                               GITypeTag type_tag,
                               GITransfer transfer,
                               GIDirection direction,
                               gint c_arg_index,
                               gint py_arg_index)
857
{
858
    PyGIArgCache *arg_cache = NULL;
859

860 861 862 863 864
    switch (type_tag) {
       case GI_TYPE_TAG_VOID:
           arg_cache = _arg_cache_new();
           if (arg_cache == NULL)
               break;
865

866 867
           if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
               _arg_cache_in_void_setup(arg_cache);
868

869 870 871 872 873 874 875
           if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
               _arg_cache_out_void_setup(arg_cache);
           break;
       case GI_TYPE_TAG_BOOLEAN:
           arg_cache = _arg_cache_new();
           if (arg_cache == NULL)
               break;
876

877 878
           if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
               _arg_cache_in_boolean_setup(arg_cache);
879

880 881
           if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
               _arg_cache_out_boolean_setup(arg_cache);
882

883 884 885 886 887
           break;
       case GI_TYPE_TAG_INT8:
           arg_cache = _arg_cache_new();
           if (arg_cache == NULL)
               break;
888

889 890
           if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
               _arg_cache_in_int8_setup(arg_cache);
891

892 893
           if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
               _arg_cache_out_int8_setup(arg_cache);
894

895 896 897 898 899
           break;
       case GI_TYPE_TAG_UINT8:
           arg_cache = _arg_cache_new();
           if (arg_cache == NULL)
               break;
900

901 902
           if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
               _arg_cache_in_uint8_setup(arg_cache);
903

904 905
           if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
               _arg_cache_out_uint8_setup(arg_cache);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
906

907 908 909 910 911
           break;
       case GI_TYPE_TAG_INT16:
           arg_cache = _arg_cache_new();
           if (arg_cache == NULL)
               break;
John (J5) Palmieri's avatar
John (J5) Palmieri committed
912

913 914
           if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
               _arg_cache_in_int16_setup(arg_cache);
915

916 917
           if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
               _arg_cache_out_int16_setup(arg_cache);
918

919 920 921 922 923
           break;
       case GI_TYPE_TAG_UINT16:
           arg_cache = _arg_cache_new();
           if (arg_cache == NULL)
               break;
924

925 926
           if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
               _arg_cache_in_uint16_setup(arg_cache);
927

928 929
           if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
               _arg_cache_out_uint16_setup(arg_cache);
930

931 932 933 934 935
           break;
       case GI_TYPE_TAG_INT32:
           arg_cache = _arg_cache_new();
           if (arg_cache == NULL)
               break;
936

937 938
           if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
               _arg_cache_in_int32_setup(arg_cache);
939

940 941
           if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
               _arg_cache_out_int32_setup(arg_cache);
942

943 944 945 946 947
           break;
       case GI_TYPE_TAG_UINT32:
           arg_cache = _arg_cache_new();
           if (arg_cache == NULL)
               break;
948

949 950
           if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
               _arg_cache_in_uint32_setup(arg_cache);
951

952 953