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

25 26 27 28 29 30 31
PyGIArgCache * _arg_cache_in_new_from_type_info (GITypeInfo *type_info,
                                  PyGIFunctionCache *function_cache,
                                  GITypeTag type_tag,
                                  GITransfer transfer,
                                  GIDirection direction,
                                  gint c_arg_index,
                                  gint py_arg_index);
32 33
/* cleanup */
static inline void
34
_interface_cache_free_func (PyGIInterfaceCache *cache)
35 36 37 38 39 40 41 42 43 44 45 46 47 48
{
    if (cache != NULL) {
        Py_XDECREF(cache->py_type);
        g_slice_free(PyGIInterfaceCache, cache);
    }
}

static inline void
_pygi_hash_cache_free (PyGIHashCache *cache)
{
    if (cache != NULL)
        g_slice_free(PyGIHashCache, cache);
}

49 50
static void
_sequence_cache_free_func (PyGISequenceCache *cache)
51 52 53 54 55
{
    if (cache != NULL)
        g_slice_free(PyGISequenceCache, cache);
}

56 57
static void
_callback_cache_free_func (PyGICallbackCache *cache)
58 59 60 61 62 63
{
    if (cache != NULL)
        g_slice_free(PyGICallbackCache, cache);
}

void
64
_pygi_arg_cache_free (PyGIArgCache *cache)
65
{
66 67 68 69 70
    if (cache == NULL)
        return;

    if (cache->arg_info != NULL)
        g_base_info_unref(cache->arg_info);
71 72 73 74
    if (cache->destroy_notify)
        cache->destroy_notify(cache);
    else
        g_slice_free(PyGIArgCache, cache);
75 76 77 78 79 80 81
}

void
_pygi_function_cache_free (PyGIFunctionCache *cache)
{
    int i;

82 83 84
    if (cache == NULL)
        return;

85 86 87 88
    g_slist_free(cache->in_args);
    g_slist_free(cache->out_args);
    for (i = 0; i < cache->n_args; i++) {
        PyGIArgCache *tmp = cache->args_cache[i];
89
        _pygi_arg_cache_free(tmp);
90
    }
91
    g_slice_free1(cache->n_args * sizeof(PyGIArgCache *), cache->args_cache);
92 93 94 95 96
    g_slice_free(PyGIFunctionCache, cache);
}

/* cache generation */
static inline PyGIFunctionCache *
97
_function_cache_new_from_function_info(GIFunctionInfo *function_info)
98 99 100 101 102 103 104 105 106
{
    PyGIFunctionCache *fc;
    GIFunctionInfoFlags flags;

    fc = g_slice_new0(PyGIFunctionCache);
    flags = g_function_info_get_flags(function_info);
    fc->is_method = flags & GI_FUNCTION_IS_METHOD;
    fc->is_constructor = flags & GI_FUNCTION_IS_CONSTRUCTOR;
    fc->n_args = g_callable_info_get_n_args ( (GICallableInfo *) function_info);
107 108
    if (fc->n_args > 0)
        fc->args_cache = g_slice_alloc0(fc->n_args * sizeof(PyGIArgCache *));
109 110 111 112

    return fc;
}

113
static inline PyGISequenceCache *
114 115 116 117
_sequence_cache_new_from_type_info(GITypeInfo *type_info)
{
    PyGISequenceCache *sc;
    GITypeInfo *item_type_info;
118
    GITypeTag item_type_tag;
119 120 121 122 123 124

    sc = g_slice_new0(PyGISequenceCache);

    sc->fixed_size = -1;
    sc->len_arg_index = -1;
    sc->is_zero_terminated = g_type_info_is_zero_terminated(type_info);
125
    if (!sc->is_zero_terminated)
126 127
        sc->fixed_size = g_type_info_get_array_fixed_size(type_info);
    if (sc->fixed_size < 0)
128 129
        sc->len_arg_index = g_type_info_get_array_length (type_info);

130
    item_type_info = g_type_info_get_param_type (type_info, 0);
131
    item_type_tag = g_type_info_get_tag (item_type_info);
132

133 134 135 136 137 138 139 140
    /* FIXME: support out also */
    sc->item_cache = _arg_cache_in_new_from_type_info(item_type_info,
                                                      NULL,
                                                      item_type_tag,
                                                      GI_TRANSFER_EVERYTHING,
                                                      GI_DIRECTION_IN,
                                                      0, 0);

141 142 143 144 145 146
    if (sc->item_cache == NULL) {
        _pygi_arg_cache_free((PyGIArgCache *)sc);
        return NULL;
    }
   
    sc->item_cache->type_tag = item_type_tag;    
147
    g_base_info_unref( (GIBaseInfo *) item_type_info);
148

149
    ((PyGIArgCache *)sc)->destroy_notify = (GDestroyNotify)_sequence_cache_free_func;
150 151

    return sc;
152 153
}

154 155 156 157 158
static inline PyGIArgCache *
_arg_cache_new(void)
{
    return g_slice_new0(PyGIArgCache);
}
159 160
/* process in args */

161 162
static inline PyGIArgCache *
_arg_cache_new_for_in_void(void)
163
{
164
     PyGIArgCache *arg_cache = _arg_cache_new();
165
     arg_cache->in_marshaller = _pygi_marshal_in_void;
166

167
     return arg_cache;
168 169
}

170 171
static inline PyGIArgCache *
_arg_cache_new_for_in_boolean(void)
172
{
173
    PyGIArgCache *arg_cache = _arg_cache_new();
174
    arg_cache->in_marshaller = _pygi_marshal_in_boolean;
175
    return arg_cache;
176 177
}

178 179
static inline PyGIArgCache *
_arg_cache_new_for_in_int8(void)
180
{
181
    PyGIArgCache *arg_cache = _arg_cache_new();
182
    arg_cache->in_marshaller = _pygi_marshal_in_int8;
183
    return arg_cache;
184 185
}

186 187
static inline PyGIArgCache *
_arg_cache_new_for_in_uint8(void)
188
{
189
    PyGIArgCache *arg_cache = _arg_cache_new();
190
    arg_cache->in_marshaller = _pygi_marshal_in_uint8;
191
    return arg_cache;
192 193
}

194 195
static inline PyGIArgCache *
_arg_cache_new_for_in_int16(void)
196
{
197
    PyGIArgCache *arg_cache = _arg_cache_new();
198
    arg_cache->in_marshaller = _pygi_marshal_in_int16;
199
    return arg_cache;
200 201
}

202 203
static inline PyGIArgCache *
_arg_cache_new_for_in_uint16(void)
204
{
205
    PyGIArgCache *arg_cache = _arg_cache_new();
206
    arg_cache->in_marshaller = _pygi_marshal_in_uint16;
207
    return arg_cache;
208 209
}

210 211
static inline PyGIArgCache *
_arg_cache_new_for_in_int32(void)
212
{
213
    PyGIArgCache *arg_cache = _arg_cache_new();
214
    arg_cache->in_marshaller = _pygi_marshal_in_int32;
215
    return arg_cache;
216 217
}

218 219
static inline PyGIArgCache *
_arg_cache_new_for_in_uint32(void)
220
{
221
    PyGIArgCache *arg_cache = _arg_cache_new();
222
    arg_cache->in_marshaller = _pygi_marshal_in_uint32;
223
    return arg_cache;
224 225
}

226 227
static inline PyGIArgCache *
_arg_cache_new_for_in_int64(void)
228
{
229
    PyGIArgCache *arg_cache = _arg_cache_new();
230
    arg_cache->in_marshaller = _pygi_marshal_in_int64;
231
    return arg_cache;
232 233
}

234 235
static inline PyGIArgCache *
_arg_cache_new_for_in_uint64(void)
236
{
237
    PyGIArgCache *arg_cache = _arg_cache_new();
238
    arg_cache->in_marshaller = _pygi_marshal_in_uint64;
239
    return arg_cache;
240 241
}

242 243
static inline PyGIArgCache *
_arg_cache_new_for_in_float(void)
244
{
245
    PyGIArgCache *arg_cache = _arg_cache_new();
246
    arg_cache->in_marshaller = _pygi_marshal_in_float;
247
    return arg_cache;
248 249
}

250 251
static inline PyGIArgCache *
_arg_cache_new_for_in_double(void)
252
{
253
    PyGIArgCache *arg_cache = _arg_cache_new();
254
    arg_cache->in_marshaller = _pygi_marshal_in_double;
255
    return arg_cache;
256 257
}

258 259
static inline PyGIArgCache *
_arg_cache_new_for_in_unichar(void)
260
{
261
    PyGIArgCache *arg_cache = _arg_cache_new();
262
    arg_cache->in_marshaller = _pygi_marshal_in_unichar;
263
    return arg_cache;
264 265
}

266 267
static inline PyGIArgCache *
_arg_cache_new_for_in_gtype(void)
268
{
269
    PyGIArgCache *arg_cache = _arg_cache_new();
270
    arg_cache->in_marshaller = _pygi_marshal_in_gtype;
271
    return arg_cache;
272 273
}

274 275
static inline PyGIArgCache *
_arg_cache_new_for_in_utf8(GITransfer transfer)
276
{
277
    PyGIArgCache *arg_cache = _arg_cache_new();
278
    arg_cache->in_marshaller = _pygi_marshal_in_utf8;
279 280 281
    if (arg_cache->transfer == GI_TRANSFER_NOTHING)
        arg_cache->cleanup = g_free;

282
    return arg_cache;
283 284
}

285 286
static inline PyGIArgCache *
_arg_cache_new_for_in_filename(GITransfer transfer)
287
{
288
    PyGIArgCache *arg_cache = _arg_cache_new();
289
    arg_cache->in_marshaller = _pygi_marshal_in_filename;
290 291 292
    if (arg_cache->transfer == GI_TRANSFER_NOTHING)
        arg_cache->cleanup = g_free;

293
    return arg_cache;
294 295
}

296 297 298
static inline PyGIArgCache *
_arg_cache_new_for_in_array(GITypeInfo *type_info,
                                      GITransfer transfer)
299
{
300
    PyGIArgCache *arg_cache = (PyGIArgCache *)_sequence_cache_new_from_type_info(type_info);
301
    arg_cache->in_marshaller = _pygi_marshal_in_array;
302 303

    /* arg_cache->cleanup = _pygi_cleanup_array; */
304
    return arg_cache;
305 306
}

307 308
static inline PyGIArgCache *
_arg_cache_new_for_in_interface(void)
309
{
310
    PyGIArgCache *arg_cache = NULL;
311 312 313
    /* TODO: Switch on GI_INFO_TYPE_ to determine caching */
    PyErr_Format(PyExc_NotImplementedError,
                 "Caching for this type is not fully implemented yet");
314
    return arg_cache;
315 316
}

317 318 319
static inline PyGIArgCache *
_arg_cache_new_for_in_glist(GITypeInfo *type_info,
                                      GITransfer transfer)
320
{
321
    PyGIArgCache *arg_cache = (PyGIArgCache *)_sequence_cache_new_from_type_info(type_info);
322
    arg_cache->in_marshaller = _pygi_marshal_in_glist;
323 324
    /* arg_cache->cleanup = */

325
    return arg_cache;
326 327
}

328 329 330
static inline PyGIArgCache *
_arg_cache_new_for_in_gslist(GITypeInfo *type_info,
                                       GITransfer transfer)
331
{
332
    PyGIArgCache *arg_cache = (PyGIArgCache *)_sequence_cache_new_from_type_info(type_info);
333
    arg_cache->in_marshaller = _pygi_marshal_in_gslist;
334 335
    /* arg_cache->cleanup = */

336
    return arg_cache;
337 338
}

339 340
static inline PyGIArgCache *
_arg_cache_new_for_in_ghash(GITypeInfo *type_info)
341
{
342 343
    PyGIArgCache *arg_cache = NULL;
    /*arg_cache->in_marshaller = _pygi_marshal_in_ghash;*/
344 345
    PyErr_Format(PyExc_NotImplementedError,
                 "Caching for this type is not fully implemented yet");
346
    return arg_cache;
347 348
}

349 350
static inline PyGIArgCache *
_arg_cache_new_for_in_gerror(void)
351
{
352
    PyGIArgCache *arg_cache = _arg_cache_new();
353
    arg_cache->in_marshaller = _pygi_marshal_in_gerror;
354
    arg_cache->is_aux = TRUE;
355
    return arg_cache;
356 357
}

358 359 360 361 362 363 364 365
PyGIArgCache *
_arg_cache_in_new_from_type_info (GITypeInfo *type_info,
                                  PyGIFunctionCache *function_cache,
                                  GITypeTag type_tag,
                                  GITransfer transfer,
                                  GIDirection direction,
                                  gint c_arg_index,
                                  gint py_arg_index)
366
{
367
    PyGIArgCache *arg_cache = NULL;
368 369 370

    switch (type_tag) {
       case GI_TYPE_TAG_VOID:
371
           arg_cache = _arg_cache_new_for_in_void();
372 373
           break;
       case GI_TYPE_TAG_BOOLEAN:
374
           arg_cache = _arg_cache_new_for_in_boolean();
375 376
           break;
       case GI_TYPE_TAG_INT8:
377
           arg_cache = _arg_cache_new_for_in_int8();
378 379
           break;
       case GI_TYPE_TAG_UINT8:
380
           arg_cache = _arg_cache_new_for_in_uint8();
381 382
           break;
       case GI_TYPE_TAG_INT16:
383
           arg_cache = _arg_cache_new_for_in_uint16();
384 385
           break;
       case GI_TYPE_TAG_UINT16:
386
           arg_cache = _arg_cache_new_for_in_uint16();
387 388
           break;
       case GI_TYPE_TAG_INT32:
389
           arg_cache = _arg_cache_new_for_in_int32();
390 391
           break;
       case GI_TYPE_TAG_UINT32:
392
           arg_cache = _arg_cache_new_for_in_uint32();
393 394
           break;
       case GI_TYPE_TAG_INT64:
395
           arg_cache = _arg_cache_new_for_in_int64();
396 397
           break;
       case GI_TYPE_TAG_UINT64:
398
           arg_cache = _arg_cache_new_for_in_uint64();
399 400
           break;
       case GI_TYPE_TAG_FLOAT:
401
           arg_cache = _arg_cache_new_for_in_float();
402 403
           break;
       case GI_TYPE_TAG_DOUBLE:
404
           arg_cache = _arg_cache_new_for_in_double();
405 406
           break;
       case GI_TYPE_TAG_UNICHAR:
407
           arg_cache = _arg_cache_new_for_in_unichar();
408 409
           break;
       case GI_TYPE_TAG_GTYPE:
410
           arg_cache = _arg_cache_new_for_in_gtype();
411 412
           break;
       case GI_TYPE_TAG_UTF8:
413
           arg_cache = _arg_cache_new_for_in_utf8(transfer);
414 415
           break;
       case GI_TYPE_TAG_FILENAME:
416
           arg_cache = _arg_cache_new_for_in_filename(transfer);
417 418
           break;
       case GI_TYPE_TAG_ARRAY:
419 420
           arg_cache = _arg_cache_new_for_in_array(type_info,
                                                   transfer);
421 422
           break;
       case GI_TYPE_TAG_INTERFACE:
423
           arg_cache = _arg_cache_new_for_in_interface();
424 425
           break;
       case GI_TYPE_TAG_GLIST:
426 427
           arg_cache = _arg_cache_new_for_in_glist(type_info,
                                                   transfer);
428 429
           break;
       case GI_TYPE_TAG_GSLIST:
430 431
           arg_cache = _arg_cache_new_for_in_gslist(type_info,
                                                    transfer);
432 433
           break;
       case GI_TYPE_TAG_GHASH:
434
           arg_cache = _arg_cache_new_for_in_ghash(type_info);
435 436
           break;
       case GI_TYPE_TAG_ERROR:
437
           arg_cache = _arg_cache_new_for_in_gerror();
438 439 440
           break;
    }

441 442 443 444 445 446 447 448 449
    if (arg_cache != NULL) {
        arg_cache->direction = direction;
        arg_cache->transfer = transfer;
        arg_cache->type_tag = type_tag;
        arg_cache->py_arg_index = py_arg_index;
        arg_cache->c_arg_index = c_arg_index;
    }

    return arg_cache;
450 451
}

452
static inline gboolean
John (J5) Palmieri's avatar
John (J5) Palmieri committed
453
_args_cache_generate(GIFunctionInfo *function_info,
454 455
                     PyGIFunctionCache *function_cache)
{
456 457
    int arg_index;
    for (arg_index = 0; arg_index < function_cache->n_args; arg_index++) {
458
        PyGIArgCache *arg_cache = NULL;
459
        GIArgInfo *arg_info;
460
        GITypeInfo *type_info;
461 462 463 464
        GIDirection direction;
        GITransfer transfer;
        GITypeTag type_tag;
        gint py_arg_index;
465 466

        /* must be an aux arg filled in by its owner so skip */
467
        if (function_cache->args_cache[arg_index] != NULL)
468 469
            continue;

John (J5) Palmieri's avatar
John (J5) Palmieri committed
470
        arg_info =
471
            g_callable_info_get_arg( (GICallableInfo *) function_info, arg_index);
472

473 474
        direction = g_arg_info_get_direction(arg_info);
        transfer = g_arg_info_get_ownership_transfer(arg_info);
475
        type_info = g_arg_info_get_type(arg_info);
476
        type_tag = g_type_info_get_tag(type_info);
477

478
        switch(direction) {
479
            case GI_DIRECTION_IN:
480
                py_arg_index = function_cache->n_in_args;
481
                function_cache->n_in_args++;
482

483 484 485 486 487 488 489 490
                arg_cache =
                    _arg_cache_in_new_from_type_info(type_info,
                                                     function_cache,
                                                     type_tag,
                                                     transfer,
                                                     direction,
                                                     arg_index,
                                                     py_arg_index);
491

492 493 494
                if (arg_cache == NULL)
                    goto arg_err;

495 496
                function_cache->in_args =
                    g_slist_append(function_cache->in_args, arg_cache);
497
                break;
498 499

            case GI_DIRECTION_OUT:
500
                function_cache->n_out_args++;
501 502 503 504 505 506 507 508 509 510
                PyErr_Format(PyExc_NotImplementedError,
                             "Out caching is not fully implemented yet");

                goto arg_err;

            case GI_DIRECTION_INOUT:
                PyErr_Format(PyExc_NotImplementedError,
                             "In/Out caching is not fully implemented yet");
                goto arg_err;

511
        }
512 513

        function_cache->args_cache[arg_index] = arg_cache;
514
        g_base_info_unref( (GIBaseInfo *) type_info);
515 516 517 518
        continue;
arg_err:
        g_base_info_unref( (GIBaseInfo *) type_info);
        return FALSE;
519
    }
520
    return TRUE;
521 522 523 524 525
}

PyGIFunctionCache *
_pygi_function_cache_new (GIFunctionInfo *function_info)
{
526
    PyGIFunctionCache *fc = _function_cache_new_from_function_info(function_info);
527 528 529
    if (fc == NULL)
        return NULL;

530 531 532
    if (!_args_cache_generate(function_info, fc))
        goto err;

533
    return fc;
534 535
err:
    _pygi_function_cache_free(fc);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
536
    return NULL;
537
}