ffi 0.6.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of ffi might be problematic. Click here for more details.

Files changed (92) hide show
  1. data/History.txt +7 -0
  2. data/LICENSE +10 -21
  3. data/README.rdoc +70 -0
  4. data/Rakefile +56 -84
  5. data/ext/ffi_c/AbstractMemory.c +56 -38
  6. data/ext/ffi_c/AbstractMemory.h +15 -22
  7. data/ext/ffi_c/Buffer.c +61 -22
  8. data/ext/ffi_c/Call.c +52 -540
  9. data/ext/ffi_c/Call.h +1 -1
  10. data/ext/ffi_c/DataConverter.c +62 -0
  11. data/ext/ffi_c/DynamicLibrary.c +21 -1
  12. data/ext/ffi_c/Function.c +252 -30
  13. data/ext/ffi_c/MappedType.c +146 -0
  14. data/{libtest/FunctionTest.c → ext/ffi_c/MappedType.h} +32 -25
  15. data/ext/ffi_c/MemoryPointer.c +12 -33
  16. data/ext/ffi_c/Platform.c +2 -0
  17. data/ext/ffi_c/Pointer.c +66 -28
  18. data/ext/ffi_c/Struct.c +19 -306
  19. data/ext/ffi_c/Struct.h +6 -0
  20. data/ext/ffi_c/StructByReference.c +150 -0
  21. data/{libtest/LastErrorTest.c → ext/ffi_c/StructByReference.h} +30 -21
  22. data/ext/ffi_c/StructLayout.c +26 -16
  23. data/ext/ffi_c/Type.c +39 -68
  24. data/ext/ffi_c/Type.h +12 -22
  25. data/ext/ffi_c/Types.c +20 -5
  26. data/ext/ffi_c/Types.h +7 -7
  27. data/ext/ffi_c/Variadic.c +21 -17
  28. data/ext/ffi_c/extconf.rb +4 -0
  29. data/ext/ffi_c/ffi.c +8 -2
  30. data/ext/ffi_c/rbffi.h +1 -0
  31. data/lib/ffi/autopointer.rb +23 -22
  32. data/lib/ffi/enum.rb +36 -21
  33. data/lib/ffi/errno.rb +20 -0
  34. data/lib/ffi/ffi.rb +13 -80
  35. data/lib/ffi/io.rb +12 -20
  36. data/lib/ffi/library.rb +109 -92
  37. data/lib/ffi/managedstruct.rb +1 -1
  38. data/lib/ffi/memorypointer.rb +15 -21
  39. data/lib/ffi/platform.rb +27 -33
  40. data/lib/ffi/pointer.rb +14 -21
  41. data/lib/ffi/struct.rb +98 -49
  42. data/lib/ffi/struct_layout_builder.rb +158 -0
  43. data/lib/ffi/types.rb +99 -128
  44. data/lib/ffi/union.rb +20 -0
  45. data/lib/ffi/variadic.rb +33 -22
  46. data/spec/ffi/async_callback_spec.rb +23 -0
  47. data/spec/ffi/callback_spec.rb +62 -0
  48. data/spec/ffi/custom_param_type.rb +31 -0
  49. data/spec/ffi/custom_type_spec.rb +73 -0
  50. data/spec/ffi/enum_spec.rb +19 -0
  51. data/spec/ffi/ffi_spec.rb +24 -0
  52. data/spec/ffi/pointer_spec.rb +15 -0
  53. data/spec/ffi/rbx/memory_pointer_spec.rb +7 -1
  54. data/spec/ffi/strptr_spec.rb +36 -0
  55. data/spec/ffi/struct_packed_spec.rb +46 -0
  56. data/spec/ffi/struct_spec.rb +19 -5
  57. data/spec/ffi/typedef_spec.rb +14 -0
  58. data/tasks/ann.rake +80 -0
  59. data/tasks/extension.rake +25 -0
  60. data/tasks/gem.rake +200 -0
  61. data/tasks/git.rake +41 -0
  62. data/tasks/notes.rake +27 -0
  63. data/tasks/post_load.rake +34 -0
  64. data/tasks/rdoc.rake +50 -0
  65. data/tasks/rubyforge.rake +55 -0
  66. data/tasks/setup.rb +301 -0
  67. data/tasks/spec.rake +54 -0
  68. data/tasks/svn.rake +47 -0
  69. data/tasks/test.rake +40 -0
  70. metadata +139 -131
  71. data/README.md +0 -109
  72. data/ext/ffi_c/AutoPointer.c +0 -60
  73. data/ext/ffi_c/AutoPointer.h +0 -18
  74. data/ext/ffi_c/Ffi_c.iml +0 -12
  75. data/ffi.gemspec +0 -18
  76. data/gen/log +0 -1
  77. data/lib/Lib.iml +0 -21
  78. data/libtest/Benchmark.c +0 -73
  79. data/libtest/BoolTest.c +0 -52
  80. data/libtest/BufferTest.c +0 -52
  81. data/libtest/ClosureTest.c +0 -173
  82. data/libtest/EnumTest.c +0 -55
  83. data/libtest/GNUmakefile +0 -141
  84. data/libtest/GlobalVariable.c +0 -56
  85. data/libtest/NumberTest.c +0 -145
  86. data/libtest/PointerTest.c +0 -84
  87. data/libtest/ReferenceTest.c +0 -44
  88. data/libtest/StringTest.c +0 -55
  89. data/libtest/StructTest.c +0 -247
  90. data/libtest/UnionTest.c +0 -64
  91. data/libtest/VariadicTest.c +0 -57
  92. data/spec/ffi/Ffi.iml +0 -12
data/ext/ffi_c/Call.h CHANGED
@@ -69,7 +69,7 @@ typedef union {
69
69
 
70
70
  extern void rbffi_Call_Init(VALUE moduleFFI);
71
71
 
72
- extern void rbffi_SetupCallParams(int argc, VALUE* argv, int paramCount, NativeType* paramTypes,
72
+ extern void rbffi_SetupCallParams(int argc, VALUE* argv, int paramCount, Type** paramTypes,
73
73
  FFIStorage* paramStorage, void** ffiValues,
74
74
  VALUE* callbackParameters, int callbackCount, VALUE enums);
75
75
 
@@ -0,0 +1,62 @@
1
+
2
+ #include <ruby.h>
3
+
4
+ #include <ffi.h>
5
+ #include "rbffi.h"
6
+
7
+ #include "Type.h"
8
+ #include "MappedType.h"
9
+
10
+
11
+ VALUE rbffi_DataConverterClass = Qnil;
12
+ static ID id_native_type_ivar;
13
+
14
+ static VALUE
15
+ conv_native_type(int argc, VALUE* argv, VALUE self)
16
+ {
17
+ if (argc == 0) {
18
+ if (!rb_ivar_defined(self, id_native_type_ivar)) {
19
+ rb_raise(rb_eNotImpError, "native_type method not overridden and no native_type set");
20
+ }
21
+
22
+ return rb_ivar_get(self, id_native_type_ivar);
23
+
24
+ } else if (argc == 1) {
25
+ VALUE type = rbffi_Type_Find(argv[0]);
26
+
27
+ rb_ivar_set(self, id_native_type_ivar, type);
28
+
29
+ return type;
30
+
31
+ } else {
32
+ rb_raise(rb_eArgError, "incorrect arguments");
33
+ }
34
+ }
35
+
36
+ static VALUE
37
+ conv_to_native(VALUE self, VALUE value, VALUE ctx)
38
+ {
39
+ return value;
40
+ }
41
+
42
+ static VALUE
43
+ conv_from_native(VALUE self, VALUE value, VALUE ctx)
44
+ {
45
+ return value;
46
+ }
47
+
48
+
49
+
50
+ void
51
+ rbffi_DataConverter_Init(VALUE moduleFFI)
52
+ {
53
+ rbffi_DataConverterClass = rb_define_module_under(moduleFFI, "DataConverter");
54
+
55
+ rb_define_method(rbffi_DataConverterClass, "native_type", conv_native_type, -1);
56
+ rb_define_method(rbffi_DataConverterClass, "to_native", conv_to_native, 2);
57
+ rb_define_method(rbffi_DataConverterClass, "from_native", conv_from_native, 2);
58
+
59
+ id_native_type_ivar = rb_intern("@native_type");
60
+ }
61
+
62
+
@@ -1,3 +1,23 @@
1
+ /*
2
+ * Copyright (c) 2008-2010 Wayne Meissner
3
+ *
4
+ * All rights reserved.
5
+ *
6
+ * This file is part of ruby-ffi.
7
+ *
8
+ * This code is free software: you can redistribute it and/or modify it under
9
+ * the terms of the GNU Lesser General Public License version 3 only, as
10
+ * published by the Free Software Foundation.
11
+ *
12
+ * This code is distributed in the hope that it will be useful, but WITHOUT
13
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
15
+ * version 3 for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public License
18
+ * version 3 along with this work. If not, see <http://www.gnu.org/licenses/>.
19
+ */
20
+
1
21
  #include <sys/types.h>
2
22
  #include <stdio.h>
3
23
  #include <stdint.h>
@@ -156,7 +176,7 @@ symbol_new(VALUE library, void* address, VALUE name)
156
176
  sym->memory.address = address;
157
177
  sym->memory.size = LONG_MAX;
158
178
  sym->memory.typeSize = 1;
159
- sym->memory.access = MEM_RD | MEM_WR;
179
+ sym->memory.flags = MEM_RD | MEM_WR;
160
180
  sym->library = library;
161
181
  sym->name = name;
162
182
 
data/ext/ffi_c/Function.c CHANGED
@@ -1,28 +1,21 @@
1
1
  /*
2
2
  * Copyright (c) 2009, Wayne Meissner
3
+
3
4
  * All rights reserved.
4
5
  *
5
- * Redistribution and use in source and binary forms, with or without
6
- * modification, are permitted provided that the following conditions are met:
6
+ * This file is part of ruby-ffi.
7
+ *
8
+ * This code is free software: you can redistribute it and/or modify it under
9
+ * the terms of the GNU Lesser General Public License version 3 only, as
10
+ * published by the Free Software Foundation.
7
11
  *
8
- * * Redistributions of source code must retain the above copyright notice, this
9
- * list of conditions and the following disclaimer.
10
- * * Redistributions in binary form must reproduce the above copyright notice
11
- * this list of conditions and the following disclaimer in the documentation
12
- * and/or other materials provided with the distribution.
13
- * * The name of the author or authors may not be used to endorse or promote
14
- * products derived from this software without specific prior written permission.
12
+ * This code is distributed in the hope that it will be useful, but WITHOUT
13
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
15
+ * version 3 for more details.
15
16
  *
16
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17
+ * You should have received a copy of the GNU Lesser General Public License
18
+ * version 3 along with this work. If not, see <http://www.gnu.org/licenses/>.
26
19
  */
27
20
 
28
21
  #include "MethodHandle.h"
@@ -39,6 +32,10 @@
39
32
  #include <ruby.h>
40
33
 
41
34
  #include <ffi.h>
35
+ #if defined(HAVE_NATIVETHREAD) && !defined(_WIN32)
36
+ #include <pthread.h>
37
+ #endif
38
+
42
39
  #include "rbffi.h"
43
40
  #include "compat.h"
44
41
 
@@ -51,6 +48,7 @@
51
48
  #include "Call.h"
52
49
  #include "ClosurePool.h"
53
50
  #include "Function.h"
51
+ #include "MappedType.h"
54
52
 
55
53
  typedef struct Function_ {
56
54
  AbstractMemory memory;
@@ -67,10 +65,60 @@ static void function_free(Function *);
67
65
  static VALUE function_init(VALUE self, VALUE rbFunctionInfo, VALUE rbProc);
68
66
  static void callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data);
69
67
  static bool callback_prep(void* ctx, void* code, Closure* closure, char* errmsg, size_t errmsgsize);
68
+ static void* callback_with_gvl(void* data);
69
+
70
+ #if defined(HAVE_NATIVETHREAD) && defined(HAVE_RB_THREAD_BLOCKING_REGION)
71
+ # define DEFER_ASYNC_CALLBACK 1
72
+ #endif
73
+
74
+ #if defined(DEFER_ASYNC_CALLBACK)
75
+ static VALUE async_cb_event(void);
76
+ static VALUE async_cb_call(void *);
77
+ #endif
78
+
79
+ #if defined(HAVE_NATIVETHREAD) && defined (HAVE_RB_THREAD_BLOCKING_REGION)
80
+ # define DEFER_ASYNC_CALLBACK
81
+ #endif
82
+
83
+ #ifdef HAVE_RUBY_THREAD_HAS_GVL_P
84
+ extern int ruby_thread_has_gvl_p(void);
85
+ #endif
86
+
87
+ #ifdef HAVE_RB_THREAD_CALL_WITH_GVL
88
+ extern void *rb_thread_call_with_gvl(void *(*func)(void *), void *data1);
89
+ #endif
70
90
 
71
91
  VALUE rbffi_FunctionClass = Qnil;
72
92
 
73
- static ID id_call = 0, id_cbtable = 0, id_cb_ref = 0;
93
+ #if defined(DEFER_ASYNC_CALLBACK)
94
+ static VALUE async_cb_thread = Qnil;
95
+ #endif
96
+
97
+ static ID id_call = 0, id_to_native = 0, id_from_native = 0, id_cbtable = 0, id_cb_ref = 0;
98
+
99
+ struct gvl_callback {
100
+ Closure* closure;
101
+ void* retval;
102
+ void** parameters;
103
+
104
+ #if defined(DEFER_ASYNC_CALLBACK)
105
+ struct gvl_callback* next;
106
+ # ifndef _WIN32
107
+ pthread_cond_t async_cond;
108
+ pthread_mutex_t async_mutex;
109
+ # endif
110
+ #endif
111
+ };
112
+
113
+
114
+ #if defined(DEFER_ASYNC_CALLBACK)
115
+ static struct gvl_callback* async_cb_list = NULL;
116
+ # ifndef _WIN32
117
+ static pthread_mutex_t async_cb_mutex = PTHREAD_MUTEX_INITIALIZER;
118
+ static pthread_cond_t async_cb_cond = PTHREAD_COND_INITIALIZER;
119
+ # endif
120
+ #endif
121
+
74
122
 
75
123
  static VALUE
76
124
  function_allocate(VALUE klass)
@@ -80,7 +128,7 @@ function_allocate(VALUE klass)
80
128
 
81
129
  obj = Data_Make_Struct(klass, Function, function_mark, function_free, fn);
82
130
 
83
- fn->memory.access = MEM_RD;
131
+ fn->memory.flags = MEM_RD;
84
132
 
85
133
  fn->rbProc = Qnil;
86
134
  fn->rbFunctionInfo = Qnil;
@@ -215,6 +263,12 @@ function_init(VALUE self, VALUE rbFunctionInfo, VALUE rbProc)
215
263
  }
216
264
  }
217
265
 
266
+ #if defined(DEFER_ASYNC_CALLBACK)
267
+ if (async_cb_thread == Qnil) {
268
+ async_cb_thread = rb_thread_create(async_cb_event, NULL);
269
+ }
270
+ #endif
271
+
218
272
  fn->closure = rbffi_Closure_Alloc(fn->info->closurePool);
219
273
  fn->closure->info = fn;
220
274
  fn->memory.address = fn->closure->code;
@@ -222,7 +276,8 @@ function_init(VALUE self, VALUE rbFunctionInfo, VALUE rbProc)
222
276
  fn->autorelease = true;
223
277
 
224
278
  } else {
225
- rb_raise(rb_eTypeError, "wrong argument type. Expected pointer or proc");
279
+ rb_raise(rb_eTypeError, "wrong argument type %s, expected pointer or proc",
280
+ rb_obj_classname(rbProc));
226
281
  }
227
282
 
228
283
  fn->rbProc = rbProc;
@@ -320,17 +375,147 @@ function_release(VALUE self)
320
375
  static void
321
376
  callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data)
322
377
  {
323
- Closure* closure = (Closure *) user_data;
324
- Function* fn = (Function *) closure->info;
378
+ struct gvl_callback cb;
379
+ cb.closure = (Closure *) user_data;
380
+ cb.retval = retval;
381
+ cb.parameters = parameters;
382
+
383
+ #ifdef HAVE_RUBY_THREAD_HAS_GVL_P
384
+ if (ruby_thread_has_gvl_p()) {
385
+ #else
386
+ if (1) {
387
+ #endif
388
+ callback_with_gvl(&cb);
389
+
390
+ #if defined(HAVE_RUBY_NATIVE_THREAD_P) && defined (HAVE_RB_THREAD_CALL_WITH_GVL)
391
+ } else if (ruby_native_thread_p()) {
392
+ rb_thread_call_with_gvl(callback_with_gvl, &cb);
393
+ #endif
394
+ #if defined(DEFER_ASYNC_CALLBACK) && !defined(_WIN32)
395
+ } else {
396
+ pthread_mutex_init(&cb.async_mutex, NULL);
397
+ pthread_cond_init(&cb.async_cond, NULL);
398
+
399
+ pthread_mutex_lock(&cb.async_mutex);
400
+
401
+ // Now signal the async callback thread
402
+ pthread_mutex_lock(&async_cb_mutex);
403
+ cb.next = async_cb_list;
404
+ async_cb_list = &cb;
405
+ pthread_cond_signal(&async_cb_cond);
406
+ pthread_mutex_unlock(&async_cb_mutex);
407
+
408
+ // Wait for the thread executing the ruby callback to signal it is done
409
+ pthread_cond_wait(&cb.async_cond, &cb.async_mutex);
410
+ #endif
411
+ }
412
+ }
413
+
414
+ #if defined(DEFER_ASYNC_CALLBACK)
415
+ struct async_wait {
416
+ void* cb;
417
+ bool stop;
418
+ };
419
+
420
+ static VALUE async_cb_wait(void *);
421
+ static void async_cb_stop(void *);
422
+
423
+ static VALUE
424
+ async_cb_event(void)
425
+ {
426
+ struct async_wait w = { 0 };
427
+
428
+ w.stop = false;
429
+ while (!w.stop) {
430
+ rb_thread_blocking_region(async_cb_wait, &w, async_cb_stop, &w);
431
+ if (w.cb != NULL) {
432
+ // Start up a new ruby thread to run the ruby callback
433
+ rb_thread_create(async_cb_call, w.cb);
434
+ }
435
+ }
436
+
437
+ return Qnil;
438
+ }
439
+
440
+ static VALUE
441
+ async_cb_wait(void *data)
442
+ {
443
+ struct async_wait* w = (struct async_wait *) data;
444
+
445
+ w->cb = NULL;
446
+
447
+ pthread_mutex_lock(&async_cb_mutex);
448
+
449
+ while (!w->stop && async_cb_list == NULL) {
450
+ pthread_cond_wait(&async_cb_cond, &async_cb_mutex);
451
+ }
452
+
453
+ if (async_cb_list != NULL) {
454
+ w->cb = async_cb_list;
455
+ async_cb_list = async_cb_list->next;
456
+ }
457
+
458
+ pthread_mutex_unlock(&async_cb_mutex);
459
+
460
+ return Qnil;
461
+ }
462
+
463
+ static void
464
+ async_cb_stop(void *data)
465
+ {
466
+ struct async_wait* w = (struct async_wait *) data;
467
+
468
+ pthread_mutex_lock(&async_cb_mutex);
469
+ w->stop = true;
470
+ pthread_cond_signal(&async_cb_cond);
471
+ pthread_mutex_unlock(&async_cb_mutex);
472
+ }
473
+
474
+ static VALUE
475
+ async_cb_call(void *data)
476
+ {
477
+ struct gvl_callback* cb = (struct gvl_callback *) data;
478
+
479
+ callback_with_gvl(cb);
480
+
481
+ // Signal the original native thread that the ruby code has completed
482
+ pthread_mutex_lock(&cb->async_mutex);
483
+ pthread_cond_signal(&cb->async_cond);
484
+ pthread_mutex_unlock(&cb->async_mutex);
485
+
486
+ return Qnil;
487
+ }
488
+
489
+ #endif
490
+
491
+
492
+ static void*
493
+ callback_with_gvl(void* data)
494
+ {
495
+ struct gvl_callback* cb = (struct gvl_callback *) data;
496
+
497
+ Function* fn = (Function *) cb->closure->info;
325
498
  FunctionType *cbInfo = fn->info;
499
+ Type* returnType = cbInfo->returnType;
500
+ void* retval = cb->retval;
501
+ void** parameters = cb->parameters;
326
502
  VALUE* rbParams;
503
+ VALUE rbReturnType = cbInfo->rbReturnType;
327
504
  VALUE rbReturnValue;
328
505
  int i;
329
506
 
330
507
  rbParams = ALLOCA_N(VALUE, cbInfo->parameterCount);
331
508
  for (i = 0; i < cbInfo->parameterCount; ++i) {
332
509
  VALUE param;
333
- switch (cbInfo->parameterTypes[i]->nativeType) {
510
+ Type* paramType = cbInfo->parameterTypes[i];
511
+ VALUE rbParamType = rb_ary_entry(cbInfo->rbParameterTypes, i);
512
+
513
+ if (unlikely(paramType->nativeType == NATIVE_MAPPED)) {
514
+ paramType = ((MappedType *) paramType)->type;
515
+ rbParamType = ((MappedType *) paramType)->rbType;
516
+ }
517
+
518
+ switch (paramType->nativeType) {
334
519
  case NATIVE_INT8:
335
520
  param = INT2NUM(*(int8_t *) parameters[i]);
336
521
  break;
@@ -379,19 +564,36 @@ callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data)
379
564
 
380
565
  case NATIVE_FUNCTION:
381
566
  case NATIVE_CALLBACK:
382
- param = rbffi_NativeValue_ToRuby(cbInfo->parameterTypes[i],
383
- rb_ary_entry(cbInfo->rbParameterTypes, i), parameters[i], Qnil);
567
+ case NATIVE_STRUCT:
568
+ param = rbffi_NativeValue_ToRuby(paramType, rbParamType, parameters[i], Qnil);
384
569
  break;
570
+
385
571
  default:
386
572
  param = Qnil;
387
573
  break;
388
574
  }
575
+
576
+ // Convert the native value into a custom ruby value
577
+ if (unlikely(cbInfo->parameterTypes[i]->nativeType == NATIVE_MAPPED)) {
578
+ VALUE values[] = { param, Qnil };
579
+ param = rb_funcall2(((MappedType *) cbInfo->parameterTypes[i])->rbConverter, id_from_native, 2, values);
580
+ }
581
+
389
582
  rbParams[i] = param;
390
583
  }
584
+
391
585
  rbReturnValue = rb_funcall2(fn->rbProc, id_call, cbInfo->parameterCount, rbParams);
586
+
587
+ if (unlikely(returnType->nativeType == NATIVE_MAPPED)) {
588
+ VALUE values[] = { rbReturnValue, Qnil };
589
+ rbReturnValue = rb_funcall2(((MappedType *) returnType)->rbConverter, id_to_native, 2, values);
590
+ rbReturnType = ((MappedType *) returnType)->rbType;
591
+ returnType = ((MappedType* ) returnType)->type;
592
+ }
593
+
392
594
  if (rbReturnValue == Qnil || TYPE(rbReturnValue) == T_NIL) {
393
- memset(retval, 0, cbInfo->ffiReturnType->size);
394
- } else switch (cbInfo->returnType->nativeType) {
595
+ memset(retval, 0, returnType->ffiType->size);
596
+ } else switch (returnType->nativeType) {
395
597
  case NATIVE_INT8:
396
598
  case NATIVE_INT16:
397
599
  case NATIVE_INT32:
@@ -442,7 +644,7 @@ callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data)
442
644
  } else if (rb_obj_is_kind_of(rbReturnValue, rb_cProc) || rb_respond_to(rbReturnValue, id_call)) {
443
645
  VALUE function;
444
646
 
445
- function = rbffi_Function_ForProc(cbInfo->rbReturnType, rbReturnValue);
647
+ function = rbffi_Function_ForProc(rbReturnType, rbReturnValue);
446
648
 
447
649
  *((void **) retval) = ((AbstractMemory *) DATA_PTR(function))->address;
448
650
  } else {
@@ -450,10 +652,28 @@ callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data)
450
652
  }
451
653
  break;
452
654
 
655
+ case NATIVE_STRUCT:
656
+ if (TYPE(rbReturnValue) == T_DATA && rb_obj_is_kind_of(rbReturnValue, rbffi_StructClass)) {
657
+ AbstractMemory* memory = ((Struct *) DATA_PTR(rbReturnValue))->pointer;
658
+
659
+ if (memory->address != NULL) {
660
+ memcpy(retval, memory->address, returnType->ffiType->size);
661
+
662
+ } else {
663
+ memset(retval, 0, returnType->ffiType->size);
664
+ }
665
+
666
+ } else {
667
+ memset(retval, 0, returnType->ffiType->size);
668
+ }
669
+ break;
670
+
453
671
  default:
454
672
  *((ffi_arg *) retval) = 0;
455
673
  break;
456
674
  }
675
+
676
+ return NULL;
457
677
  }
458
678
 
459
679
 
@@ -492,5 +712,7 @@ rbffi_Function_Init(VALUE moduleFFI)
492
712
  id_call = rb_intern("call");
493
713
  id_cbtable = rb_intern("@__ffi_callback_table__");
494
714
  id_cb_ref = rb_intern("@__ffi_callback__");
715
+ id_to_native = rb_intern("to_native");
716
+ id_from_native = rb_intern("from_native");
495
717
  }
496
718