pygi-cache.c 14.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 23
#include "pygi-cache.h"
#include "pygi-argument.h"
#include <girepository.h>
24

25 26 27
gboolean _arg_cache_generate_metadata_in(PyGIArgCache *arg_cache,
                                         GITypeInfo *type_info,
                                         GITypeTag type_tag);
28 29 30 31 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

/* 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
61
_pygi_arg_cache_clear (PyGIArgCache *cache)
62 63 64 65 66
{
    cache->is_aux = FALSE;
    cache->is_pointer = FALSE;
    cache->direction = 0;
    g_base_info_unref(cache->arg_info);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
67

68 69
    cache->in_marshaller = NULL;
    cache->out_marshaller = NULL;
John (J5) Palmieri's avatar
John (J5) Palmieri committed
70
    cache->cleanup = NULL;
71 72 73 74 75 76

    _pygi_sequence_cache_free(cache->sequence_cache);
    cache->sequence_cache = NULL;
    _pygi_interface_cache_free(cache->interface_cache);
    cache->interface_cache = NULL;
    _pygi_hash_cache_free(cache->hash_cache);
John (J5) Palmieri's avatar
John (J5) Palmieri committed
77
    cache->hash_cache = NULL;
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
    _pygi_callback_cache_free(cache->callback_cache);
    cache->callback_cache = NULL;

    gint c_arg_index = -1;
    gint py_arg_index = -1;
}

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
95
        g_slice_free(PyGIArgCache, tmp);
96 97 98 99 100 101 102
    }

    g_slice_free(PyGIFunctionCache, cache);
}

/* cache generation */
static inline PyGIFunctionCache *
103
_function_cache_new_from_function_info(GIFunctionInfo *function_info)
104 105 106 107 108 109 110 111 112
{
    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);
113
    fc->args_cache = g_slice_alloc0(fc->n_args * sizeof(PyGIArgCache *));
114 115 116 117

    return fc;
}

118
static inline PyGISequenceCache *
119 120 121 122
_sequence_cache_new_from_type_info(GITypeInfo *type_info)
{
    PyGISequenceCache *sc;
    GITypeInfo *item_type_info;
123
    GITypeTag item_type_tag;
124 125 126 127 128 129 130 131 132 133 134 135

    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);
    if (!sc->is_zero_terminated) 
        sc->fixed_size = g_type_info_get_array_fixed_size(type_info);
    if (sc->fixed_size < 0)
        sc->len_arg_index = g_type_info_get_array_length (type_info);    
    
    item_type_info = g_type_info_get_param_type (type_info, 0);
136
    item_type_tag = g_type_info_get_tag (item_type_info);
137 138

    sc->item_cache = g_slice_new0(PyGIArgCache);
139
    sc->item_cache->type_tag = item_type_tag;
140

141
    _arg_cache_generate_metadata_in(sc->item_cache,
142 143 144 145 146
                                    item_type_info,
                                    item_type_tag);

 
    g_base_info_unref ( (GIBaseInfo *) item_type_info);
147 148

    return sc;
149 150
}

151 152
/* process in args */

153
static inline gboolean
154
_arg_cache_generate_metadata_in_void(PyGIArgCache *arg_cache)
155
{
156
     arg_cache->in_marshaller = _pygi_marshal_in_void;
157 158 159 160

     return TRUE;
}

161
static inline gboolean
162
_arg_cache_generate_metadata_in_boolean(PyGIArgCache *arg_cache)
163
{
164
    arg_cache->in_marshaller = _pygi_marshal_in_boolean;
165 166 167
    return TRUE;
}

168
static inline gboolean
169
_arg_cache_generate_metadata_in_int8(PyGIArgCache *arg_cache)
170
{
171
    arg_cache->in_marshaller = _pygi_marshal_in_int8;
172 173 174
    return TRUE;
}

175
static inline gboolean
176
_arg_cache_generate_metadata_in_uint8(PyGIArgCache *arg_cache)
177
{
178
    arg_cache->in_marshaller = _pygi_marshal_in_uint8;
179 180 181
    return TRUE;
}

182
static inline gboolean
183
_arg_cache_generate_metadata_in_int16(PyGIArgCache *arg_cache)
184
{
185
    arg_cache->in_marshaller = _pygi_marshal_in_int16;
186 187 188
    return TRUE;
}

189
static inline gboolean
190
_arg_cache_generate_metadata_in_uint16(PyGIArgCache *arg_cache)
191
{
192
    arg_cache->in_marshaller = _pygi_marshal_in_uint16;
193 194 195
    return TRUE;
}

196
static inline gboolean
197
_arg_cache_generate_metadata_in_int32(PyGIArgCache *arg_cache)
198
{
199
    arg_cache->in_marshaller = _pygi_marshal_in_int32;
200 201 202
    return TRUE;
}

203
static inline gboolean
204
_arg_cache_generate_metadata_in_uint32(PyGIArgCache *arg_cache)
205
{
206
    arg_cache->in_marshaller = _pygi_marshal_in_uint32;
207 208 209
    return TRUE;
}

210
static inline gboolean
211
_arg_cache_generate_metadata_in_int64(PyGIArgCache *arg_cache)
212
{
213
    arg_cache->in_marshaller = _pygi_marshal_in_int64;
214 215 216
    return TRUE;
}

217
static inline gboolean
218
_arg_cache_generate_metadata_in_uint64(PyGIArgCache *arg_cache)
219
{
220
    arg_cache->in_marshaller = _pygi_marshal_in_uint64;
221 222 223
    return TRUE;
}

224
static inline gboolean
225
_arg_cache_generate_metadata_in_float(PyGIArgCache *arg_cache)
226
{
227
    arg_cache->in_marshaller = _pygi_marshal_in_float;
228 229 230
    return TRUE;
}

231
static inline gboolean
232
_arg_cache_generate_metadata_in_double(PyGIArgCache *arg_cache)
233
{
234
    arg_cache->in_marshaller = _pygi_marshal_in_double;
235 236 237
    return TRUE;
}

238
static inline gboolean
239
_arg_cache_generate_metadata_in_unichar(PyGIArgCache *arg_cache)
240
{
241
    arg_cache->in_marshaller = _pygi_marshal_in_unichar;
242 243 244
    return TRUE;
}

245
static inline gboolean
246
_arg_cache_generate_metadata_in_gtype(PyGIArgCache *arg_cache)
247
{
248
    arg_cache->in_marshaller = _pygi_marshal_in_gtype;
249 250 251
    return TRUE;
}

252
static inline gboolean
253
_arg_cache_generate_metadata_in_utf8(PyGIArgCache *arg_cache)
254
{
255
    arg_cache->in_marshaller = _pygi_marshal_in_utf8;
256 257 258
    if (arg_cache->transfer == GI_TRANSFER_NOTHING)
        arg_cache->cleanup = g_free;

259 260 261
    return TRUE;
}

262
static inline gboolean
263
_arg_cache_generate_metadata_in_filename(PyGIArgCache *arg_cache)
264
{
265
    arg_cache->in_marshaller = _pygi_marshal_in_filename;
266 267 268
    if (arg_cache->transfer == GI_TRANSFER_NOTHING)
        arg_cache->cleanup = g_free;

269 270 271
    return TRUE;
}

272
static inline gboolean
273
_arg_cache_generate_metadata_in_array(PyGIArgCache *arg_cache,
274
                                      GITypeInfo *type_info)
275
{
276
    arg_cache->in_marshaller = _pygi_marshal_in_array;
277 278 279 280
    arg_cache->sequence_cache = _sequence_cache_new_from_type_info(type_info);

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

283
static inline gboolean
284
_arg_cache_generate_metadata_in_interface(PyGIArgCache *arg_cache)
285
{
286 287 288 289
    /* TODO: Switch on GI_INFO_TYPE_ to determine caching */
    PyErr_Format(PyExc_NotImplementedError,
                 "Caching for this type is not fully implemented yet");
    return FALSE;
290 291
}

292
static inline gboolean
293
_arg_cache_generate_metadata_in_glist(PyGIArgCache *arg_cache,
294
                                      GITypeInfo *type_info)
295
{
296
    arg_cache->in_marshaller = _pygi_marshal_in_glist;
297 298 299 300
    arg_cache->sequence_cache = _sequence_cache_new_from_type_info(type_info);
    /* arg_cache->cleanup = */

    return TRUE;
301 302
}

303
static inline gboolean
304
_arg_cache_generate_metadata_in_gslist(PyGIArgCache *arg_cache,
305
                                       GITypeInfo *type_info)
306
{
307
    arg_cache->in_marshaller = _pygi_marshal_in_gslist;
308 309 310 311
    arg_cache->sequence_cache = _sequence_cache_new_from_type_info(type_info);
    /* arg_cache->cleanup = */

    return TRUE;
312 313
}

314
static inline gboolean
315
_arg_cache_generate_metadata_in_ghash(PyGIArgCache *arg_cache,
316
                                      GITypeInfo *type_info)
317
{
318
    arg_cache->in_marshaller = _pygi_marshal_in_ghash;
319 320 321
    PyErr_Format(PyExc_NotImplementedError,
                 "Caching for this type is not fully implemented yet");
    return FALSE;
322 323
}

324 325
static inline gboolean
_arg_cache_generate_metadata_in_gerror(PyGIArgCache *arg_cache)
326
{
327
    arg_cache->in_marshaller = _pygi_marshal_in_gerror;
328
    arg_cache->is_aux = TRUE;
329 330 331
    PyErr_Format(PyExc_NotImplementedError,
                 "Caching for this type is not fully implemented yet");
    return FALSE;
332 333
}

334
gboolean
335
_arg_cache_generate_metadata_in(PyGIArgCache *arg_cache,
336
                                GITypeInfo *type_info,
337
                                GITypeTag type_tag)
338
{
339
    gboolean success = TRUE;
340 341 342

    switch (type_tag) {
       case GI_TYPE_TAG_VOID:
343
           success = _arg_cache_generate_metadata_in_void(arg_cache);
344 345
           break;
       case GI_TYPE_TAG_BOOLEAN:
346
           success = _arg_cache_generate_metadata_in_boolean(arg_cache);
347 348
           break;
       case GI_TYPE_TAG_INT8:
349
           success = _arg_cache_generate_metadata_in_int8(arg_cache);
350 351
           break;
       case GI_TYPE_TAG_UINT8:
352
           success = _arg_cache_generate_metadata_in_uint8(arg_cache);
353 354
           break;
       case GI_TYPE_TAG_INT16:
355
           success = _arg_cache_generate_metadata_in_uint16(arg_cache);
356 357
           break;
       case GI_TYPE_TAG_UINT16:
358
           success = _arg_cache_generate_metadata_in_uint16(arg_cache);
359 360
           break;
       case GI_TYPE_TAG_INT32:
361
           success = _arg_cache_generate_metadata_in_int32(arg_cache);
362 363
           break;
       case GI_TYPE_TAG_UINT32:
364
           success = _arg_cache_generate_metadata_in_uint32(arg_cache);
365 366
           break;
       case GI_TYPE_TAG_INT64:
367
           success = _arg_cache_generate_metadata_in_int64(arg_cache);
368 369
           break;
       case GI_TYPE_TAG_UINT64:
370
           success = _arg_cache_generate_metadata_in_uint64(arg_cache);
371 372
           break;
       case GI_TYPE_TAG_FLOAT:
373
           success = _arg_cache_generate_metadata_in_float(arg_cache);
374 375
           break;
       case GI_TYPE_TAG_DOUBLE:
376
           success = _arg_cache_generate_metadata_in_double(arg_cache);
377 378
           break;
       case GI_TYPE_TAG_UNICHAR:
379
           success = _arg_cache_generate_metadata_in_unichar(arg_cache);
380 381
           break;
       case GI_TYPE_TAG_GTYPE:
382
           success = _arg_cache_generate_metadata_in_gtype(arg_cache);
383 384
           break;
       case GI_TYPE_TAG_UTF8:
385
           success = _arg_cache_generate_metadata_in_utf8(arg_cache);
386 387
           break;
       case GI_TYPE_TAG_FILENAME:
388
           success = _arg_cache_generate_metadata_in_filename(arg_cache);
389 390 391
           break;
       case GI_TYPE_TAG_ARRAY:
           success = _arg_cache_generate_metadata_in_array(arg_cache,
392
                                                           type_info);
393 394
           break;
       case GI_TYPE_TAG_INTERFACE:
395
           success = _arg_cache_generate_metadata_in_interface(arg_cache);
396 397 398
           break;
       case GI_TYPE_TAG_GLIST:
           success = _arg_cache_generate_metadata_in_glist(arg_cache,
399
                                                           type_info);
400 401 402
           break;
       case GI_TYPE_TAG_GSLIST:
           success = _arg_cache_generate_metadata_in_gslist(arg_cache,
403
                                                            type_info);
404 405 406
           break;
       case GI_TYPE_TAG_GHASH:
           success = _arg_cache_generate_metadata_in_ghash(arg_cache,
407
                                                           type_info);
408 409
           break;
       case GI_TYPE_TAG_ERROR:
410
           success = _arg_cache_generate_metadata_in_gerror(arg_cache);
411 412 413 414 415 416
           break;
    }

    return success;
}

417
static inline gboolean
John (J5) Palmieri's avatar
John (J5) Palmieri committed
418
_args_cache_generate(GIFunctionInfo *function_info,
419 420
                     PyGIFunctionCache *function_cache)
{
421
    int i;
422 423 424
    for (i = 0; i < function_cache->n_args; i++) {
        PyGIArgCache *arg_cache;
        GIArgInfo *arg_info;
425
        GITypeInfo *type_info;
426 427 428 429 430

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

John (J5) Palmieri's avatar
John (J5) Palmieri committed
431
        arg_info =
432 433 434
            g_callable_info_get_arg ( (GICallableInfo *) function_info, i);

        arg_cache = function_cache->args_cache[i] = g_slice_new0(PyGIArgCache);
435 436 437 438
        arg_cache->direction = g_arg_info_get_direction(arg_info);
        arg_cache->transfer = g_arg_info_get_ownership_transfer (arg_info);
        type_info = g_base_info_get_type_info ( (GIBaseInfo *) arg_info);
        arg_cache->type_tag = g_type_info_get_tag (type_info);
439

440
        switch(arg_cache->direction) {
441
            case GI_DIRECTION_IN:
442
                function_cache->n_in_args++;
443 444
                arg_cache->c_arg_index = i + function_cache->is_method;
                arg_cache->py_arg_index =
445
                    function_cache->n_in_args + function_cache->is_method;
446

447
                _arg_cache_generate_metadata_in(arg_cache,
448
                                                type_info,
449
                                                arg_cache->type_tag);
450

451 452
                function_cache->in_args =
                    g_slist_append(function_cache->in_args, arg_cache);
453
                break;
454 455

            case GI_DIRECTION_OUT:
456
                function_cache->n_out_args++;
457
        }
458
        g_base_info_unref( (GIBaseInfo *) type_info);
459
    }
460
    return TRUE;
461 462 463 464 465
}

PyGIFunctionCache *
_pygi_function_cache_new (GIFunctionInfo *function_info)
{
466
    PyGIFunctionCache *fc = _function_cache_new_from_function_info(function_info);
467 468 469 470 471
    if (!_args_cache_generate(function_info, fc))
        goto err;

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