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

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

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

PyGIArgCache * _arg_cache_new_for_interface (GIInterfaceInfo *iface_info,
40
                                             GITypeInfo *type_info,
41 42
                                             GIArgInfo *arg_info,
                                             GITransfer transfer,
43
                                             PyGIDirection direction,
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
                                             /* will be removed */
                                             PyGICallableCache *callable_cache);


/* _arg_info_default_value
 * info:
 * arg: (out): GIArgument to fill in with default value.
 *
 * This is currently a place holder API which only supports "allow-none" pointer args.
 * Once defaults are part of the GI API, we can replace this with: g_arg_info_default_value
 * https://bugzilla.gnome.org/show_bug.cgi?id=558620
 *
 * Returns: TRUE if the given argument supports a default value and was filled in.
 */
static gboolean
_arg_info_default_value (GIArgInfo *info, GIArgument *arg)
{
    if (g_arg_info_may_be_null (info)) {
        arg->v_pointer = NULL;
        return TRUE;
    }
    return FALSE;
}

gboolean
pygi_arg_base_setup (PyGIArgCache *arg_cache,
                     GITypeInfo   *type_info,
                     GIArgInfo    *arg_info,  /* may be NULL for return arguments */
                     GITransfer    transfer,
                     PyGIDirection direction)
{
    arg_cache->direction = direction;
    arg_cache->transfer = transfer;
    arg_cache->py_arg_index = -1;
    arg_cache->c_arg_index = -1;

    if (type_info != NULL) {
        arg_cache->is_pointer = g_type_info_is_pointer (type_info);
        arg_cache->type_tag = g_type_info_get_tag (type_info);
        g_base_info_ref ( (GIBaseInfo *) type_info);
        arg_cache->type_info = type_info;
    }

    if (arg_info != NULL) {
        if (!arg_cache->has_default) {
            /* It is possible has_default was set somewhere else */
            arg_cache->has_default = _arg_info_default_value (arg_info,
                                                              &arg_cache->default_value);
        }
        arg_cache->arg_name = g_base_info_get_name ((GIBaseInfo *) arg_info);
        arg_cache->allow_none = g_arg_info_may_be_null (arg_info);

        if (arg_cache->type_tag == GI_TYPE_TAG_INTERFACE || arg_cache->type_tag == GI_TYPE_TAG_ARRAY)
            arg_cache->is_caller_allocates = g_arg_info_is_caller_allocates (arg_info);
        else
            arg_cache->is_caller_allocates = FALSE;
    }
    return TRUE;
}


gboolean
pygi_arg_interface_setup (PyGIInterfaceCache *iface_cache,
                          GITypeInfo         *type_info,
                          GIArgInfo          *arg_info,    /* may be NULL for return arguments */
                          GITransfer          transfer,
                          PyGIDirection       direction,
                          GIInterfaceInfo    *iface_info)
{
    if (!pygi_arg_base_setup ((PyGIArgCache *)iface_cache,
                              type_info,
                              arg_info,
                              transfer,
                              direction)) {
        return FALSE;
    }

    g_base_info_ref ( (GIBaseInfo *)iface_info);
    iface_cache->interface_info = iface_info;
    iface_cache->arg_cache.type_tag = GI_TYPE_TAG_INTERFACE;

    return TRUE;
}

128

129
/* cleanup */
Martin Pitt's avatar
Martin Pitt committed
130
static void
131
_pygi_arg_cache_free (PyGIArgCache *cache)
John (J5) Palmieri's avatar
John (J5) Palmieri committed
132 133 134 135
{
    if (cache == NULL)
        return;

136
    if (cache->type_info != NULL)
137
        g_base_info_unref ( (GIBaseInfo *)cache->type_info);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
138
    if (cache->destroy_notify)
139
        cache->destroy_notify (cache);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
140
    else
141
        g_slice_free (PyGIArgCache, cache);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
142 143 144
}

static void
145
_interface_cache_free_func (PyGIInterfaceCache *cache)
146 147
{
    if (cache != NULL) {
148
        Py_XDECREF (cache->py_type);
149
        if (cache->type_name != NULL)
150
            g_free (cache->type_name);
151
        if (cache->interface_info != NULL)
152 153
            g_base_info_unref ( (GIBaseInfo *)cache->interface_info);
        g_slice_free (PyGIInterfaceCache, cache);
154 155 156
    }
}

John (J5) Palmieri's avatar
John (J5) Palmieri committed
157
static void
158
_hash_cache_free_func (PyGIHashCache *cache)
159
{
John (J5) Palmieri's avatar
John (J5) Palmieri committed
160
    if (cache != NULL) {
161 162 163
        _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
164
    }
165 166
}

167
static void
168
_sequence_cache_free_func (PyGISequenceCache *cache)
169
{
John (J5) Palmieri's avatar
John (J5) Palmieri committed
170
    if (cache != NULL) {
171 172
        _pygi_arg_cache_free (cache->item_cache);
        g_slice_free (PyGISequenceCache, cache);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
173
    }
174 175
}

176
static void
177
_callback_cache_free_func (PyGICallbackCache *cache)
178
{
179 180
    if (cache != NULL) {
        if (cache->interface_info != NULL)
181
            g_base_info_unref ( (GIBaseInfo *)cache->interface_info);
182

183
        g_slice_free (PyGICallbackCache, cache);
184
    }
185 186 187
}

void
188
_pygi_callable_cache_free (PyGICallableCache *cache)
189
{
190 191 192
    if (cache == NULL)
        return;

193
    g_slist_free (cache->to_py_args);
194 195
    g_slist_free (cache->arg_name_list);
    g_hash_table_destroy (cache->arg_name_hash);
196
    g_ptr_array_unref (cache->args_cache);
197

198
    if (cache->return_cache != NULL)
199
        _pygi_arg_cache_free (cache->return_cache);
200

201
    g_slice_free (PyGICallableCache, cache);
202 203 204 205
}

/* cache generation */

206 207
static PyGIInterfaceCache *
_interface_cache_new (GIInterfaceInfo *iface_info)
208 209
{
    PyGIInterfaceCache *ic;
John (J5) Palmieri's avatar
John (J5) Palmieri committed
210

211 212
    ic = g_slice_new0 (PyGIInterfaceCache);
    ( (PyGIArgCache *)ic)->destroy_notify = (GDestroyNotify)_interface_cache_free_func;
213
    ic->g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *)iface_info);
214
    ic->py_type = _pygi_type_import_by_gi_info ( (GIBaseInfo *) iface_info);
215 216 217 218

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

219
    ic->type_name = _pygi_g_base_info_get_fullname (iface_info);
220 221 222
    return ic;
}

223 224 225 226 227
static PyGISequenceCache *
_sequence_cache_new (GITypeInfo *type_info,
                     GIDirection direction,
                     GITransfer transfer,
                     gssize child_offset)
228 229 230
{
    PyGISequenceCache *sc;
    GITypeInfo *item_type_info;
231
    GITransfer item_transfer;
232

233 234
    sc = g_slice_new0 (PyGISequenceCache);
    ( (PyGIArgCache *)sc)->destroy_notify = (GDestroyNotify)_sequence_cache_free_func;
235

236
    sc->is_zero_terminated = g_type_info_is_zero_terminated (type_info);
237 238 239 240
    sc->fixed_size = g_type_info_get_array_fixed_size (type_info);
    sc->len_arg_index = g_type_info_get_array_length (type_info);
    if (sc->len_arg_index >= 0)
        sc->len_arg_index += child_offset;
241

242 243
    item_type_info = g_type_info_get_param_type (type_info, 0);

244 245
    item_transfer =
        transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
246

247 248 249 250
    sc->item_cache = _arg_cache_new (item_type_info,
                                     NULL,
                                     item_transfer,
                                     direction,
251 252
                                     0, 0,
                                     NULL);
253

254
    if (sc->item_cache == NULL) {
255
        _pygi_arg_cache_free ( (PyGIArgCache *)sc);
256 257
        return NULL;
    }
John (J5) Palmieri's avatar
John (J5) Palmieri committed
258

259 260
    sc->item_size = _pygi_g_type_info_size (item_type_info);
    g_base_info_unref ( (GIBaseInfo *)item_type_info);
261

262
    return sc;
263
}
264 265 266 267
static PyGIHashCache *
_hash_cache_new (GITypeInfo *type_info,
                 GIDirection direction,
                 GITransfer transfer)
John (J5) Palmieri's avatar
John (J5) Palmieri committed
268 269 270 271
{
    PyGIHashCache *hc;
    GITypeInfo *key_type_info;
    GITypeInfo *value_type_info;
272
    GITransfer item_transfer;
John (J5) Palmieri's avatar
John (J5) Palmieri committed
273

274 275
    hc = g_slice_new0 (PyGIHashCache);
    ( (PyGIArgCache *)hc)->destroy_notify = (GDestroyNotify)_hash_cache_free_func;
John (J5) Palmieri's avatar
John (J5) Palmieri committed
276 277 278
    key_type_info = g_type_info_get_param_type (type_info, 0);
    value_type_info = g_type_info_get_param_type (type_info, 1);

279 280
    item_transfer =
        transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
281

282 283 284 285
    hc->key_cache = _arg_cache_new (key_type_info,
                                    NULL,
                                    item_transfer,
                                    direction,
286 287
                                    0, 0,
                                    NULL);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
288 289

    if (hc->key_cache == NULL) {
290
        _pygi_arg_cache_free ( (PyGIArgCache *)hc);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
291 292 293
        return NULL;
    }

294 295 296 297
    hc->value_cache = _arg_cache_new (value_type_info,
                                      NULL,
                                      item_transfer,
                                      direction,
298 299
                                      0, 0,
                                      NULL);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
300 301

    if (hc->value_cache == NULL) {
302
        _pygi_arg_cache_free ( (PyGIArgCache *)hc);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
303 304 305 306 307 308 309 310
        return NULL;
    }

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

    return hc;
}
311

312 313 314 315
static PyGICallbackCache *
_callback_cache_new (GIArgInfo *arg_info,
                     GIInterfaceInfo *iface_info,
                     gssize child_offset)
John (J5) Palmieri's avatar
John (J5) Palmieri committed
316 317 318
{
   PyGICallbackCache *cc;

319
   cc = g_slice_new0 (PyGICallbackCache);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
320 321
   ( (PyGIArgCache *)cc)->destroy_notify = (GDestroyNotify)_callback_cache_free_func;

322
   cc->user_data_index = g_arg_info_get_closure (arg_info);
323
   if (cc->user_data_index != -1)
324
       cc->user_data_index += child_offset;
325
   cc->destroy_notify_index = g_arg_info_get_destroy (arg_info);
326
   if (cc->destroy_notify_index != -1)
327
       cc->destroy_notify_index += child_offset;
328
   cc->scope = g_arg_info_get_scope (arg_info);
329 330
   g_base_info_ref( (GIBaseInfo *)iface_info);
   cc->interface_info = iface_info;
John (J5) Palmieri's avatar
John (J5) Palmieri committed
331 332 333
   return cc;
}

334 335
static PyGIArgCache *
_arg_cache_alloc (void)
336
{
337
    return g_slice_new0 (PyGIArgCache);
338
}
339

340 341 342 343 344 345
static void
_arg_cache_from_py_basic_type_setup (PyGIArgCache *arg_cache)
{
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_basic_type_cache_adapter;
}

346 347 348
static void
_arg_cache_to_py_basic_type_setup (PyGIArgCache *arg_cache)
{
349
    arg_cache->to_py_marshaller = _pygi_marshal_to_py_basic_type_cache_adapter;
350 351
}

352
static void
353
_arg_cache_from_py_void_setup (PyGIArgCache *arg_cache)
354
{
355
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_void;
356
}
357

358
static void
359
_arg_cache_to_py_void_setup (PyGIArgCache *arg_cache)
360
{
361
    arg_cache->to_py_marshaller = _pygi_marshal_to_py_void;
362 363
}

364
static void
365 366
_arg_cache_from_py_utf8_setup (PyGIArgCache *arg_cache,
                               GITransfer transfer)
367
{
368
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_basic_type_cache_adapter;
369
    arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_utf8;
370
}
371

372
static void
373 374
_arg_cache_to_py_utf8_setup (PyGIArgCache *arg_cache,
                               GITransfer transfer)
375
{
376
    arg_cache->to_py_marshaller = _pygi_marshal_to_py_basic_type_cache_adapter;
377
    arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_utf8;
378 379
}

380 381
static PyGIArgCache*
_arg_cache_array_len_arg_setup (PyGIArgCache *arg_cache,
382
                                PyGICallableCache *callable_cache,
383
                                PyGIDirection direction,
384 385
                                gssize arg_index,
                                gssize *py_arg_index)
386
{
John (J5) Palmieri's avatar
John (J5) Palmieri committed
387
    PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
388
    if (seq_cache->len_arg_index >= 0) {
389
        PyGIArgCache *child_cache = NULL;
390

391 392
        child_cache = _pygi_callable_cache_get_arg (callable_cache,
                                                    seq_cache->len_arg_index);
393
        if (child_cache == NULL) {
394
            child_cache = _arg_cache_alloc ();
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
        } else {
            /* If the "length" arg cache already exists (the length comes before
             * the array in the argument list), remove it from the to_py_args list
             * because it does not belong in "to python" return tuple. The length
             * will implicitly be a part of the returned Python list.
             */
            if (direction & PYGI_DIRECTION_TO_PYTHON) {
                callable_cache->to_py_args =
                    g_slist_remove (callable_cache->to_py_args, child_cache);
            }

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

414 415 416 417 418
        /* There is a length argument for this array, so increment the number
         * of "to python" child arguments when applicable.
         */
        if (direction & PYGI_DIRECTION_TO_PYTHON)
             callable_cache->n_to_py_child_args++;
419

420
        child_cache->meta_type = PYGI_META_ARG_TYPE_CHILD;
421
        child_cache->direction = direction;
422 423
        child_cache->to_py_marshaller = NULL;
        child_cache->from_py_marshaller = NULL;
424

425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
        /* ugly edge case code:
         *
         * When the length comes before the array parameter we need to update
         * indexes of arguments after the index argument.
         */
        if (seq_cache->len_arg_index < arg_index && direction & PYGI_DIRECTION_FROM_PYTHON) {
            gssize i;
            (*py_arg_index) -= 1;
            callable_cache->n_py_args -= 1;

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

                update_cache->py_arg_index -= 1;
            }
        }

445
        _pygi_callable_cache_set_arg (callable_cache, seq_cache->len_arg_index, child_cache);
446
        return child_cache;
447 448
    }

449 450
    return NULL;
}
451

452 453 454 455 456 457 458 459 460 461 462 463
static gboolean
_arg_cache_from_py_array_setup (PyGIArgCache *arg_cache,
                                PyGICallableCache *callable_cache,
                                GITypeInfo *type_info,
                                GITransfer transfer,
                                PyGIDirection direction,
                                gssize arg_index)
{
    PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
    seq_cache->array_type = g_type_info_get_array_type (type_info);
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_array;
    arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_array;
464
    return TRUE;
465 466
}

467
static gboolean
468 469 470 471 472 473
_arg_cache_to_py_array_setup (PyGIArgCache *arg_cache,
                              PyGICallableCache *callable_cache,
                              GITypeInfo *type_info,
                              GITransfer transfer,
                              PyGIDirection direction,
                              gssize arg_index)
474
{
John (J5) Palmieri's avatar
John (J5) Palmieri committed
475
    PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
476
    seq_cache->array_type = g_type_info_get_array_type (type_info);
477 478
    arg_cache->to_py_marshaller = _pygi_marshal_to_py_array;
    arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_array;
479 480 481
    return TRUE;
}

482
static void
483 484
_arg_cache_from_py_glist_setup (PyGIArgCache *arg_cache,
                                GITransfer transfer)
485
{
486 487
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_glist;
    arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_glist;
488
}
489

490
static void
491 492
_arg_cache_to_py_glist_setup (PyGIArgCache *arg_cache,
                              GITransfer transfer)
493
{
494 495
    arg_cache->to_py_marshaller = _pygi_marshal_to_py_glist;
    arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_glist;
496 497
}

498
static void
499 500
_arg_cache_from_py_gslist_setup (PyGIArgCache *arg_cache,
                                 GITransfer transfer)
501
{
502 503
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_gslist;
    arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_glist;
504
}
505

506
static void
507 508
_arg_cache_to_py_gslist_setup (PyGIArgCache *arg_cache,
                                 GITransfer transfer)
509
{
510 511
    arg_cache->to_py_marshaller = _pygi_marshal_to_py_gslist;
    arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_glist;
512 513
}

514
static void
515
_arg_cache_from_py_ghash_setup (PyGIArgCache *arg_cache)
516
{
517 518
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_ghash;
    arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_ghash;
519 520
}

521
static void
522
_arg_cache_to_py_ghash_setup (PyGIArgCache *arg_cache)
523
{
524 525
    arg_cache->to_py_marshaller = _pygi_marshal_to_py_ghash;
    arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_ghash;
526 527
}

528
static void
529
_arg_cache_from_py_gerror_setup (PyGIArgCache *arg_cache)
530
{
531
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_gerror;
532
    arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD;
533 534
}

535
static void
536
_arg_cache_to_py_gerror_setup (PyGIArgCache *arg_cache)
537
{
538
    arg_cache->to_py_marshaller = _pygi_marshal_to_py_gerror;
539
    arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD;
540 541
}

542
static void
543 544
_arg_cache_from_py_interface_union_setup (PyGIArgCache *arg_cache,
                                          GITransfer transfer)
545
{
546
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_struct_cache_adapter;
547 548
}

549
static void
550 551
_arg_cache_to_py_interface_union_setup (PyGIArgCache *arg_cache,
                                        GITransfer transfer)
552
{
553
    arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_struct_cache_adapter;
554 555
}

556
static void
557 558 559
_arg_cache_from_py_interface_struct_setup (PyGIArgCache *arg_cache,
                                           GIInterfaceInfo *iface_info,
                                           GITransfer transfer)
560
{
561
    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
562
    iface_cache->is_foreign = g_struct_info_is_foreign ( (GIStructInfo*)iface_info);
563
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_struct_cache_adapter;
564 565

    if (iface_cache->g_type == G_TYPE_VALUE)
566
        arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_struct_gvalue;
567
    else if (iface_cache->is_foreign)
568
        arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_struct_foreign;
569
}
570

571
static void
572 573 574
_arg_cache_to_py_interface_struct_setup (PyGIArgCache *arg_cache,
                                         GIInterfaceInfo *iface_info,
                                         GITransfer transfer)
575 576
{
    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
577
    iface_cache->is_foreign = g_struct_info_is_foreign ( (GIStructInfo*)iface_info);
578
    arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_struct_cache_adapter;
579 580

    if (iface_cache->is_foreign)
581
        arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_interface_struct_foreign;
582 583
}

584
static void
585 586
_arg_cache_from_py_interface_object_setup (PyGIArgCache *arg_cache,
                                           GITransfer transfer)
587
{
588 589
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_object;
    arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_object;
590 591
}

592
static void
593 594
_arg_cache_to_py_interface_object_setup (PyGIArgCache *arg_cache,
                                         GITransfer transfer)
595
{
596
    arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_object_cache_adapter;
597
    arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_interface_object;
598 599
}

600
static void
601 602
_arg_cache_from_py_interface_callback_setup (PyGIArgCache *arg_cache,
                                             PyGICallableCache *callable_cache)
John (J5) Palmieri's avatar
John (J5) Palmieri committed
603
{
604
    PyGICallbackCache *callback_cache = (PyGICallbackCache *)arg_cache;
John (J5) Palmieri's avatar
John (J5) Palmieri committed
605
    if (callback_cache->user_data_index >= 0) {
606
        PyGIArgCache *user_data_arg_cache = _arg_cache_alloc ();
607
        user_data_arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD_WITH_PYARG;
608
        user_data_arg_cache->direction = PYGI_DIRECTION_FROM_PYTHON;
609
        user_data_arg_cache->has_default = TRUE; /* always allow user data with a NULL default. */
610 611
        _pygi_callable_cache_set_arg (callable_cache, callback_cache->user_data_index,
                                      user_data_arg_cache);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
612
    }
613 614

    if (callback_cache->destroy_notify_index >= 0) {
615
        PyGIArgCache *destroy_arg_cache = _arg_cache_alloc ();
616
        destroy_arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD;
617
        destroy_arg_cache->direction = PYGI_DIRECTION_FROM_PYTHON;
618 619
        _pygi_callable_cache_set_arg (callable_cache, callback_cache->destroy_notify_index,
                                      destroy_arg_cache);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
620
    }
621
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_callback;
622
    arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_callback;
623 624
}

625
static void
626
_arg_cache_to_py_interface_callback_setup (void)
627
{
628 629 630
    PyErr_Format(PyExc_NotImplementedError,
                 "Callback returns are not supported");
}
631

632
static void
633 634
_arg_cache_from_py_interface_enum_setup (PyGIArgCache *arg_cache,
                                         GITransfer transfer)
635
{
636
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_enum;
637 638
}

639
static void
640 641
_arg_cache_to_py_interface_enum_setup (PyGIArgCache *arg_cache,
                                       GITransfer transfer)
642
{
643
    arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_enum;
644
}
645

646
static void
647 648
_arg_cache_from_py_interface_flags_setup (PyGIArgCache *arg_cache,
                                          GITransfer transfer)
649
{
650
    arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_flags;
651 652
}

653
static void
654 655
_arg_cache_to_py_interface_flags_setup (PyGIArgCache *arg_cache,
                                        GITransfer transfer)
656
{
657
    arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_flags;
658 659
}

660

661
PyGIArgCache *
662 663 664 665 666 667
_arg_cache_new_for_interface (GIInterfaceInfo   *iface_info,
                              GITypeInfo        *type_info,
                              GIArgInfo         *arg_info,
                              GITransfer         transfer,
                              PyGIDirection      direction,
                              PyGICallableCache *callable_cache)
668
{
669
    PyGIArgCache *arg_cache = NULL;
670
    gssize child_offset = 0;
671
    GIInfoType info_type;
672 673 674 675 676

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

678 679
    info_type = g_base_info_get_type ( (GIBaseInfo *)iface_info);

680
    /* Callbacks are special cased */
681 682
    if (info_type == GI_INFO_TYPE_CALLBACK) {
        PyGICallbackCache *callback_cache;
683

684 685 686 687 688 689 690 691 692 693 694
        if (direction & PYGI_DIRECTION_TO_PYTHON) {
            _arg_cache_to_py_interface_callback_setup ();
            return NULL;
        }

        callback_cache =
            _callback_cache_new (arg_info,
                                 iface_info,
                                 child_offset);

        arg_cache = (PyGIArgCache *)callback_cache;
695 696
        if (arg_cache == NULL)
            return NULL;
697 698 699 700 701 702 703 704 705 706 707 708

        pygi_arg_base_setup (arg_cache,
                             type_info,
                             arg_info,
                             transfer,
                             direction);

        if (direction & PYGI_DIRECTION_FROM_PYTHON)
            _arg_cache_from_py_interface_callback_setup (arg_cache, callable_cache);

        return arg_cache;

709 710
    }

711 712 713 714
    arg_cache = (PyGIArgCache *)_interface_cache_new (iface_info);
    if (arg_cache == NULL)
        return NULL;

715 716
    switch (info_type) {
        case GI_INFO_TYPE_UNION:
717
            if (direction & PYGI_DIRECTION_FROM_PYTHON)
718
               _arg_cache_from_py_interface_union_setup (arg_cache, transfer);
719

720
            if (direction & PYGI_DIRECTION_TO_PYTHON)
721
               _arg_cache_to_py_interface_union_setup (arg_cache, transfer);
722

723
            break;
724
        case GI_INFO_TYPE_BOXED:
725
        case GI_INFO_TYPE_STRUCT:
726
            if (direction & PYGI_DIRECTION_FROM_PYTHON)
727 728 729 730
               _arg_cache_from_py_interface_struct_setup (arg_cache,
                                                          iface_info,
                                                          transfer);

731
            if (direction & PYGI_DIRECTION_TO_PYTHON)
732 733 734
               _arg_cache_to_py_interface_struct_setup (arg_cache,
                                                        iface_info,
                                                        transfer);
735 736 737
            break;
        case GI_INFO_TYPE_OBJECT:
        case GI_INFO_TYPE_INTERFACE:
738
            if (direction & PYGI_DIRECTION_FROM_PYTHON)
739
               _arg_cache_from_py_interface_object_setup (arg_cache, transfer);
740

741
            if (direction & PYGI_DIRECTION_TO_PYTHON)
742
               _arg_cache_to_py_interface_object_setup (arg_cache, transfer);
743

744 745
            break;
        case GI_INFO_TYPE_ENUM:
746
            if (direction & PYGI_DIRECTION_FROM_PYTHON)
747
               _arg_cache_from_py_interface_enum_setup (arg_cache, transfer);
748

749
            if (direction & PYGI_DIRECTION_TO_PYTHON)
750
               _arg_cache_to_py_interface_enum_setup (arg_cache, transfer);
751

752 753
            break;
        case GI_INFO_TYPE_FLAGS:
754
            if (direction & PYGI_DIRECTION_FROM_PYTHON)
755
               _arg_cache_from_py_interface_flags_setup (arg_cache, transfer);
756

757
            if (direction & PYGI_DIRECTION_TO_PYTHON)
758
               _arg_cache_to_py_interface_flags_setup (arg_cache, transfer);
759

760 761
            break;
        default:
762
            g_assert_not_reached ();
763 764
    }

765 766 767 768 769 770
    pygi_arg_interface_setup ((PyGIInterfaceCache *)arg_cache,
                              type_info,
                              arg_info,
                              transfer,
                              direction,
                              iface_info);
771 772

    return arg_cache;
773 774
}

775
PyGIArgCache *
776
_arg_cache_new (GITypeInfo *type_info,
777
                GIArgInfo *arg_info,     /* may be null */
778
                GITransfer transfer,
779
                PyGIDirection direction,
780
                gssize c_arg_index,
781 782
                gssize py_arg_index,
                PyGICallableCache *callable_cache)
783
{
784
    PyGIArgCache *arg_cache = NULL;
785
    gssize child_offset = 0;
786
    GITypeTag type_tag;
787

788 789
    type_tag = g_type_info_get_tag (type_info);

790 791 792 793
    if (callable_cache != NULL)
        child_offset =
            (callable_cache->function_type == PYGI_FUNCTION_TYPE_METHOD ||
                callable_cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) ? 1: 0;
794

795 796
    switch (type_tag) {
       case GI_TYPE_TAG_VOID:
797
           arg_cache = _arg_cache_alloc ();
798 799
           if (arg_cache == NULL)
               break;
800

801
           if (direction & PYGI_DIRECTION_FROM_PYTHON)
John (J5) Palmieri's avatar