pygi-cache.c 15 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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
/* cleanup */
static inline void
_pygi_interface_cache_free (PyGIInterfaceCache *cache)
{
    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);
}

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

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

void
64
_pygi_arg_cache_free (PyGIArgCache *cache)
65 66
{
    g_base_info_unref(cache->arg_info);
67 68 69 70
    if (cache->destroy_notify)
        cache->destroy_notify(cache);
    else
        g_slice_free(PyGIArgCache, cache);
71 72 73 74 75 76 77 78 79 80 81 82
}

void
_pygi_function_cache_free (PyGIFunctionCache *cache)
{
    int i;

    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];
        _pygi_arg_cache_clear(tmp);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
83
        g_slice_free(PyGIArgCache, tmp);
84 85 86 87 88 89 90
    }

    g_slice_free(PyGIFunctionCache, cache);
}

/* cache generation */
static inline PyGIFunctionCache *
91
_function_cache_new_from_function_info(GIFunctionInfo *function_info)
92 93 94 95 96 97 98 99 100
{
    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);
101
    fc->args_cache = g_slice_alloc0(fc->n_args * sizeof(PyGIArgCache *));
102 103 104 105

    return fc;
}

106
static inline PyGISequenceCache *
107 108 109 110
_sequence_cache_new_from_type_info(GITypeInfo *type_info)
{
    PyGISequenceCache *sc;
    GITypeInfo *item_type_info;
111
    GITypeTag item_type_tag;
112 113 114 115 116 117

    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);
118
    if (!sc->is_zero_terminated)
119 120
        sc->fixed_size = g_type_info_get_array_fixed_size(type_info);
    if (sc->fixed_size < 0)
121 122
        sc->len_arg_index = g_type_info_get_array_length (type_info);

123
    item_type_info = g_type_info_get_param_type (type_info, 0);
124
    item_type_tag = g_type_info_get_tag (item_type_info);
125

126
    sc->item_cache->type_tag = item_type_tag;
127

128 129 130 131 132 133 134 135 136
    /* 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);

    g_base_info_unref( (GIBaseInfo *) item_type_info);
137

138
    ((PyGIArgCache *)sc)->destroy_notify = (GDestroyNotify)_pygi_sequence_cache_free;
139 140

    return sc;
141 142
}

143 144 145 146 147
static inline PyGIArgCache *
_arg_cache_new(void)
{
    return g_slice_new0(PyGIArgCache);
}
148 149
/* process in args */

150 151
static inline PyGIArgCache *
_arg_cache_new_for_in_void(void)
152
{
153
     PyGIArgCache *arg_cache = _arg_cache_new();
154
     arg_cache->in_marshaller = _pygi_marshal_in_void;
155

156
     return arg_cache;
157 158
}

159 160
static inline PyGIArgCache *
_arg_cache_new_for_in_boolean(void)
161
{
162
    PyGIArgCache *arg_cache = _arg_cache_new();
163
    arg_cache->in_marshaller = _pygi_marshal_in_boolean;
164
    return arg_cache;
165 166
}

167 168
static inline PyGIArgCache *
_arg_cache_new_for_in_int8(void)
169
{
170
    PyGIArgCache *arg_cache = _arg_cache_new();
171
    arg_cache->in_marshaller = _pygi_marshal_in_int8;
172
    return arg_cache;
173 174
}

175 176
static inline PyGIArgCache *
_arg_cache_new_for_in_uint8(void)
177
{
178
    PyGIArgCache *arg_cache = _arg_cache_new();
179
    arg_cache->in_marshaller = _pygi_marshal_in_uint8;
180
    return arg_cache;
181 182
}

183 184
static inline PyGIArgCache *
_arg_cache_new_for_in_int16(void)
185
{
186
    PyGIArgCache *arg_cache = _arg_cache_new();
187
    arg_cache->in_marshaller = _pygi_marshal_in_int16;
188
    return arg_cache;
189 190
}

191 192
static inline PyGIArgCache *
_arg_cache_new_for_in_uint16(void)
193
{
194
    PyGIArgCache *arg_cache = _arg_cache_new();
195
    arg_cache->in_marshaller = _pygi_marshal_in_uint16;
196
    return arg_cache;
197 198
}

199 200
static inline PyGIArgCache *
_arg_cache_new_for_in_int32(void)
201
{
202
    PyGIArgCache *arg_cache = _arg_cache_new();
203
    arg_cache->in_marshaller = _pygi_marshal_in_int32;
204
    return arg_cache;
205 206
}

207 208
static inline PyGIArgCache *
_arg_cache_new_for_in_uint32(void)
209
{
210
    PyGIArgCache *arg_cache = _arg_cache_new();
211
    arg_cache->in_marshaller = _pygi_marshal_in_uint32;
212
    return arg_cache;
213 214
}

215 216
static inline PyGIArgCache *
_arg_cache_new_for_in_int64(void)
217
{
218
    PyGIArgCache *arg_cache = _arg_cache_new();
219
    arg_cache->in_marshaller = _pygi_marshal_in_int64;
220
    return arg_cache;
221 222
}

223 224
static inline PyGIArgCache *
_arg_cache_new_for_in_uint64(void)
225
{
226
    PyGIArgCache *arg_cache = _arg_cache_new();
227
    arg_cache->in_marshaller = _pygi_marshal_in_uint64;
228
    return arg_cache;
229 230
}

231 232
static inline PyGIArgCache *
_arg_cache_new_for_in_float(void)
233
{
234
    PyGIArgCache *arg_cache = _arg_cache_new();
235
    arg_cache->in_marshaller = _pygi_marshal_in_float;
236
    return arg_cache;
237 238
}

239 240
static inline PyGIArgCache *
_arg_cache_new_for_in_double(void)
241
{
242
    PyGIArgCache *arg_cache = _arg_cache_new();
243
    arg_cache->in_marshaller = _pygi_marshal_in_double;
244
    return arg_cache;
245 246
}

247 248
static inline PyGIArgCache *
_arg_cache_new_for_in_unichar(void)
249
{
250
    PyGIArgCache *arg_cache = _arg_cache_new();
251
    arg_cache->in_marshaller = _pygi_marshal_in_unichar;
252
    return arg_cache;
253 254
}

255 256
static inline PyGIArgCache *
_arg_cache_new_for_in_gtype(void)
257
{
258
    PyGIArgCache *arg_cache = _arg_cache_new();
259
    arg_cache->in_marshaller = _pygi_marshal_in_gtype;
260
    return arg_cache;
261 262
}

263 264
static inline PyGIArgCache *
_arg_cache_new_for_in_utf8(GITransfer transfer)
265
{
266
    PyGIArgCache *arg_cache = _arg_cache_new();
267
    arg_cache->in_marshaller = _pygi_marshal_in_utf8;
268 269 270
    if (arg_cache->transfer == GI_TRANSFER_NOTHING)
        arg_cache->cleanup = g_free;

271
    return arg_cache;
272 273
}

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

282
    return arg_cache;
283 284
}

285 286 287
static inline PyGIArgCache *
_arg_cache_new_for_in_array(GITypeInfo *type_info,
                                      GITransfer transfer)
288
{
289
    PyGIArgCache *arg_cache = (PyGIArgCache *)_sequence_cache_new_from_type_info(type_info);
290
    arg_cache->in_marshaller = _pygi_marshal_in_array;
291 292

    /* arg_cache->cleanup = _pygi_cleanup_array; */
293
    return arg_cache;
294 295
}

296 297
static inline PyGIArgCache *
_arg_cache_new_for_in_interface(void)
298
{
299
    PyGIArgCache *arg_cache = NULL;
300 301 302
    /* TODO: Switch on GI_INFO_TYPE_ to determine caching */
    PyErr_Format(PyExc_NotImplementedError,
                 "Caching for this type is not fully implemented yet");
303
    return arg_cache;
304 305
}

306 307 308
static inline PyGIArgCache *
_arg_cache_new_for_in_glist(GITypeInfo *type_info,
                                      GITransfer transfer)
309
{
310
    PyGIArgCache *arg_cache = (PyGIArgCache *)_sequence_cache_new_from_type_info(type_info);
311
    arg_cache->in_marshaller = _pygi_marshal_in_glist;
312 313
    /* arg_cache->cleanup = */

314
    return arg_cache;
315 316
}

317 318 319
static inline PyGIArgCache *
_arg_cache_new_for_in_gslist(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_gslist;
323 324
    /* arg_cache->cleanup = */

325
    return arg_cache;
326 327
}

328 329
static inline PyGIArgCache *
_arg_cache_new_for_in_ghash(GITypeInfo *type_info)
330
{
331 332
    PyGIArgCache *arg_cache = NULL;
    /*arg_cache->in_marshaller = _pygi_marshal_in_ghash;*/
333 334
    PyErr_Format(PyExc_NotImplementedError,
                 "Caching for this type is not fully implemented yet");
335
    return arg_cache;
336 337
}

338 339
static inline PyGIArgCache *
_arg_cache_new_for_in_gerror(void)
340
{
341
    PyGIArgCache *arg_cache = _arg_cache_new();
342
    arg_cache->in_marshaller = _pygi_marshal_in_gerror;
343
    arg_cache->is_aux = TRUE;
344
    return arg_cache;
345 346
}

347 348 349 350 351 352 353 354
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)
355
{
356
    PyGIArgCache *arg_cache = NULL;
357 358 359

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

430 431 432 433 434 435 436 437 438
    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;
439 440
}

441
static inline gboolean
John (J5) Palmieri's avatar
John (J5) Palmieri committed
442
_args_cache_generate(GIFunctionInfo *function_info,
443 444
                     PyGIFunctionCache *function_cache)
{
445 446
    int arg_index;
    for (arg_index = 0; arg_index < function_cache->n_args; arg_index++) {
447 448
        PyGIArgCache *arg_cache;
        GIArgInfo *arg_info;
449
        GITypeInfo *type_info;
450 451 452 453
        GIDirection direction;
        GITransfer transfer;
        GITypeTag type_tag;
        gint py_arg_index;
454 455

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

John (J5) Palmieri's avatar
John (J5) Palmieri committed
459
        arg_info =
460
            g_callable_info_get_arg( (GICallableInfo *) function_info, arg_index);
461

462 463 464 465
        direction = g_arg_info_get_direction(arg_info);
        transfer = g_arg_info_get_ownership_transfer(arg_info);
        type_info = g_arg_info_get_type_info(arg_info);
        type_tag = g_type_info_get_tag(type_info);
466

467
        switch(arg_cache->direction) {
468
            case GI_DIRECTION_IN:
469
                py_arg_index = function_cache->n_in_args;
470
                function_cache->n_in_args++;
471

472 473 474 475 476 477 478 479
                arg_cache =
                    _arg_cache_in_new_from_type_info(type_info,
                                                     function_cache,
                                                     type_tag,
                                                     transfer,
                                                     direction,
                                                     arg_index,
                                                     py_arg_index);
480

481 482
                function_cache->in_args =
                    g_slist_append(function_cache->in_args, arg_cache);
483
                break;
484 485

            case GI_DIRECTION_OUT:
486
                function_cache->n_out_args++;
487
        }
488 489

        function_cache->args_cache[arg_index] = arg_cache;
490
        g_base_info_unref( (GIBaseInfo *) type_info);
491
    }
492
    return TRUE;
493 494 495 496 497
}

PyGIFunctionCache *
_pygi_function_cache_new (GIFunctionInfo *function_info)
{
498
    PyGIFunctionCache *fc = _function_cache_new_from_function_info(function_info);
499 500 501 502 503
    if (!_args_cache_generate(function_info, fc))
        goto err;

err:
    _pygi_function_cache_free(fc);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
504
    return NULL;
505
}