ffi 0.3.0 → 0.3.1
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.
- data/Rakefile +11 -2
- data/ext/ffi_c/AbstractMemory.c +103 -23
- data/ext/ffi_c/AbstractMemory.h +27 -1
- data/ext/ffi_c/AutoPointer.c +13 -15
- data/ext/ffi_c/Buffer.c +46 -29
- data/ext/ffi_c/Callback.c +58 -39
- data/ext/ffi_c/Invoker.c +6 -2
- data/ext/ffi_c/MemoryPointer.c +4 -1
- data/ext/ffi_c/NativeLibrary.c +5 -8
- data/ext/ffi_c/NullPointer.c +35 -0
- data/ext/ffi_c/Pointer.c +21 -15
- data/ext/ffi_c/Struct.c +145 -219
- metadata +2 -2
data/ext/ffi_c/Callback.c
CHANGED
@@ -15,8 +15,7 @@
|
|
15
15
|
#include "extconf.h"
|
16
16
|
|
17
17
|
|
18
|
-
static void
|
19
|
-
static void CallbackInfo_free(CallbackInfo *);
|
18
|
+
static void cbinfo_free(CallbackInfo *);
|
20
19
|
|
21
20
|
#if defined(HAVE_LIBFFI) && !defined(HAVE_FFI_CLOSURE_ALLOC)
|
22
21
|
static void* ffi_closure_alloc(size_t size, void** code);
|
@@ -33,18 +32,29 @@ static ID callID = Qnil, cbTableID = Qnil;
|
|
33
32
|
VALUE rb_FFI_CallbackInfo_class = Qnil;
|
34
33
|
|
35
34
|
static VALUE
|
36
|
-
|
35
|
+
cbinfo_allocate(VALUE klass)
|
36
|
+
{
|
37
|
+
CallbackInfo* cbInfo;
|
38
|
+
return Data_Make_Struct(klass, CallbackInfo, NULL, cbinfo_free, cbInfo);
|
39
|
+
}
|
40
|
+
|
41
|
+
static VALUE
|
42
|
+
cbinfo_initialize(VALUE self, VALUE rbReturnType, VALUE rbParamTypes)
|
37
43
|
{
|
38
44
|
CallbackInfo *cbInfo;
|
39
|
-
|
40
|
-
int paramCount = RARRAY_LEN(rbParamTypes);
|
45
|
+
int paramCount;
|
41
46
|
ffi_status status;
|
42
47
|
int i;
|
43
48
|
|
44
|
-
|
49
|
+
Check_Type(rbParamTypes, T_ARRAY);
|
50
|
+
paramCount = RARRAY_LEN(rbParamTypes);
|
51
|
+
|
52
|
+
Data_Get_Struct(self, CallbackInfo, cbInfo);
|
45
53
|
cbInfo->parameterCount = paramCount;
|
46
54
|
cbInfo->parameterTypes = xcalloc(paramCount, sizeof(NativeType));
|
47
55
|
cbInfo->ffiParameterTypes = xcalloc(paramCount, sizeof(ffi_type *));
|
56
|
+
cbInfo->returnType = FIX2INT(rbReturnType);
|
57
|
+
|
48
58
|
for (i = 0; i < paramCount; ++i) {
|
49
59
|
cbInfo->parameterTypes[i] = FIX2INT(rb_ary_entry(rbParamTypes, i));
|
50
60
|
cbInfo->ffiParameterTypes[i] = rb_FFI_NativeTypeToFFI(cbInfo->parameterTypes[i]);
|
@@ -52,7 +62,7 @@ CallbackInfo_new(VALUE klass, VALUE rbReturnType, VALUE rbParamTypes)
|
|
52
62
|
rb_raise(rb_eArgError, "Unknown argument type: %#x", cbInfo->parameterTypes[i]);
|
53
63
|
}
|
54
64
|
}
|
55
|
-
|
65
|
+
|
56
66
|
cbInfo->ffiReturnType = rb_FFI_NativeTypeToFFI(cbInfo->returnType);
|
57
67
|
if (cbInfo->ffiReturnType == NULL) {
|
58
68
|
rb_raise(rb_eArgError, "Unknown return type: %#x", cbInfo->returnType);
|
@@ -74,38 +84,28 @@ CallbackInfo_new(VALUE klass, VALUE rbReturnType, VALUE rbParamTypes)
|
|
74
84
|
default:
|
75
85
|
rb_raise(rb_eArgError, "Unknown FFI error");
|
76
86
|
}
|
77
|
-
return
|
87
|
+
return self;
|
78
88
|
}
|
79
89
|
|
80
90
|
static void
|
81
|
-
|
91
|
+
cbinfo_free(CallbackInfo* cbInfo)
|
82
92
|
{
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
if (cbInfo != NULL) {
|
89
|
-
if (cbInfo->parameterTypes != NULL) {
|
90
|
-
xfree(cbInfo->parameterTypes);
|
91
|
-
cbInfo->parameterTypes = NULL;
|
92
|
-
}
|
93
|
-
if (cbInfo->ffiParameterTypes != NULL) {
|
94
|
-
xfree(cbInfo->ffiParameterTypes);
|
95
|
-
cbInfo->ffiParameterTypes = NULL;
|
96
|
-
}
|
97
|
-
xfree(cbInfo);
|
93
|
+
if (cbInfo->parameterTypes != NULL) {
|
94
|
+
xfree(cbInfo->parameterTypes);
|
95
|
+
}
|
96
|
+
if (cbInfo->ffiParameterTypes != NULL) {
|
97
|
+
xfree(cbInfo->ffiParameterTypes);
|
98
98
|
}
|
99
|
+
xfree(cbInfo);
|
99
100
|
}
|
100
101
|
|
101
102
|
static void
|
102
103
|
native_callback_free(NativeCallback* cb)
|
103
104
|
{
|
104
|
-
if (cb != NULL) {
|
105
|
-
|
106
|
-
ffi_closure_free(cb->ffi_closure);
|
107
|
-
}
|
105
|
+
if (cb->ffi_closure != NULL) {
|
106
|
+
ffi_closure_free(cb->ffi_closure);
|
108
107
|
}
|
108
|
+
xfree(cb);
|
109
109
|
}
|
110
110
|
|
111
111
|
static void
|
@@ -209,30 +209,45 @@ native_callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user
|
|
209
209
|
}
|
210
210
|
}
|
211
211
|
|
212
|
+
static VALUE
|
213
|
+
native_callback_allocate(VALUE klass)
|
214
|
+
{
|
215
|
+
NativeCallback* closure;
|
216
|
+
VALUE obj;
|
217
|
+
|
218
|
+
obj = Data_Make_Struct(klass, NativeCallback, native_callback_mark, native_callback_free, closure);
|
219
|
+
closure->rbCallbackInfo = Qnil;
|
220
|
+
closure->rbProc = Qnil;
|
221
|
+
|
222
|
+
return obj;
|
223
|
+
}
|
224
|
+
|
212
225
|
VALUE
|
213
226
|
rb_FFI_NativeCallback_new(VALUE rbCallbackInfo, VALUE rbProc)
|
214
227
|
{
|
215
228
|
NativeCallback* closure = NULL;
|
216
|
-
CallbackInfo* cbInfo
|
229
|
+
CallbackInfo* cbInfo;
|
230
|
+
VALUE obj;
|
217
231
|
ffi_status status;
|
218
|
-
|
219
|
-
|
232
|
+
|
233
|
+
Data_Get_Struct(rbCallbackInfo, CallbackInfo, cbInfo);
|
234
|
+
obj = Data_Make_Struct(classNativeCallback, NativeCallback, native_callback_mark, native_callback_free, closure);
|
235
|
+
closure->cbInfo = cbInfo;
|
236
|
+
closure->rbProc = rbProc;
|
237
|
+
closure->rbCallbackInfo = rbCallbackInfo;
|
238
|
+
|
220
239
|
closure->ffi_closure = ffi_closure_alloc(sizeof(*closure->ffi_closure), &closure->code);
|
221
240
|
if (closure->ffi_closure == NULL) {
|
222
|
-
xfree(closure);
|
223
241
|
rb_raise(rb_eNoMemError, "Failed to allocate FFI native closure");
|
224
242
|
}
|
225
|
-
|
226
|
-
closure->rbProc = rbProc;
|
227
|
-
closure->rbCallbackInfo = rbCallbackInfo;
|
243
|
+
|
228
244
|
status = ffi_prep_closure_loc(closure->ffi_closure, &cbInfo->ffi_cif,
|
229
245
|
native_callback_invoke, closure, closure->code);
|
230
246
|
if (status != FFI_OK) {
|
231
|
-
ffi_closure_free(closure->ffi_closure);
|
232
|
-
xfree(closure);
|
233
247
|
rb_raise(rb_eArgError, "ffi_prep_closure_loc failed");
|
234
248
|
}
|
235
|
-
|
249
|
+
|
250
|
+
return obj;
|
236
251
|
}
|
237
252
|
|
238
253
|
VALUE
|
@@ -295,9 +310,13 @@ void
|
|
295
310
|
rb_FFI_Callback_Init()
|
296
311
|
{
|
297
312
|
VALUE moduleFFI = rb_define_module("FFI");
|
313
|
+
|
298
314
|
rb_FFI_CallbackInfo_class = classCallbackInfo = rb_define_class_under(moduleFFI, "CallbackInfo", rb_cObject);
|
299
|
-
|
315
|
+
rb_define_alloc_func(classCallbackInfo, cbinfo_allocate);
|
316
|
+
rb_define_method(classCallbackInfo, "initialize", cbinfo_initialize, 2);
|
317
|
+
|
300
318
|
classNativeCallback = rb_define_class_under(moduleFFI, "NativeCallback", rb_cObject);
|
319
|
+
rb_define_alloc_func(classNativeCallback, native_callback_allocate);
|
301
320
|
callID = rb_intern("call");
|
302
321
|
cbTableID = rb_intern("@__ffi_callback_table__");
|
303
322
|
}
|
data/ext/ffi_c/Invoker.c
CHANGED
@@ -621,16 +621,20 @@ static inline VALUE
|
|
621
621
|
ffi_invoke(ffi_cif* cif, void* function, NativeType returnType, void** ffiValues)
|
622
622
|
{
|
623
623
|
FFIStorage retval;
|
624
|
+
int error = 0;
|
625
|
+
|
624
626
|
#ifdef USE_RAW
|
625
627
|
ffi_raw_call(cif, FFI_FN(function), &retval, (ffi_raw *) ffiValues[0]);
|
626
628
|
#else
|
627
629
|
ffi_call(cif, FFI_FN(function), &retval, ffiValues);
|
628
630
|
#endif
|
629
631
|
#if defined(_WIN32) || defined(__WIN32__)
|
630
|
-
|
632
|
+
error = GetLastError();
|
631
633
|
#else
|
632
|
-
|
634
|
+
error = errno;
|
633
635
|
#endif
|
636
|
+
threadData->td_errno = error;
|
637
|
+
|
634
638
|
return rb_FFI_NativeValueToRuby(returnType, &retval);
|
635
639
|
}
|
636
640
|
static VALUE
|
data/ext/ffi_c/MemoryPointer.c
CHANGED
@@ -34,7 +34,10 @@ static VALUE
|
|
34
34
|
memptr_allocate(VALUE klass)
|
35
35
|
{
|
36
36
|
MemoryPointer* p;
|
37
|
-
|
37
|
+
VALUE obj = Data_Make_Struct(klass, MemoryPointer, NULL, memptr_release, p);
|
38
|
+
p->memory.ops = &rb_FFI_AbstractMemory_ops;
|
39
|
+
|
40
|
+
return obj;
|
38
41
|
}
|
39
42
|
|
40
43
|
static VALUE
|
data/ext/ffi_c/NativeLibrary.c
CHANGED
@@ -94,16 +94,13 @@ library_dlerror(VALUE self)
|
|
94
94
|
static void
|
95
95
|
library_free(Library* library)
|
96
96
|
{
|
97
|
-
|
98
|
-
// dlclose() on MacOS tends to segfault - avoid it
|
97
|
+
// dlclose() on MacOS tends to segfault - avoid it
|
99
98
|
#ifndef __APPLE__
|
100
|
-
|
101
|
-
|
102
|
-
}
|
103
|
-
#endif
|
104
|
-
library->handle = NULL;
|
105
|
-
xfree(library);
|
99
|
+
if (library->handle != NULL) {
|
100
|
+
dl_close(library->handle);
|
106
101
|
}
|
102
|
+
#endif
|
103
|
+
xfree(library);
|
107
104
|
}
|
108
105
|
|
109
106
|
#if defined(_WIN32) || defined(__WIN32__)
|
data/ext/ffi_c/NullPointer.c
CHANGED
@@ -9,6 +9,8 @@
|
|
9
9
|
|
10
10
|
static VALUE NullPointerError;
|
11
11
|
static VALUE classNullPointer;
|
12
|
+
static MemoryOps nullptr_ops;
|
13
|
+
|
12
14
|
VALUE rb_FFI_NullPointer_class;
|
13
15
|
VALUE rb_FFI_NullPointer_singleton;
|
14
16
|
|
@@ -21,6 +23,8 @@ rb_FFI_NullPointer_allocate(VALUE klass)
|
|
21
23
|
retval = Data_Make_Struct(klass, AbstractMemory, NULL, -1, p);
|
22
24
|
p->address = 0;
|
23
25
|
p->size = 0;
|
26
|
+
p->ops = &nullptr_ops;
|
27
|
+
|
24
28
|
return retval;
|
25
29
|
}
|
26
30
|
|
@@ -30,6 +34,18 @@ nullptr_op(int argc, VALUE* argv, VALUE self)
|
|
30
34
|
rb_raise(NullPointerError, "NULL Pointer access attempted");
|
31
35
|
}
|
32
36
|
|
37
|
+
static VALUE
|
38
|
+
nullptr_op_get(AbstractMemory* ptr, long offset)
|
39
|
+
{
|
40
|
+
rb_raise(NullPointerError, "NULL Pointer access attempted");
|
41
|
+
}
|
42
|
+
|
43
|
+
static void
|
44
|
+
nullptr_op_put(AbstractMemory* ptr, long offset, VALUE value)
|
45
|
+
{
|
46
|
+
rb_raise(NullPointerError, "NULL Pointer access attempted");
|
47
|
+
}
|
48
|
+
|
33
49
|
static VALUE
|
34
50
|
nullptr_inspect(VALUE self)
|
35
51
|
{
|
@@ -46,10 +62,13 @@ static VALUE
|
|
46
62
|
nullptr_equals(VALUE self, VALUE other)
|
47
63
|
{
|
48
64
|
AbstractMemory* p2;
|
65
|
+
|
49
66
|
if (!rb_obj_is_kind_of(other, rb_FFI_Pointer_class)) {
|
50
67
|
rb_raise(rb_eArgError, "Comparing Pointer with non Pointer");
|
51
68
|
}
|
69
|
+
|
52
70
|
Data_Get_Struct(other, AbstractMemory, p2);
|
71
|
+
|
53
72
|
return p2->address == 0 ? Qtrue : Qfalse;
|
54
73
|
}
|
55
74
|
|
@@ -59,6 +78,22 @@ nullptr_address(VALUE self)
|
|
59
78
|
return INT2NUM(0);
|
60
79
|
}
|
61
80
|
|
81
|
+
static MemoryOp nullptr_memory_op = { nullptr_op_get, nullptr_op_put };
|
82
|
+
|
83
|
+
static MemoryOps nullptr_ops = {
|
84
|
+
.int8 = &nullptr_memory_op,
|
85
|
+
.uint8 = &nullptr_memory_op,
|
86
|
+
.int16 = &nullptr_memory_op,
|
87
|
+
.int16 = &nullptr_memory_op,
|
88
|
+
.int32 = &nullptr_memory_op,
|
89
|
+
.uint32 = &nullptr_memory_op,
|
90
|
+
.int64 = &nullptr_memory_op,
|
91
|
+
.uint64 = &nullptr_memory_op,
|
92
|
+
.float32 = &nullptr_memory_op,
|
93
|
+
.float64 = &nullptr_memory_op,
|
94
|
+
.pointer = &nullptr_memory_op,
|
95
|
+
.strptr = &nullptr_memory_op,
|
96
|
+
};
|
62
97
|
|
63
98
|
void
|
64
99
|
rb_FFI_NullPointer_Init()
|
data/ext/ffi_c/Pointer.c
CHANGED
@@ -16,28 +16,36 @@ typedef struct Pointer {
|
|
16
16
|
VALUE rb_FFI_Pointer_class;
|
17
17
|
static VALUE classPointer = Qnil;
|
18
18
|
static void ptr_mark(Pointer* ptr);
|
19
|
-
static void ptr_free(Pointer* ptr);
|
20
19
|
|
21
20
|
VALUE
|
22
21
|
rb_FFI_Pointer_new(void* addr)
|
23
22
|
{
|
24
23
|
Pointer* p;
|
25
|
-
VALUE
|
24
|
+
VALUE obj;
|
25
|
+
|
26
26
|
if (addr == NULL) {
|
27
27
|
return rb_FFI_NullPointer_singleton;
|
28
28
|
}
|
29
|
-
|
29
|
+
|
30
|
+
obj = Data_Make_Struct(classPointer, Pointer, NULL, -1, p);
|
30
31
|
p->memory.address = addr;
|
31
32
|
p->memory.size = LONG_MAX;
|
33
|
+
p->memory.ops = &rb_FFI_AbstractMemory_ops;
|
32
34
|
p->parent = Qnil;
|
33
|
-
|
35
|
+
|
36
|
+
return obj;
|
34
37
|
}
|
35
38
|
|
36
39
|
static VALUE
|
37
40
|
ptr_allocate(VALUE klass)
|
38
41
|
{
|
39
42
|
Pointer* p;
|
40
|
-
|
43
|
+
VALUE obj;
|
44
|
+
|
45
|
+
obj = Data_Make_Struct(classPointer, Pointer, NULL, -1, p);
|
46
|
+
p->parent = Qnil;
|
47
|
+
|
48
|
+
return obj;
|
41
49
|
}
|
42
50
|
|
43
51
|
static VALUE
|
@@ -51,10 +59,11 @@ ptr_plus(VALUE self, VALUE offset)
|
|
51
59
|
Data_Get_Struct(self, AbstractMemory, ptr);
|
52
60
|
checkBounds(ptr, off, 1);
|
53
61
|
|
54
|
-
retval = Data_Make_Struct(classPointer, Pointer, ptr_mark,
|
62
|
+
retval = Data_Make_Struct(classPointer, Pointer, ptr_mark, -1, p);
|
55
63
|
|
56
64
|
p->memory.address = ptr->address + off;
|
57
65
|
p->memory.size = ptr->size == LONG_MAX ? LONG_MAX : ptr->size - off;
|
66
|
+
p->memory.ops = &rb_FFI_AbstractMemory_ops;
|
58
67
|
p->parent = self;
|
59
68
|
|
60
69
|
return retval;
|
@@ -76,7 +85,9 @@ static VALUE
|
|
76
85
|
ptr_null_p(VALUE self)
|
77
86
|
{
|
78
87
|
Pointer* ptr;
|
88
|
+
|
79
89
|
Data_Get_Struct(self, Pointer, ptr);
|
90
|
+
|
80
91
|
return ptr->memory.address == NULL ? Qtrue : Qfalse;
|
81
92
|
}
|
82
93
|
|
@@ -84,6 +95,7 @@ static VALUE
|
|
84
95
|
ptr_equals(VALUE self, VALUE other)
|
85
96
|
{
|
86
97
|
Pointer* ptr;
|
98
|
+
|
87
99
|
Data_Get_Struct(self, Pointer, ptr);
|
88
100
|
|
89
101
|
return ptr->memory.address == POINTER(other)->address ? Qtrue : Qfalse;
|
@@ -93,6 +105,7 @@ static VALUE
|
|
93
105
|
ptr_address(VALUE self)
|
94
106
|
{
|
95
107
|
Pointer* ptr;
|
108
|
+
|
96
109
|
Data_Get_Struct(self, Pointer, ptr);
|
97
110
|
|
98
111
|
return ULL2NUM((uintptr_t) ptr->memory.address);
|
@@ -101,15 +114,7 @@ ptr_address(VALUE self)
|
|
101
114
|
static void
|
102
115
|
ptr_mark(Pointer* ptr)
|
103
116
|
{
|
104
|
-
|
105
|
-
rb_gc_mark(ptr->parent);
|
106
|
-
}
|
107
|
-
}
|
108
|
-
|
109
|
-
static void
|
110
|
-
ptr_free(Pointer* ptr)
|
111
|
-
{
|
112
|
-
xfree(ptr);
|
117
|
+
rb_gc_mark(ptr->parent);
|
113
118
|
}
|
114
119
|
|
115
120
|
void
|
@@ -117,6 +122,7 @@ rb_FFI_Pointer_Init()
|
|
117
122
|
{
|
118
123
|
VALUE moduleFFI = rb_define_module("FFI");
|
119
124
|
rb_FFI_Pointer_class = classPointer = rb_define_class_under(moduleFFI, "Pointer", rb_FFI_AbstractMemory_class);
|
125
|
+
rb_global_variable(&rb_FFI_Pointer_class);
|
120
126
|
|
121
127
|
rb_define_alloc_func(classPointer, ptr_allocate);
|
122
128
|
rb_define_method(classPointer, "inspect", ptr_inspect, 0);
|
data/ext/ffi_c/Struct.c
CHANGED
@@ -29,12 +29,9 @@ typedef struct StructLayoutBuilder {
|
|
29
29
|
unsigned int offset;
|
30
30
|
} StructLayoutBuilder;
|
31
31
|
|
32
|
-
static void struct_field_mark(StructField *);
|
33
|
-
static void struct_field_free(StructField *);
|
34
32
|
static void struct_mark(Struct *);
|
35
|
-
static void struct_free(Struct *);
|
36
33
|
static void struct_layout_mark(StructLayout *);
|
37
|
-
static
|
34
|
+
static inline MemoryOp* ptr_get_op(AbstractMemory* ptr, int type);
|
38
35
|
|
39
36
|
VALUE rb_FFI_Struct_class = Qnil;
|
40
37
|
static VALUE classStruct = Qnil, classStructLayout = Qnil;
|
@@ -42,17 +39,11 @@ static VALUE classStructField = Qnil, classStructLayoutBuilder = Qnil;
|
|
42
39
|
static ID pointerID = 0, layoutID = 0, SIZE_ID, ALIGN_ID;
|
43
40
|
static ID getID = 0, putID = 0, to_ptr = 0;
|
44
41
|
|
45
|
-
#define FIELD_CAST(obj) ((StructField *)((TYPE(obj) == T_DATA && rb_obj_is_kind_of(obj, classStructField)) \
|
46
|
-
? DATA_PTR(obj) : (rb_raise(rb_eArgError, "StructField expected"), NULL)))
|
47
|
-
|
48
|
-
#define LAYOUT_CAST(obj) ((StructLayout *)((TYPE(obj) == T_DATA && rb_obj_is_kind_of(obj, classStructLayout)) \
|
49
|
-
? DATA_PTR(obj) : (rb_raise(rb_eArgError, "StructLayout expected"), NULL)))
|
50
|
-
|
51
42
|
static VALUE
|
52
43
|
struct_field_allocate(VALUE klass)
|
53
44
|
{
|
54
45
|
StructField* field;
|
55
|
-
return Data_Make_Struct(klass, StructField,
|
46
|
+
return Data_Make_Struct(klass, StructField, NULL, -1, field);
|
56
47
|
}
|
57
48
|
|
58
49
|
static VALUE
|
@@ -72,12 +63,14 @@ struct_field_initialize(int argc, VALUE* argv, VALUE self)
|
|
72
63
|
} else {
|
73
64
|
field->type = ~0;
|
74
65
|
}
|
66
|
+
|
75
67
|
#ifdef notyet
|
76
68
|
field->size = NUM2UINT(rb_const_get(klass, rb_intern("SIZE")));
|
77
69
|
field->align = NUM2UINT(rb_const_get(klass, rb_intern("ALIGN")));
|
78
70
|
#endif
|
79
71
|
rb_iv_set(self, "@off", offset);
|
80
72
|
rb_iv_set(self, "@info", info);
|
73
|
+
|
81
74
|
return self;
|
82
75
|
}
|
83
76
|
|
@@ -89,135 +82,67 @@ struct_field_offset(VALUE self)
|
|
89
82
|
return UINT2NUM(field->offset);
|
90
83
|
}
|
91
84
|
|
92
|
-
static
|
93
|
-
|
94
|
-
{
|
95
|
-
}
|
96
|
-
static void
|
97
|
-
struct_field_free(StructField *f)
|
85
|
+
static VALUE
|
86
|
+
struct_field_get(VALUE self, VALUE pointer)
|
98
87
|
{
|
99
|
-
|
100
|
-
|
88
|
+
StructField* f;
|
89
|
+
MemoryOp* op;
|
90
|
+
AbstractMemory* memory = MEMORY(pointer);
|
91
|
+
|
92
|
+
Data_Get_Struct(self, StructField, f);
|
93
|
+
op = ptr_get_op(memory, f->type);
|
94
|
+
if (op == NULL) {
|
95
|
+
VALUE name = rb_class_name(CLASS_OF(self));
|
96
|
+
rb_raise(rb_eArgError, "get not supported for %s", StringValueCStr(name));
|
97
|
+
return Qnil;
|
101
98
|
}
|
102
|
-
}
|
103
99
|
|
104
|
-
|
105
|
-
memory_address(VALUE self)
|
106
|
-
{
|
107
|
-
return ((AbstractMemory *)DATA_PTR((self)))->address;
|
100
|
+
return (*op->get)(memory, f->offset);
|
108
101
|
}
|
109
102
|
|
110
|
-
static
|
111
|
-
|
103
|
+
static VALUE
|
104
|
+
struct_field_put(VALUE self, VALUE pointer, VALUE value)
|
112
105
|
{
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
return
|
123
|
-
} else if (rb_respond_to(value, to_ptr)) {
|
124
|
-
VALUE ptr = rb_funcall2(value, to_ptr, 0, NULL);
|
125
|
-
if (rb_obj_is_kind_of(ptr, rb_FFI_Pointer_class) && TYPE(ptr) == T_DATA) {
|
126
|
-
return memory_address(ptr);
|
127
|
-
} else {
|
128
|
-
rb_raise(rb_eArgError, "to_ptr returned an invalid pointer");
|
129
|
-
}
|
130
|
-
} else {
|
131
|
-
rb_raise(rb_eArgError, "value is not a pointer");
|
106
|
+
StructField* f;
|
107
|
+
MemoryOp* op;
|
108
|
+
AbstractMemory* memory = MEMORY(pointer);
|
109
|
+
|
110
|
+
Data_Get_Struct(self, StructField, f);
|
111
|
+
op = ptr_get_op(memory, f->type);
|
112
|
+
if (op == NULL) {
|
113
|
+
VALUE name = rb_class_name(CLASS_OF(self));
|
114
|
+
rb_raise(rb_eArgError, "put not supported for %s", StringValueCStr(name));
|
115
|
+
return self;
|
132
116
|
}
|
133
|
-
|
117
|
+
|
118
|
+
(*op->put)(memory, f->offset, value);
|
134
119
|
|
135
|
-
|
136
|
-
pointer_new(char* value)
|
137
|
-
{
|
138
|
-
return rb_FFI_Pointer_new(value);
|
120
|
+
return self;
|
139
121
|
}
|
140
122
|
|
141
123
|
static inline char*
|
142
|
-
|
143
|
-
{
|
144
|
-
rb_raise(rb_eArgError, "Cannot set :string fields");
|
145
|
-
}
|
146
|
-
|
147
|
-
static inline VALUE
|
148
|
-
string_from_native(char* value)
|
124
|
+
memory_address(VALUE self)
|
149
125
|
{
|
150
|
-
return
|
151
|
-
}
|
152
|
-
|
153
|
-
#define FIELD_OP(name, type, toNative, fromNative) \
|
154
|
-
static VALUE struct_field_put_##name(VALUE self, VALUE pointer, VALUE value); \
|
155
|
-
static inline void ptr_put_##name(AbstractMemory* ptr, StructField* field, VALUE value); \
|
156
|
-
static inline VALUE ptr_get_##name(AbstractMemory* ptr, StructField* field); \
|
157
|
-
static inline void \
|
158
|
-
ptr_put_##name(AbstractMemory* ptr, StructField* field, VALUE value) \
|
159
|
-
{ \
|
160
|
-
type tmp = toNative(value); \
|
161
|
-
memcpy(ptr->address + field->offset, &tmp, sizeof(tmp)); \
|
162
|
-
} \
|
163
|
-
static inline VALUE \
|
164
|
-
ptr_get_##name(AbstractMemory* ptr, StructField* field) \
|
165
|
-
{ \
|
166
|
-
type tmp; \
|
167
|
-
memcpy(&tmp, ptr->address + field->offset, sizeof(tmp)); \
|
168
|
-
return fromNative(tmp); \
|
169
|
-
} \
|
170
|
-
static VALUE \
|
171
|
-
struct_field_put_##name(VALUE self, VALUE pointer, VALUE value) \
|
172
|
-
{ \
|
173
|
-
StructField* f; Data_Get_Struct(self, StructField, f); \
|
174
|
-
ptr_put_##name(MEMORY(pointer), f, value); \
|
175
|
-
return self; \
|
176
|
-
} \
|
177
|
-
static VALUE struct_field_get_##name(VALUE self, VALUE pointer); \
|
178
|
-
static VALUE \
|
179
|
-
struct_field_get_##name(VALUE self, VALUE pointer) \
|
180
|
-
{ \
|
181
|
-
StructField* f; Data_Get_Struct(self, StructField, f); \
|
182
|
-
return ptr_get_##name(MEMORY(pointer), f); \
|
126
|
+
return ((AbstractMemory *)DATA_PTR((self)))->address;
|
183
127
|
}
|
184
128
|
|
185
|
-
FIELD_OP(int8, int8_t, NUM2INT, INT2NUM);
|
186
|
-
FIELD_OP(uint8, uint8_t, NUM2UINT, UINT2NUM);
|
187
|
-
FIELD_OP(int16, int16_t, NUM2INT, INT2NUM);
|
188
|
-
FIELD_OP(uint16, uint16_t, NUM2UINT, UINT2NUM);
|
189
|
-
FIELD_OP(int32, int32_t, NUM2INT, INT2NUM);
|
190
|
-
FIELD_OP(uint32, uint32_t, NUM2UINT, UINT2NUM);
|
191
|
-
FIELD_OP(int64, int64_t, NUM2LL, LL2NUM);
|
192
|
-
FIELD_OP(uint64, uint64_t, NUM2ULL, ULL2NUM);
|
193
|
-
FIELD_OP(float32, float, NUM2DBL, rb_float_new);
|
194
|
-
FIELD_OP(float64, double, NUM2DBL, rb_float_new);
|
195
|
-
FIELD_OP(pointer, char*, pointer_native, pointer_new);
|
196
|
-
FIELD_OP(string, char*, string_to_native, string_from_native);
|
197
|
-
|
198
129
|
static VALUE
|
199
130
|
struct_allocate(VALUE klass)
|
200
131
|
{
|
201
132
|
Struct* s;
|
202
|
-
VALUE
|
133
|
+
VALUE obj = Data_Make_Struct(klass, Struct, struct_mark, -1, s);
|
203
134
|
|
204
135
|
s->rbPointer = Qnil;
|
205
|
-
s->pointer = NULL;
|
206
136
|
s->rbLayout = Qnil;
|
207
|
-
s->layout = NULL;
|
208
137
|
|
209
|
-
|
210
|
-
s->rbLayout = rb_cvar_get(klass, layoutID);
|
211
|
-
Data_Get_Struct(s->rbLayout, StructLayout, s->layout);
|
212
|
-
}
|
213
|
-
return retval;
|
138
|
+
return obj;
|
214
139
|
}
|
215
140
|
|
216
141
|
static VALUE
|
217
142
|
struct_initialize(int argc, VALUE* argv, VALUE self)
|
218
143
|
{
|
219
144
|
Struct* s;
|
220
|
-
VALUE rbPointer = Qnil, rest = Qnil;
|
145
|
+
VALUE rbPointer = Qnil, rest = Qnil, klass = CLASS_OF(self);
|
221
146
|
int nargs;
|
222
147
|
|
223
148
|
Data_Get_Struct(self, Struct, s);
|
@@ -227,37 +152,39 @@ struct_initialize(int argc, VALUE* argv, VALUE self)
|
|
227
152
|
/* Call up into ruby code to adjust the layout */
|
228
153
|
if (nargs > 1) {
|
229
154
|
s->rbLayout = rb_funcall2(CLASS_OF(self), rb_intern("layout"), RARRAY_LEN(rest), RARRAY_PTR(rest));
|
230
|
-
|
231
|
-
|
232
|
-
|
155
|
+
} else if (rb_cvar_defined(klass, layoutID)) {
|
156
|
+
s->rbLayout = rb_cvar_get(klass, layoutID);
|
157
|
+
} else {
|
158
|
+
rb_raise(rb_eRuntimeError, "No Struct layout configured");
|
159
|
+
}
|
233
160
|
|
234
|
-
|
161
|
+
if (!rb_obj_is_kind_of(s->rbLayout, classStructLayout)) {
|
162
|
+
rb_raise(rb_eRuntimeError, "Invalid Struct layout");
|
235
163
|
}
|
164
|
+
|
165
|
+
Data_Get_Struct(s->rbLayout, StructLayout, s->layout);
|
236
166
|
|
237
|
-
if (rbPointer
|
238
|
-
|
167
|
+
if (rbPointer != Qnil) {
|
168
|
+
s->pointer = MEMORY(rbPointer);
|
169
|
+
s->rbPointer = rbPointer;
|
170
|
+
} else {
|
171
|
+
s->rbPointer = rb_FFI_MemoryPointer_new(s->layout->size, 1, true);
|
172
|
+
s->pointer = (AbstractMemory *) DATA_PTR(s->rbPointer);
|
239
173
|
}
|
240
|
-
|
241
|
-
s->
|
242
|
-
|
243
|
-
|
174
|
+
|
175
|
+
if (s->pointer->ops == NULL) {
|
176
|
+
VALUE name = rb_class_name(CLASS_OF(s->rbPointer));
|
177
|
+
rb_raise(rb_eRuntimeError, "No memory ops set for %s", StringValueCStr(name));
|
178
|
+
}
|
179
|
+
|
244
180
|
return self;
|
245
181
|
}
|
246
182
|
|
247
183
|
static void
|
248
184
|
struct_mark(Struct *s)
|
249
185
|
{
|
250
|
-
|
251
|
-
|
252
|
-
}
|
253
|
-
if (s->rbLayout != Qnil) {
|
254
|
-
rb_gc_mark(s->rbLayout);
|
255
|
-
}
|
256
|
-
}
|
257
|
-
|
258
|
-
static void struct_free(Struct *s)
|
259
|
-
{
|
260
|
-
xfree(s);
|
186
|
+
rb_gc_mark(s->rbPointer);
|
187
|
+
rb_gc_mark(s->rbLayout);
|
261
188
|
}
|
262
189
|
|
263
190
|
static VALUE
|
@@ -268,54 +195,71 @@ struct_field(Struct* s, VALUE fieldName)
|
|
268
195
|
if (layout == NULL) {
|
269
196
|
rb_raise(rb_eRuntimeError, "layout not set for Struct");
|
270
197
|
}
|
198
|
+
|
271
199
|
rbField = rb_hash_aref(layout->rbFields, fieldName);
|
272
200
|
if (rbField == Qnil) {
|
273
201
|
VALUE str = rb_funcall2(fieldName, rb_intern("to_s"), 0, NULL);
|
274
202
|
rb_raise(rb_eArgError, "No such field '%s'", StringValuePtr(str));
|
275
203
|
}
|
204
|
+
|
276
205
|
return rbField;
|
277
206
|
}
|
278
207
|
|
279
|
-
static
|
280
|
-
|
208
|
+
static inline MemoryOp*
|
209
|
+
ptr_get_op(AbstractMemory* ptr, int type)
|
281
210
|
{
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
Data_Get_Struct(self, Struct, s);
|
287
|
-
rbField = struct_field(s, fieldName);
|
288
|
-
f = FIELD_CAST(rbField);
|
289
|
-
|
290
|
-
switch (f->type) {
|
211
|
+
if (ptr == NULL || ptr->ops == NULL) {
|
212
|
+
return NULL;
|
213
|
+
}
|
214
|
+
switch (type) {
|
291
215
|
case NATIVE_INT8:
|
292
|
-
return
|
216
|
+
return ptr->ops->int8;
|
293
217
|
case NATIVE_UINT8:
|
294
|
-
return
|
218
|
+
return ptr->ops->uint8;
|
295
219
|
case NATIVE_INT16:
|
296
|
-
return
|
220
|
+
return ptr->ops->int16;
|
297
221
|
case NATIVE_UINT16:
|
298
|
-
return
|
222
|
+
return ptr->ops->uint16;
|
299
223
|
case NATIVE_INT32:
|
300
|
-
return
|
224
|
+
return ptr->ops->int32;
|
301
225
|
case NATIVE_UINT32:
|
302
|
-
return
|
226
|
+
return ptr->ops->uint32;
|
303
227
|
case NATIVE_INT64:
|
304
|
-
return
|
228
|
+
return ptr->ops->int64;
|
305
229
|
case NATIVE_UINT64:
|
306
|
-
return
|
230
|
+
return ptr->ops->uint64;
|
307
231
|
case NATIVE_FLOAT32:
|
308
|
-
return
|
232
|
+
return ptr->ops->float32;
|
309
233
|
case NATIVE_FLOAT64:
|
310
|
-
return
|
234
|
+
return ptr->ops->float64;
|
311
235
|
case NATIVE_POINTER:
|
312
|
-
return
|
236
|
+
return ptr->ops->pointer;
|
313
237
|
case NATIVE_STRING:
|
314
|
-
return
|
238
|
+
return ptr->ops->strptr;
|
315
239
|
default:
|
316
|
-
|
317
|
-
|
240
|
+
return NULL;
|
241
|
+
}
|
242
|
+
}
|
243
|
+
|
244
|
+
static VALUE
|
245
|
+
struct_get_field(VALUE self, VALUE fieldName)
|
246
|
+
{
|
247
|
+
Struct* s;
|
248
|
+
VALUE rbField;
|
249
|
+
StructField* f;
|
250
|
+
MemoryOp* op;
|
251
|
+
|
252
|
+
Data_Get_Struct(self, Struct, s);
|
253
|
+
rbField = struct_field(s, fieldName);
|
254
|
+
f = (StructField *) DATA_PTR(rbField);
|
255
|
+
|
256
|
+
op = ptr_get_op(s->pointer, f->type);
|
257
|
+
if (op != NULL) {
|
258
|
+
return (*op->get)(s->pointer, f->offset);
|
318
259
|
}
|
260
|
+
|
261
|
+
/* call up to the ruby code to fetch the value */
|
262
|
+
return rb_funcall2(rbField, getID, 1, &s->rbPointer);
|
319
263
|
}
|
320
264
|
|
321
265
|
static VALUE
|
@@ -324,55 +268,24 @@ struct_put_field(VALUE self, VALUE fieldName, VALUE value)
|
|
324
268
|
Struct* s;
|
325
269
|
VALUE rbField;
|
326
270
|
StructField* f;
|
271
|
+
MemoryOp* op;
|
327
272
|
VALUE argv[2];
|
328
273
|
|
329
274
|
Data_Get_Struct(self, Struct, s);
|
330
275
|
rbField = struct_field(s, fieldName);
|
331
|
-
f =
|
276
|
+
f = (StructField *) DATA_PTR(rbField);
|
332
277
|
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
case NATIVE_UINT8:
|
338
|
-
ptr_put_uint8(s->pointer, f, value);
|
339
|
-
break;
|
340
|
-
case NATIVE_INT16:
|
341
|
-
ptr_put_int16(s->pointer, f, value);
|
342
|
-
break;
|
343
|
-
case NATIVE_UINT16:
|
344
|
-
ptr_put_uint16(s->pointer, f, value);
|
345
|
-
break;
|
346
|
-
case NATIVE_INT32:
|
347
|
-
ptr_put_int32(s->pointer, f, value);
|
348
|
-
break;
|
349
|
-
case NATIVE_UINT32:
|
350
|
-
ptr_put_uint32(s->pointer, f, value);
|
351
|
-
break;
|
352
|
-
case NATIVE_INT64:
|
353
|
-
ptr_put_int64(s->pointer, f, value);
|
354
|
-
break;
|
355
|
-
case NATIVE_UINT64:
|
356
|
-
ptr_put_uint64(s->pointer, f, value);
|
357
|
-
break;
|
358
|
-
case NATIVE_FLOAT32:
|
359
|
-
ptr_put_float32(s->pointer, f, value);
|
360
|
-
break;
|
361
|
-
case NATIVE_FLOAT64:
|
362
|
-
ptr_put_float64(s->pointer, f, value);
|
363
|
-
break;
|
364
|
-
case NATIVE_POINTER:
|
365
|
-
ptr_put_pointer(s->pointer, f, value);
|
366
|
-
break;
|
367
|
-
case NATIVE_STRING:
|
368
|
-
rb_raise(rb_eArgError, "Cannot set :string fields");
|
369
|
-
default:
|
370
|
-
/* call up to the ruby code to set the value */
|
371
|
-
argv[0] = s->rbPointer;
|
372
|
-
argv[1] = value;
|
373
|
-
rb_funcall2(rbField, putID, 2, argv);
|
374
|
-
break;
|
278
|
+
op = ptr_get_op(s->pointer, f->type);
|
279
|
+
if (op != NULL) {
|
280
|
+
(*op->put)(s->pointer, f->offset, value);
|
281
|
+
return self;
|
375
282
|
}
|
283
|
+
|
284
|
+
/* call up to the ruby code to set the value */
|
285
|
+
argv[0] = s->rbPointer;
|
286
|
+
argv[1] = value;
|
287
|
+
rb_funcall2(rbField, putID, 2, argv);
|
288
|
+
|
376
289
|
return self;
|
377
290
|
}
|
378
291
|
|
@@ -389,6 +302,7 @@ struct_set_pointer(VALUE self, VALUE pointer)
|
|
389
302
|
s->pointer = MEMORY(pointer);
|
390
303
|
s->rbPointer = pointer;
|
391
304
|
rb_ivar_set(self, pointerID, pointer);
|
305
|
+
|
392
306
|
return self;
|
393
307
|
}
|
394
308
|
|
@@ -396,7 +310,9 @@ static VALUE
|
|
396
310
|
struct_get_pointer(VALUE self)
|
397
311
|
{
|
398
312
|
Struct* s;
|
313
|
+
|
399
314
|
Data_Get_Struct(self, Struct, s);
|
315
|
+
|
400
316
|
return s->rbPointer;
|
401
317
|
}
|
402
318
|
|
@@ -409,8 +325,10 @@ struct_set_layout(VALUE self, VALUE layout)
|
|
409
325
|
if (!rb_obj_is_kind_of(layout, classStructLayout)) {
|
410
326
|
rb_raise(rb_eArgError, "Invalid Struct layout");
|
411
327
|
}
|
328
|
+
|
412
329
|
Data_Get_Struct(layout, StructLayout, s->layout);
|
413
330
|
rb_ivar_set(self, layoutID, layout);
|
331
|
+
|
414
332
|
return self;
|
415
333
|
}
|
416
334
|
|
@@ -418,6 +336,7 @@ static VALUE
|
|
418
336
|
struct_get_layout(VALUE self)
|
419
337
|
{
|
420
338
|
Struct* s;
|
339
|
+
|
421
340
|
Data_Get_Struct(self, Struct, s);
|
422
341
|
|
423
342
|
return s->rbLayout;
|
@@ -427,16 +346,22 @@ static VALUE
|
|
427
346
|
struct_layout_allocate(VALUE klass)
|
428
347
|
{
|
429
348
|
StructLayout* layout;
|
430
|
-
|
349
|
+
VALUE obj;
|
350
|
+
|
351
|
+
obj = Data_Make_Struct(klass, StructLayout, struct_layout_mark, -1, layout);
|
352
|
+
layout->rbFields = Qnil;
|
353
|
+
|
354
|
+
return obj;
|
431
355
|
}
|
432
356
|
|
433
357
|
static VALUE
|
434
358
|
struct_layout_initialize(VALUE self, VALUE field_names, VALUE fields, VALUE size, VALUE align)
|
435
359
|
{
|
436
360
|
StructLayout* layout;
|
361
|
+
int i;
|
437
362
|
|
438
363
|
Data_Get_Struct(self, StructLayout, layout);
|
439
|
-
layout->rbFields =
|
364
|
+
layout->rbFields = rb_hash_new();
|
440
365
|
layout->size = NUM2INT(size);
|
441
366
|
layout->align = NUM2INT(align);
|
442
367
|
|
@@ -445,6 +370,14 @@ struct_layout_initialize(VALUE self, VALUE field_names, VALUE fields, VALUE size
|
|
445
370
|
rb_iv_set(self, "@size", size);
|
446
371
|
rb_iv_set(self, "@align", align);
|
447
372
|
|
373
|
+
for (i = 0; i < RARRAY_LEN(field_names); ++i) {
|
374
|
+
VALUE name = RARRAY_PTR(field_names)[i];
|
375
|
+
VALUE field = rb_hash_aref(fields, name);
|
376
|
+
if (TYPE(field) != T_DATA || !rb_obj_is_kind_of(field, classStructField)) {
|
377
|
+
rb_raise(rb_eArgError, "Invalid field");
|
378
|
+
}
|
379
|
+
rb_hash_aset(layout->rbFields, name, field);
|
380
|
+
}
|
448
381
|
return self;
|
449
382
|
}
|
450
383
|
|
@@ -454,6 +387,7 @@ struct_layout_aref(VALUE self, VALUE field)
|
|
454
387
|
StructLayout* layout;
|
455
388
|
|
456
389
|
Data_Get_Struct(self, StructLayout, layout);
|
390
|
+
|
457
391
|
return rb_hash_aref(layout->rbFields, field);
|
458
392
|
}
|
459
393
|
|
@@ -461,15 +395,7 @@ struct_layout_aref(VALUE self, VALUE field)
|
|
461
395
|
static void
|
462
396
|
struct_layout_mark(StructLayout *layout)
|
463
397
|
{
|
464
|
-
|
465
|
-
rb_gc_mark(layout->rbFields);
|
466
|
-
}
|
467
|
-
}
|
468
|
-
|
469
|
-
static void
|
470
|
-
struct_layout_free(StructLayout *layout)
|
471
|
-
{
|
472
|
-
xfree(layout);
|
398
|
+
rb_gc_mark(layout->rbFields);
|
473
399
|
}
|
474
400
|
|
475
401
|
void
|
@@ -504,7 +430,9 @@ rb_FFI_Struct_Init()
|
|
504
430
|
rb_define_alloc_func(classStructField, struct_field_allocate);
|
505
431
|
rb_define_method(classStructField, "initialize", struct_field_initialize, -1);
|
506
432
|
rb_define_method(classStructField, "offset", struct_field_offset, 0);
|
507
|
-
|
433
|
+
rb_define_method(classStructField, "put", struct_field_put, 2);
|
434
|
+
rb_define_method(classStructField, "get", struct_field_get, 1);
|
435
|
+
|
508
436
|
rb_define_alloc_func(classStructLayout, struct_layout_allocate);
|
509
437
|
rb_define_method(classStructLayout, "initialize", struct_layout_initialize, 4);
|
510
438
|
rb_define_method(classStructLayout, "[]", struct_layout_aref, 1);
|
@@ -519,12 +447,10 @@ rb_FFI_Struct_Init()
|
|
519
447
|
#undef FIELD
|
520
448
|
#define FIELD(name, typeName, nativeType, T) do { \
|
521
449
|
typedef struct { char c; T v; } s; \
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
rb_define_const(klass, "SIZE", INT2NUM(sizeof(T)* 8)); \
|
527
|
-
rb_define_const(klass, "TYPE", INT2NUM(nativeType)); \
|
450
|
+
klass = rb_define_class_under(classStructLayoutBuilder, #name, classStructField); \
|
451
|
+
rb_define_const(klass, "ALIGN", INT2NUM((sizeof(s) - sizeof(T)) * 8)); \
|
452
|
+
rb_define_const(klass, "SIZE", INT2NUM(sizeof(T)* 8)); \
|
453
|
+
rb_define_const(klass, "TYPE", INT2NUM(nativeType)); \
|
528
454
|
} while(0)
|
529
455
|
|
530
456
|
FIELD(Signed8, int8, NATIVE_INT8, char);
|