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

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

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

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

static void
54
_interface_cache_free_func (PyGIInterfaceCache *cache)
55 56 57
{
    if (cache != NULL) {
        Py_XDECREF(cache->py_type);
58 59
        if (cache->type_name != NULL)
            g_free(cache->type_name);
60 61 62
        if (cache->interface_info != NULL)
            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 67
static void
_hash_cache_free_func(PyGIHashCache *cache)
68
{
John (J5) Palmieri's avatar
John (J5) Palmieri committed
69 70 71
    if (cache != NULL) {
        _pygi_arg_cache_free(cache->key_cache);
        _pygi_arg_cache_free(cache->value_cache);
72
        g_slice_free(PyGIHashCache, cache);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
73
    }
74 75
}

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

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

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

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

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

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

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

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

    fc = g_slice_new0(PyGIFunctionCache);
124 125

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

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

    return fc;
}

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

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

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

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

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

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

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

184 185 186 187 188
    item_transfer = GI_TRANSFER_NOTHING;
    if (transfer == GI_TRANSFER_EVERYTHING ||
        transfer == GI_TRANSFER_CONTAINER)
        item_transfer = GI_TRANSFER_EVERYTHING;

189 190 191 192 193 194 195 196
    sc->item_cache = _arg_cache_new_from_type_info(item_type_info,
                                                   NULL,
                                                   NULL,
                                                   item_type_tag,
                                                   item_transfer,
                                                   direction,
                                                   FALSE,
                                                   0, 0);
197

198 199 200 201
    if (sc->item_cache == NULL) {
        _pygi_arg_cache_free((PyGIArgCache *)sc);
        return NULL;
    }
John (J5) Palmieri's avatar
John (J5) Palmieri committed
202

203
    sc->item_cache->type_tag = item_type_tag;
204
    sc->item_size = _pygi_g_type_info_size(item_type_info);
205
    g_base_info_unref( (GIBaseInfo *) item_type_info);
206

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

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

228 229 230 231 232
    item_transfer = GI_TRANSFER_NOTHING;
    if (transfer == GI_TRANSFER_EVERYTHING ||
        transfer == GI_TRANSFER_CONTAINER)
        item_transfer = GI_TRANSFER_EVERYTHING;

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

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

247 248 249 250
    hc->value_cache = _arg_cache_new_from_type_info(value_type_info,
                                                    NULL,
                                                    NULL,
                                                    value_type_tag,
251 252
                                                    item_transfer,
                                                    direction,
253 254
                                                    FALSE,
                                                    0, 0);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
255 256 257 258 259 260 261 262 263 264 265 266 267 268

    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;
}
269

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

   cc = g_slice_new0(PyGICallbackCache);
278 279
   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
280
   cc->scope = g_arg_info_get_scope(arg_info);
281 282
   g_base_info_ref( (GIBaseInfo *)iface_info);
   cc->interface_info = iface_info;
John (J5) Palmieri's avatar
John (J5) Palmieri committed
283 284 285
   return cc;
}

286 287 288 289 290
static inline PyGIArgCache *
_arg_cache_new(void)
{
    return g_slice_new0(PyGIArgCache);
}
291

John (J5) Palmieri's avatar
John (J5) Palmieri committed
292
static inline void
293
_arg_cache_in_void_setup(PyGIArgCache *arg_cache)
294
{
295 296
    arg_cache->in_marshaller = _pygi_marshal_in_void;
}
297

John (J5) Palmieri's avatar
John (J5) Palmieri committed
298
static inline void
299 300 301
_arg_cache_out_void_setup(PyGIArgCache *arg_cache)
{
    arg_cache->out_marshaller = _pygi_marshal_out_void;
302 303
}

304 305
static inline void
_arg_cache_in_boolean_setup(PyGIArgCache *arg_cache)
306
{
307
    arg_cache->in_marshaller = _pygi_marshal_in_boolean;
308 309
}

John (J5) Palmieri's avatar
John (J5) Palmieri committed
310
static inline void
311 312 313 314 315 316 317
_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)
318
{
319
    arg_cache->in_marshaller = _pygi_marshal_in_int8;
320 321
}

322 323 324 325 326 327 328 329
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)
330
{
331
    arg_cache->in_marshaller = _pygi_marshal_in_uint8;
332 333
}

334 335 336 337 338 339 340 341
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)
342
{
343
    arg_cache->in_marshaller = _pygi_marshal_in_int16;
344 345
}

346 347 348 349 350 351 352 353
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)
354
{
355
    arg_cache->in_marshaller = _pygi_marshal_in_uint16;
356 357
}

358 359 360 361 362 363 364 365
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)
366
{
367
    arg_cache->in_marshaller = _pygi_marshal_in_int32;
368 369
}

370 371 372 373 374 375 376 377
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)
378
{
379
    arg_cache->in_marshaller = _pygi_marshal_in_uint32;
380 381
}

382 383 384 385 386 387 388 389
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)
390
{
391
    arg_cache->in_marshaller = _pygi_marshal_in_int64;
392 393
}

394 395 396 397 398 399 400 401
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)
402
{
403
    arg_cache->in_marshaller = _pygi_marshal_in_uint64;
404 405
}

406 407 408 409 410 411 412 413
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)
414
{
415
    arg_cache->in_marshaller = _pygi_marshal_in_float;
416 417
}

418 419 420 421 422 423 424 425
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)
426
{
427
    arg_cache->in_marshaller = _pygi_marshal_in_double;
428 429
}

430 431 432 433 434 435 436 437
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)
438
{
439
    arg_cache->in_marshaller = _pygi_marshal_in_unichar;
440 441
}

442 443 444 445 446 447 448 449
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)
450
{
451
    arg_cache->in_marshaller = _pygi_marshal_in_gtype;
452 453
}

454 455 456 457 458 459 460 461 462
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)
463
{
464
    arg_cache->in_marshaller = _pygi_marshal_in_utf8;
465
}
466

467 468 469 470 471
static inline void
_arg_cache_out_utf8_setup(PyGIArgCache *arg_cache,
                          GITransfer transfer)
{
    arg_cache->out_marshaller = _pygi_marshal_out_utf8;
472 473
}

474 475 476
static inline void
_arg_cache_in_filename_setup(PyGIArgCache *arg_cache,
                             GITransfer transfer)
477
{
478
    arg_cache->in_marshaller = _pygi_marshal_in_filename;
479 480
}

481 482 483
static inline void
_arg_cache_out_filename_setup(PyGIArgCache *arg_cache,
                              GITransfer transfer)
484
{
485 486
    arg_cache->out_marshaller = _pygi_marshal_out_filename;
}
487

488 489 490 491
static inline gboolean
_arg_cache_in_array_setup(PyGIArgCache *arg_cache,
                          PyGIFunctionCache *function_cache,
                          GITypeInfo *type_info,
492 493
                          GITransfer transfer,
                          GIDirection direction)
494
{
John (J5) Palmieri's avatar
John (J5) Palmieri committed
495
    PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
496 497
    seq_cache->array_type = g_type_info_get_array_type(type_info);

498 499
    if (seq_cache->len_arg_index >= 0) {
        PyGIArgCache *aux_cache = _arg_cache_new();
John (J5) Palmieri's avatar
John (J5) Palmieri committed
500
        aux_cache->aux_type = PYGI_AUX_TYPE_IGNORE;
501
        aux_cache->direction = direction;
502 503 504 505 506 507 508 509 510
        if (function_cache->args_cache[seq_cache->len_arg_index] != NULL) {
            PyGIArgCache *invalid_cache = function_cache->args_cache[seq_cache->len_arg_index];
            arg_cache->c_arg_index = invalid_cache->c_arg_index;
            _pygi_arg_cache_free(invalid_cache);
        }

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

511
    arg_cache->in_marshaller = _pygi_marshal_in_array;
512 513

    /* arg_cache->cleanup = _pygi_cleanup_array; */
514 515
}

516 517 518 519
static inline gboolean
_arg_cache_out_array_setup(PyGIArgCache *arg_cache,
                           PyGIFunctionCache *function_cache,
                           GITypeInfo *type_info,
520 521
                           GITransfer transfer,
                           gssize arg_index)
522
{
John (J5) Palmieri's avatar
John (J5) Palmieri committed
523
    PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
524 525 526 527 528 529
    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];
530 531 532 533
        if (seq_cache->len_arg_index < arg_index)
             function_cache->n_out_aux_args++;

        if (aux_cache == NULL) {
534
            aux_cache = _arg_cache_new();
535
        } else if (aux_cache->aux_type == PYGI_AUX_TYPE_IGNORE) {
536
            return TRUE;
537
        }
538 539 540 541 542 543 544 545

        aux_cache->aux_type = PYGI_AUX_TYPE_IGNORE;
        if (function_cache->args_cache[seq_cache->len_arg_index] != NULL) {
            PyGIArgCache *invalid_cache = function_cache->args_cache[seq_cache->len_arg_index];
            arg_cache->c_arg_index = invalid_cache->c_arg_index;
            _pygi_arg_cache_free(invalid_cache);
        }

546 547 548
        if (aux_cache->direction != GI_DIRECTION_INOUT)
            aux_cache->direction = GI_DIRECTION_OUT;

549 550 551 552 553 554 555 556 557 558
        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)
559
{
560
    arg_cache->in_marshaller = _pygi_marshal_in_glist;
561
    /* arg_cache->cleanup = */
562
}
563

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

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

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

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

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

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

607 608 609 610 611 612 613 614 615 616
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)
617
{
John (J5) Palmieri's avatar
John (J5) Palmieri committed
618
    arg_cache->in_marshaller = _pygi_marshal_in_interface_struct;
619 620 621 622 623 624 625
}

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

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

633 634 635 636
static inline void
_arg_cache_in_interface_struct_setup(PyGIArgCache *arg_cache,
                                     GIInterfaceInfo *iface_info,
                                     GITransfer transfer)
637
{
638
    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
639 640 641 642 643 644
    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;
645
}
646

647 648 649 650 651 652 653 654
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;
655 656
}

657 658 659
static inline void
_arg_cache_in_interface_object_setup(PyGIArgCache *arg_cache,
                                     GITransfer transfer)
660 661 662 663 664 665
{
    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
666
static inline void
667
_arg_cache_out_interface_object_setup(PyGIArgCache *arg_cache,
668
                                      GITransfer transfer)
669
{
670 671 672 673 674 675 676
    arg_cache->out_marshaller = _pygi_marshal_out_interface_object;
}

static inline void
_arg_cache_in_interface_boxed_setup(PyGIArgCache *arg_cache,
                                    GITransfer transfer)
{
677
    arg_cache->in_marshaller = _pygi_marshal_in_interface_boxed;
678 679
}

680 681 682 683 684 685 686 687 688 689
static inline void
_arg_cache_out_interface_boxed_setup(PyGIArgCache *arg_cache,
                                     GITransfer transfer)
{
    arg_cache->out_marshaller = _pygi_marshal_out_interface_struct;
}

static inline void
_arg_cache_in_interface_callback_setup(PyGIArgCache *arg_cache,
                                       PyGIFunctionCache *function_cache)
John (J5) Palmieri's avatar
John (J5) Palmieri committed
690
{
691
    PyGICallbackCache *callback_cache = (PyGICallbackCache *)arg_cache;
John (J5) Palmieri's avatar
John (J5) Palmieri committed
692 693 694 695 696
    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;
    }
697 698

    if (callback_cache->destroy_notify_index >= 0) {
John (J5) Palmieri's avatar
John (J5) Palmieri committed
699 700 701 702 703
        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;
704 705
}

John (J5) Palmieri's avatar
John (J5) Palmieri committed
706
static inline void
707
_arg_cache_out_interface_callback_setup(void)
708
{
709 710 711
    PyErr_Format(PyExc_NotImplementedError,
                 "Callback returns are not supported");
}
712

John (J5) Palmieri's avatar
John (J5) Palmieri committed
713
static inline void
714 715 716
_arg_cache_in_interface_enum_setup(PyGIArgCache *arg_cache,
                                   GITransfer transfer)
{
717
    arg_cache->in_marshaller = _pygi_marshal_in_interface_enum;
718 719
}

720 721 722
static inline void
_arg_cache_out_interface_enum_setup(PyGIArgCache *arg_cache,
                                    GITransfer transfer)
723
{
724 725
    arg_cache->out_marshaller = _pygi_marshal_out_interface_enum;
}
726

John (J5) Palmieri's avatar
John (J5) Palmieri committed
727
static inline void
728 729 730
_arg_cache_in_interface_flags_setup(PyGIArgCache *arg_cache,
                                    GITransfer transfer)
{
731
    arg_cache->in_marshaller = _pygi_marshal_in_interface_flags;
732 733
}

734 735 736
static inline void
_arg_cache_out_interface_flags_setup(PyGIArgCache *arg_cache,
                                     GITransfer transfer)
737
{
738 739 740 741 742 743 744 745 746 747 748 749 750 751
    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;
752 753
    PyGIArgCache *arg_cache = NULL;

754 755 756 757 758 759 760 761 762
    /* 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;
    }

763 764
    switch (info_type) {
        case GI_INFO_TYPE_UNION:
765 766 767 768 769 770
            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);

771 772
            break;
        case GI_INFO_TYPE_STRUCT:
773 774
            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
775
                                                    iface_info,
776 777 778 779 780 781 782
                                                    transfer);

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

783 784 785
            break;
        case GI_INFO_TYPE_OBJECT:
        case GI_INFO_TYPE_INTERFACE:
786 787 788 789 790 791
            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);

792 793
            break;
        case GI_INFO_TYPE_BOXED:
794 795 796 797 798 799
            if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
               _arg_cache_in_interface_boxed_setup(arg_cache, transfer);

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

800 801
            break;
        case GI_INFO_TYPE_CALLBACK:
802 803 804 805 806 807 808 809
            {
                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
810
                callback_cache =
811 812 813 814 815 816 817 818 819 820 821 822 823
                    _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;
            }
824
        case GI_INFO_TYPE_ENUM:
825 826 827 828 829 830
            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);

831 832
            break;
        case GI_INFO_TYPE_FLAGS:
833 834 835 836 837 838
            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);

839 840 841 842 843 844 845 846 847 848 849
            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;
850

851 852 853 854
        if (iface_cache != NULL) {
            g_base_info_ref( (GIBaseInfo *)iface_info);
            iface_cache->interface_info = iface_info;
        }
855
    }
856 857

    return arg_cache;
858 859
}

860 861 862 863 864 865 866 867 868 869
PyGIArgCache *
_arg_cache_new_from_type_info (GITypeInfo *type_info,
                               PyGIFunctionCache *function_cache,
                               GIArgInfo *arg_info,
                               GITypeTag type_tag,
                               GITransfer transfer,
                               GIDirection direction,
                               gboolean is_caller_allocates,
                               gint c_arg_index,
                               gint py_arg_index)
870
{
871
    PyGIArgCache *arg_cache = NULL;
872

873 874 875 876 877
    switch (type_tag) {
       case GI_TYPE_TAG_VOID:
           arg_cache = _arg_cache_new();
           if (arg_cache == NULL)
               break;
878

879 880
           if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
               _arg_cache_in_void_setup(arg_cache);
881

882 883 884 885 886 887 888
           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;
889

890 891
           if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
               _arg_cache_in_boolean_setup(arg_cache);
892

893 894
           if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
               _arg_cache_out_boolean_setup(arg_cache);
895

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

902 903
           if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
               _arg_cache_in_int8_setup(arg_cache);
904

905 906
           if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
               _arg_cache_out_int8_setup(arg_cache);
907

908 909 910 911 912
           break;
       case GI_TYPE_TAG_UINT8:
           arg_cache = _arg_cache_new();
           if (arg_cache == NULL)
               break;
913

914 915
           if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
               _arg_cache_in_uint8_setup(arg_cache);
916

917 918
           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
919

920 921 922 923 924
           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
925

926 927
           if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
               _arg_cache_in_int16_setup(arg_cache);
928

929 930
           if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
               _arg_cache_out_int16_setup(arg_cache);
931

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

938 939
           if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
               _arg_cache_in_uint16_setup(arg_cache);
940

941 942
           if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
               _arg_cache_out_uint16_setup(arg_cache);
943

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

950 951
           if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
               _arg_cache_in_int32_setup(arg_cache);
952

953 954
           if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
               _arg_cache_out_int32_setup(arg_cache);
955

956 957 958 959 960
           break;
       case GI_TYPE_TAG_UINT32:
           arg_cache = _arg_cache_new();
           if (arg_cache == NULL)
               break;
961

962 963
           if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
               _arg_cache_in_uint32_setup(arg_cache);
964

965 966
           if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
               _arg_cache_out_uint32_setup(arg_cache);