pygi-cache.c 14.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/* -*- 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
 */

22 23 24
boolean _arg_cache_generate_metadata_in(PyGIArgCache *arg_cache,
                                        GITypeInfo *type_info,
                                        GITypeTag type_tag);
25 26 27 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 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
_pygi_arg_cache_clear (PyGIArgCache *cache);
{
    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
64 65 66 67 68

    cache->in_validator = NULL;
    cache->in_marshaler = NULL;
    cache->out_marshaler = NULL;
    cache->cleanup = NULL;
69 70 71 72 73 74

    _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
75
    cache->hash_cache = NULL;
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
    _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
93
        g_slice_free(PyGIArgCache, tmp);
94 95 96 97 98 99 100
    }

    g_slice_free(PyGIFunctionCache, cache);
}

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

    return fc;
}

116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
static inline PyGIFunctionCache *
_sequence_cache_new_from_type_info(GITypeInfo *type_info)
{
    PyGISequenceCache *sc;
    GITypeInfo *item_type_info;
    GITypeTag *item_type_tag;

    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);
    item_tag_type = g_type_info_get_tag (item_type_info);

    sc->item_cache = g_slice_new0(PyGIArgCache);
    sc->item_cache->type_tag = item_tag_type;

    _arg_cache_generate_metadata_in(PyGIArgCache sc->item_cache,
                                    item_type_info,
                                    item_type_tag);

 
    g_base_info_unref ( (GIBaseInfo *) item_type_info);
}

147 148 149
/* process in args */

static inline boolean
150
_arg_cache_generate_metadata_in_void(PyGIArgCache *arg_cache)
151
{
152
     arg_cache->in_marshaler = _pygi_marshal_in_void;
153 154 155 156 157

     return TRUE;
}

static inline boolean
158
_arg_cache_generate_metadata_in_boolean(PyGIArgCache *arg_cache)
159
{
John (J5) Palmieri's avatar
John (J5) Palmieri committed
160
    arg_cache->in_marshaler = _pygi_marshal_in_boolean;
161 162 163 164
    return TRUE;
}

static inline boolean
165
_arg_cache_generate_metadata_in_int8(PyGIArgCache *arg_cache)
166
{
167
    arg_cache->in_marshaler = _pygi_marshal_in_int8;
168 169 170 171
    return TRUE;
}

static inline boolean
172
_arg_cache_generate_metadata_in_uint8(PyGIArgCache *arg_cache)
173
{
174
    arg_cache->in_marshaler = _pygi_marshal_in_uint8;
175 176 177 178
    return TRUE;
}

static inline boolean
179
_arg_cache_generate_metadata_in_int16(PyGIArgCache *arg_cache)
180
{
181
    arg_cache->in_marshaler = _pygi_marshal_in_int16;
182 183 184 185
    return TRUE;
}

static inline boolean
186
_arg_cache_generate_metadata_in_uint16(PyGIArgCache *arg_cache)
187
{
188
    arg_cache->in_marshaler = _pygi_marshal_in_uint16;
189 190 191 192
    return TRUE;
}

static inline boolean
193
_arg_cache_generate_metadata_in_int32(PyGIArgCache *arg_cache)
194
{
195
    arg_cache->in_marshaler = _pygi_marshal_in_int32;
196 197 198 199
    return TRUE;
}

static inline boolean
200
_arg_cache_generate_metadata_in_uint32(PyGIArgCache *arg_cache)
201
{
202
    arg_cache->in_marshaler = _pygi_marshal_in_uint32;
203 204 205 206
    return TRUE;
}

static inline boolean
207
_arg_cache_generate_metadata_in_int64(PyGIArgCache *arg_cache)
208
{
209
    arg_cache->in_marshaler = _pygi_marshal_in_int64;
210 211 212 213
    return TRUE;
}

static inline boolean
214
_arg_cache_generate_metadata_in_uint64(PyGIArgCache *arg_cache)
215
{
216
    arg_cache->in_marshaler = _pygi_marshal_in_uint64;
217 218 219 220
    return TRUE;
}

static inline boolean
221
_arg_cache_generate_metadata_in_float(PyGIArgCache *arg_cache)
222
{
223
    arg_cache->in_marshaler = _pygi_marshal_in_float;
224 225 226 227
    return TRUE;
}

static inline boolean
228
_arg_cache_generate_metadata_in_double(PyGIArgCache *arg_cache)
229
{
230
    arg_cache->in_marshaler = _pygi_marshal_in_double;
231 232 233 234
    return TRUE;
}

static inline boolean
235
_arg_cache_generate_metadata_in_unichar(PyGIArgCache *arg_cache)
236
{
237
    arg_cache->in_marshaler = _pygi_marshal_in_unichar;
238 239 240 241
    return TRUE;
}

static inline boolean
242
_arg_cache_generate_metadata_in_gtype(PyGIArgCache *arg_cache)
243
{
244
    arg_cache->in_marshaler = _pygi_marshal_in_gtype;
245 246 247 248
    return TRUE;
}

static inline boolean
249
_arg_cache_generate_metadata_in_utf8(PyGIArgCache *arg_cache)
250
{
251 252 253 254
    arg_cache->in_marshaler = _pygi_marshal_in_utf8;
    if (arg_cache->transfer == GI_TRANSFER_NOTHING)
        arg_cache->cleanup = g_free;

255 256 257 258
    return TRUE;
}

static inline boolean
259
_arg_cache_generate_metadata_in_filename(PyGIArgCache *arg_cache)
260
{
261 262 263 264
    arg_cache->in_marshaler = _pygi_marshal_in_filename;
    if (arg_cache->transfer == GI_TRANSFER_NOTHING)
        arg_cache->cleanup = g_free;

265 266 267 268 269
    return TRUE;
}

static inline boolean
_arg_cache_generate_metadata_in_array(PyGIArgCache *arg_cache,
270
                                      GITypeInfo *type_info)
271
{
272
    GITypeInfo *type_info;
273
    arg_cache->in_marshaler = _pygi_marshal_in_array;
274 275 276 277
    arg_cache->sequence_cache = _sequence_cache_new_from_type_info(type_info);

    /* arg_cache->cleanup = _pygi_cleanup_array; */
    return TRUE;
278 279 280
}

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

static inline boolean
_arg_cache_generate_metadata_in_glist(PyGIArgCache *arg_cache,
291
                                      GITypeInfo *type_info)
292
{
293
    arg_cache->in_marshaler = _pygi_marshal_in_glist;
294 295 296 297
    arg_cache->sequence_cache = _sequence_cache_new_from_type_info(type_info);
    /* arg_cache->cleanup = */

    return TRUE;
298 299 300 301
}

static inline boolean
_arg_cache_generate_metadata_in_gslist(PyGIArgCache *arg_cache,
302
                                       GITypeInfo *type_info)
303
{
304
    arg_cache->in_marshaler = _pygi_marshal_in_gslist;
305 306 307 308
    arg_cache->sequence_cache = _sequence_cache_new_from_type_info(type_info);
    /* arg_cache->cleanup = */

    return TRUE;
309 310 311 312
}

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

static inline boolean
322
_arg_cache_generate_metadata_in_error(PyGIArgCache *arg_cache)
323
{
324
    arg_cache->in_marshaler = _pygi_marshal_in_error;
325
    arg_cache->is_aux = TRUE;
326 327 328
    PyErr_Format(PyExc_NotImplementedError,
                 "Caching for this type is not fully implemented yet");
    return FALSE;
329 330
}

331
boolean
332
_arg_cache_generate_metadata_in(PyGIArgCache *arg_cache,
333
                                GITypeInfo *type_info,
334
                                GITypeTag type_tag)
335 336 337
{
    gboolean success = True;

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

John (J5) Palmieri's avatar
John (J5) Palmieri committed
414
    function_cache->in_args =
415 416 417 418 419 420
        g_slist_append(function_cache->in_args, arg_cache);

    return success;
}

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

        /* 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
432
        arg_info =
433 434 435 436
            g_callable_info_get_arg ( (GICallableInfo *) function_info, i);

        arg_cache = function_cache->args_cache[i] = g_slice_new0(PyGIArgCache);
        arg_cache->direction = g_arg_info_get_direction (arg_info);
437
        arg_cache->transfer = g_arg_info_get_transfer (arg_info);
438 439 440 441 442
        type_info = g_base_info_get_type ( (GIBaseInfo *) arg_info);
        type_tag = g_type_info_get_tag (type_info);

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

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

                break;
452 453 454 455 456

            case GI_DIRECTION_OUT:
                function_info->n_out_args++;
 		    switch (type_tag) {
                    case GI_TYPE_TAG_...:
457

458 459 460 461
                        ac->out_marshaler = <type marshaling function pointer>
                        ac->cleanup = <type cleanup function pointer>
                        fc->out_args = g_slist_append(fc->out_args, ac);
                        break;
462
            }
463
        }
464
        g_base_info_unref( (GIBaseInfo *) type_info);
465 466 467 468 469 470
    }
}

PyGIFunctionCache *
_pygi_function_cache_new (GIFunctionInfo *function_info)
{
471
    PyGIFunction *fc = _function_cache_new_from_function_info(function_info);
472 473 474 475 476
    if (!_args_cache_generate(function_info, fc))
        goto err;

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