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.

@@ -15,8 +15,7 @@
15
15
  #include "extconf.h"
16
16
 
17
17
 
18
- static void CallbackInfo_mark(CallbackInfo *);
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
- CallbackInfo_new(VALUE klass, VALUE rbReturnType, VALUE rbParamTypes)
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
- VALUE retval;
40
- int paramCount = RARRAY_LEN(rbParamTypes);
45
+ int paramCount;
41
46
  ffi_status status;
42
47
  int i;
43
48
 
44
- retval = Data_Make_Struct(klass, CallbackInfo, CallbackInfo_mark, CallbackInfo_free, cbInfo);
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
- cbInfo->returnType = FIX2INT(rbReturnType);
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 retval;
87
+ return self;
78
88
  }
79
89
 
80
90
  static void
81
- CallbackInfo_mark(CallbackInfo* cbinfo)
91
+ cbinfo_free(CallbackInfo* cbInfo)
82
92
  {
83
- }
84
-
85
- static void
86
- CallbackInfo_free(CallbackInfo* cbInfo)
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
- if (cb->ffi_closure != NULL) {
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 = (CallbackInfo *) DATA_PTR(rbCallbackInfo);
229
+ CallbackInfo* cbInfo;
230
+ VALUE obj;
217
231
  ffi_status status;
218
-
219
- closure = ALLOC(NativeCallback);
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
- closure->cbInfo = cbInfo;
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
- return Data_Wrap_Struct(classNativeCallback, native_callback_mark, native_callback_free, closure);
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
- rb_define_singleton_method(classCallbackInfo, "new", CallbackInfo_new, 2);
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
  }
@@ -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
- threadData->td_errno = GetLastError();
632
+ error = GetLastError();
631
633
  #else
632
- threadData->td_errno = errno;
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
@@ -34,7 +34,10 @@ static VALUE
34
34
  memptr_allocate(VALUE klass)
35
35
  {
36
36
  MemoryPointer* p;
37
- return Data_Make_Struct(klass, MemoryPointer, NULL, memptr_release, p);
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
@@ -94,16 +94,13 @@ library_dlerror(VALUE self)
94
94
  static void
95
95
  library_free(Library* library)
96
96
  {
97
- if (library != NULL) {
98
- // dlclose() on MacOS tends to segfault - avoid it
97
+ // dlclose() on MacOS tends to segfault - avoid it
99
98
  #ifndef __APPLE__
100
- if (library->handle != NULL) {
101
- dl_close(library->handle);
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__)
@@ -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()
@@ -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 retval;
24
+ VALUE obj;
25
+
26
26
  if (addr == NULL) {
27
27
  return rb_FFI_NullPointer_singleton;
28
28
  }
29
- retval = Data_Make_Struct(classPointer, Pointer, NULL, ptr_free, p);
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
- return retval;
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
- return Data_Make_Struct(classPointer, Pointer, NULL, ptr_free, p);
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, ptr_free, p);
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
- if (ptr->parent != Qnil) {
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);
@@ -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 void struct_layout_free(StructLayout *);
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, struct_field_mark, struct_field_free, field);
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 void
93
- struct_field_mark(StructField *f)
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
- if (f != NULL) {
100
- xfree(f);
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
- static inline char*
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 inline char*
111
- pointer_native(VALUE value)
103
+ static VALUE
104
+ struct_field_put(VALUE self, VALUE pointer, VALUE value)
112
105
  {
113
- const int type = TYPE(value);
114
-
115
- if (rb_obj_is_kind_of(value, rb_FFI_Pointer_class) && type == T_DATA) {
116
- return memory_address(value);
117
- } else if (type == T_NIL) {
118
- return NULL;
119
- } else if (type == T_FIXNUM) {
120
- return (char *)(uintptr_t) FIX2INT(value);
121
- } else if (type == T_BIGNUM) {
122
- return (char *)(uintptr_t) NUM2ULL(value);
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
- static inline VALUE
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
- string_to_native(VALUE value)
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 value != NULL ? rb_tainted_str_new2(value) : Qnil;
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 retval = Data_Make_Struct(klass, Struct, struct_mark, struct_free, s);
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
- if (rb_cvar_defined(klass, layoutID)) {
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
- if (!rb_obj_is_kind_of(s->rbLayout, classStructLayout)) {
231
- rb_raise(rb_eRuntimeError, "Invalid Struct layout");
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
- Data_Get_Struct(s->rbLayout, StructLayout, s->layout);
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 == Qnil) {
238
- rbPointer = rb_FFI_MemoryPointer_new(s->layout->size, 1, true);
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->rbPointer = rbPointer;
242
- s->pointer = MEMORY(rbPointer);
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
- if (s->rbPointer != Qnil) {
251
- rb_gc_mark(s->rbPointer);
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 VALUE
280
- struct_get_field(VALUE self, VALUE fieldName)
208
+ static inline MemoryOp*
209
+ ptr_get_op(AbstractMemory* ptr, int type)
281
210
  {
282
- Struct* s;
283
- VALUE rbField;
284
- StructField* f;
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 ptr_get_int8(s->pointer, f);
216
+ return ptr->ops->int8;
293
217
  case NATIVE_UINT8:
294
- return ptr_get_uint8(s->pointer, f);
218
+ return ptr->ops->uint8;
295
219
  case NATIVE_INT16:
296
- return ptr_get_int16(s->pointer, f);
220
+ return ptr->ops->int16;
297
221
  case NATIVE_UINT16:
298
- return ptr_get_uint16(s->pointer, f);
222
+ return ptr->ops->uint16;
299
223
  case NATIVE_INT32:
300
- return ptr_get_int32(s->pointer, f);
224
+ return ptr->ops->int32;
301
225
  case NATIVE_UINT32:
302
- return ptr_get_uint32(s->pointer, f);
226
+ return ptr->ops->uint32;
303
227
  case NATIVE_INT64:
304
- return ptr_get_int64(s->pointer, f);
228
+ return ptr->ops->int64;
305
229
  case NATIVE_UINT64:
306
- return ptr_get_uint64(s->pointer, f);
230
+ return ptr->ops->uint64;
307
231
  case NATIVE_FLOAT32:
308
- return ptr_get_float32(s->pointer, f);
232
+ return ptr->ops->float32;
309
233
  case NATIVE_FLOAT64:
310
- return ptr_get_float64(s->pointer, f);
234
+ return ptr->ops->float64;
311
235
  case NATIVE_POINTER:
312
- return ptr_get_pointer(s->pointer, f);
236
+ return ptr->ops->pointer;
313
237
  case NATIVE_STRING:
314
- return ptr_get_string(s->pointer, f);
238
+ return ptr->ops->strptr;
315
239
  default:
316
- /* call up to the ruby code to fetch the value */
317
- return rb_funcall2(rbField, getID, 1, &s->rbPointer);
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 = FIELD_CAST(rbField);
276
+ f = (StructField *) DATA_PTR(rbField);
332
277
 
333
- switch (f->type) {
334
- case NATIVE_INT8:
335
- ptr_put_int8(s->pointer, f, value);
336
- break;
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
- return Data_Make_Struct(klass, StructLayout, struct_layout_mark, struct_layout_free, layout);
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 = fields;
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
- if (layout->rbFields != Qnil) {
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
- klass = rb_define_class_under(classStructLayoutBuilder, #name, classStructField); \
523
- rb_define_method(klass, "put", struct_field_put_##typeName, 2); \
524
- rb_define_method(klass, "get", struct_field_get_##typeName, 1); \
525
- rb_define_const(klass, "ALIGN", INT2NUM((sizeof(s) - sizeof(T)) * 8)); \
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);