ffi 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. data/README.rdoc +51 -1
  2. data/Rakefile +47 -28
  3. data/ext/ffi_c/AbstractMemory.c +149 -65
  4. data/ext/ffi_c/AbstractMemory.h +34 -4
  5. data/ext/ffi_c/AutoPointer.c +15 -18
  6. data/ext/ffi_c/AutoPointer.h +2 -2
  7. data/ext/ffi_c/Buffer.c +79 -44
  8. data/ext/ffi_c/Callback.c +133 -62
  9. data/ext/ffi_c/Callback.h +11 -5
  10. data/ext/ffi_c/{NativeLibrary.c → DynamicLibrary.c} +88 -24
  11. data/ext/ffi_c/{NativeLibrary.h → DynamicLibrary.h} +1 -1
  12. data/ext/ffi_c/Invoker.c +154 -190
  13. data/ext/ffi_c/LastError.c +135 -0
  14. data/ext/ffi_c/LastError.h +18 -0
  15. data/ext/ffi_c/MemoryPointer.c +30 -20
  16. data/ext/ffi_c/MemoryPointer.h +3 -3
  17. data/ext/ffi_c/NullPointer.c +67 -28
  18. data/ext/ffi_c/Platform.c +9 -10
  19. data/ext/ffi_c/Platform.h +1 -1
  20. data/ext/ffi_c/Pointer.c +67 -30
  21. data/ext/ffi_c/Pointer.h +8 -6
  22. data/ext/ffi_c/Struct.c +202 -267
  23. data/ext/ffi_c/Struct.h +2 -2
  24. data/ext/ffi_c/Type.c +230 -0
  25. data/ext/ffi_c/Type.h +28 -0
  26. data/ext/ffi_c/Types.c +48 -6
  27. data/ext/ffi_c/Types.h +8 -2
  28. data/ext/ffi_c/endian.h +40 -0
  29. data/ext/ffi_c/extconf.rb +6 -5
  30. data/ext/ffi_c/ffi.c +21 -44
  31. data/ext/ffi_c/libffi.bsd.mk +34 -0
  32. data/ext/ffi_c/libffi.darwin.mk +30 -10
  33. data/ext/ffi_c/libffi.gnu.mk +29 -0
  34. data/ext/ffi_c/libffi.mk +4 -2
  35. data/ext/ffi_c/rbffi.h +6 -8
  36. data/gen/Rakefile +12 -0
  37. data/lib/ffi/autopointer.rb +1 -1
  38. data/lib/ffi/enum.rb +78 -0
  39. data/lib/ffi/ffi.rb +5 -6
  40. data/lib/ffi/io.rb +15 -1
  41. data/lib/ffi/library.rb +79 -18
  42. data/lib/ffi/pointer.rb +2 -2
  43. data/lib/ffi/struct.rb +68 -14
  44. data/lib/ffi/types.rb +6 -3
  45. data/lib/ffi/variadic.rb +2 -2
  46. data/lib/ffi.rb +10 -1
  47. data/spec/ffi/bool_spec.rb +24 -0
  48. data/spec/ffi/callback_spec.rb +217 -17
  49. data/spec/ffi/enum_spec.rb +164 -0
  50. data/spec/ffi/managed_struct_spec.rb +6 -1
  51. data/spec/ffi/number_spec.rb +30 -0
  52. data/spec/ffi/pointer_spec.rb +33 -8
  53. data/spec/ffi/rbx/memory_pointer_spec.rb +0 -6
  54. data/spec/ffi/spec_helper.rb +5 -1
  55. data/spec/ffi/string_spec.rb +65 -4
  56. data/spec/ffi/struct_callback_spec.rb +41 -0
  57. data/spec/ffi/struct_initialize_spec.rb +30 -0
  58. data/spec/ffi/struct_spec.rb +44 -21
  59. metadata +31 -69
  60. data/ext/ffi_c/ffi.mk +0 -23
  61. data/nbproject/Makefile-Default.mk +0 -57
  62. data/nbproject/Makefile-impl.mk +0 -123
  63. data/nbproject/Package-Default.bash +0 -72
  64. data/nbproject/configurations.xml +0 -293
  65. data/nbproject/private/configurations.xml +0 -22
  66. data/nbproject/private/private.xml +0 -7
  67. data/nbproject/project.properties +0 -0
  68. data/nbproject/project.xml +0 -15
  69. data/samples/getlogin.rb +0 -7
  70. data/samples/getpid.rb +0 -7
  71. data/samples/gettimeofday.rb +0 -17
  72. data/samples/hello.rb +0 -6
  73. data/samples/inotify.rb +0 -59
  74. data/samples/pty.rb +0 -75
  75. data/samples/qsort.rb +0 -20
  76. data/samples/sample_helper.rb +0 -6
data/ext/ffi_c/Struct.c CHANGED
@@ -29,30 +29,21 @@ 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
- VALUE rb_FFI_Struct_class = Qnil;
40
- static VALUE classStruct = Qnil, classStructLayout = Qnil;
41
- static VALUE classStructField = Qnil, classStructLayoutBuilder = Qnil;
42
- static ID pointerID = 0, layoutID = 0, SIZE_ID, ALIGN_ID;
43
- static ID getID = 0, putID = 0, to_ptr = 0;
44
-
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)))
36
+ VALUE rbffi_StructClass = Qnil;
37
+ static VALUE StructLayoutClass = Qnil;
38
+ static VALUE StructFieldClass = Qnil, StructLayoutBuilderClass = Qnil;
39
+ static ID pointer_var_id = 0, layout_var_id = 0, SIZE_ID, ALIGN_ID, TYPE_ID;
40
+ static ID get_id = 0, put_id = 0, to_ptr = 0, to_s = 0, layout_id = 0;
50
41
 
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
@@ -67,17 +58,19 @@ struct_field_initialize(int argc, VALUE* argv, VALUE self)
67
58
  nargs = rb_scan_args(argc, argv, "11", &offset, &info);
68
59
 
69
60
  field->offset = NUM2UINT(offset);
70
- if (rb_const_defined(CLASS_OF(self), rb_intern("TYPE"))) {
71
- field->type = NUM2UINT(rb_const_get(CLASS_OF(self), rb_intern("TYPE")));
61
+ if (rb_const_defined(CLASS_OF(self), TYPE_ID)) {
62
+ field->type = NUM2UINT(rb_const_get(CLASS_OF(self), TYPE_ID));
72
63
  } else {
73
64
  field->type = ~0;
74
65
  }
66
+
75
67
  #ifdef notyet
76
- field->size = NUM2UINT(rb_const_get(klass, rb_intern("SIZE")));
77
- field->align = NUM2UINT(rb_const_get(klass, rb_intern("ALIGN")));
68
+ field->size = NUM2UINT(rb_const_get(klass, SIZE_ID));
69
+ field->align = NUM2UINT(rb_const_get(klass, ALIGN_ID));
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);
@@ -226,38 +151,40 @@ struct_initialize(int argc, VALUE* argv, VALUE self)
226
151
 
227
152
  /* Call up into ruby code to adjust the layout */
228
153
  if (nargs > 1) {
229
- 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
- }
154
+ s->rbLayout = rb_funcall2(CLASS_OF(self), layout_id, RARRAY_LEN(rest), RARRAY_PTR(rest));
155
+ } else if (rb_cvar_defined(klass, layout_var_id)) {
156
+ s->rbLayout = rb_cvar_get(klass, layout_var_id);
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, StructLayoutClass)) {
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 = rbffi_MemoryPointer_NewInstance(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
- VALUE str = rb_funcall2(fieldName, rb_intern("to_s"), 0, NULL);
201
+ VALUE str = rb_funcall2(fieldName, 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, get_id, 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, put_id, 2, argv);
288
+
376
289
  return self;
377
290
  }
378
291
 
@@ -381,14 +294,15 @@ struct_set_pointer(VALUE self, VALUE pointer)
381
294
  {
382
295
  Struct* s;
383
296
 
384
- if (!rb_obj_is_kind_of(pointer, rb_FFI_AbstractMemory_class)) {
297
+ if (!rb_obj_is_kind_of(pointer, rbffi_AbstractMemoryClass)) {
385
298
  rb_raise(rb_eArgError, "Invalid pointer");
386
299
  }
387
300
 
388
301
  Data_Get_Struct(self, Struct, s);
389
302
  s->pointer = MEMORY(pointer);
390
303
  s->rbPointer = pointer;
391
- rb_ivar_set(self, pointerID, pointer);
304
+ rb_ivar_set(self, pointer_var_id, 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
 
@@ -406,11 +322,13 @@ struct_set_layout(VALUE self, VALUE layout)
406
322
  Struct* s;
407
323
  Data_Get_Struct(self, Struct, s);
408
324
 
409
- if (!rb_obj_is_kind_of(layout, classStructLayout)) {
325
+ if (!rb_obj_is_kind_of(layout, StructLayoutClass)) {
410
326
  rb_raise(rb_eArgError, "Invalid Struct layout");
411
327
  }
328
+
412
329
  Data_Get_Struct(layout, StructLayout, s->layout);
413
- rb_ivar_set(self, layoutID, layout);
330
+ rb_ivar_set(self, layout_var_id, 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, StructFieldClass)) {
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,70 +395,71 @@ 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
476
- rb_FFI_Struct_Init()
402
+ rbffi_Struct_Init(VALUE moduleFFI)
477
403
  {
478
- VALUE moduleFFI = rb_define_module("FFI");
479
- VALUE klass;
480
- rb_FFI_Struct_class = classStruct = rb_define_class_under(moduleFFI, "Struct", rb_cObject);
481
- classStructLayout = rb_define_class_under(moduleFFI, "StructLayout", rb_cObject);
482
- classStructLayoutBuilder = rb_define_class_under(moduleFFI, "StructLayoutBuilder", rb_cObject);
483
- classStructField = rb_define_class_under(classStructLayoutBuilder, "Field", rb_cObject);
484
-
485
- rb_define_alloc_func(classStruct, struct_allocate);
486
- rb_define_method(classStruct, "initialize", struct_initialize, -1);
487
-
488
- rb_define_alias(rb_singleton_class(classStruct), "alloc_in", "new");
489
- rb_define_alias(rb_singleton_class(classStruct), "alloc_out", "new");
490
- rb_define_alias(rb_singleton_class(classStruct), "alloc_inout", "new");
491
- rb_define_alias(rb_singleton_class(classStruct), "new_in", "new");
492
- rb_define_alias(rb_singleton_class(classStruct), "new_out", "new");
493
- rb_define_alias(rb_singleton_class(classStruct), "new_inout", "new");
404
+ VALUE klass, StructClass;
405
+ rbffi_StructClass = StructClass = rb_define_class_under(moduleFFI, "Struct", rb_cObject);
406
+ rb_global_variable(&rbffi_StructClass);
407
+
408
+ StructLayoutClass = rb_define_class_under(moduleFFI, "StructLayout", rb_cObject);
409
+ rb_global_variable(&StructLayoutClass);
494
410
 
495
- rb_define_method(classStruct, "pointer", struct_get_pointer, 0);
496
- rb_define_private_method(classStruct, "pointer=", struct_set_pointer, 1);
411
+ StructLayoutBuilderClass = rb_define_class_under(moduleFFI, "StructLayoutBuilder", rb_cObject);
412
+ rb_global_variable(&StructLayoutBuilderClass);
497
413
 
498
- rb_define_method(classStruct, "layout", struct_get_layout, 0);
499
- rb_define_private_method(classStruct, "layout=", struct_set_layout, 1);
414
+ StructFieldClass = rb_define_class_under(StructLayoutBuilderClass, "Field", rb_cObject);
415
+ rb_global_variable(&StructFieldClass);
500
416
 
501
- rb_define_method(classStruct, "[]", struct_get_field, 1);
502
- rb_define_method(classStruct, "[]=", struct_put_field, 2);
417
+ rb_define_alloc_func(StructClass, struct_allocate);
418
+ rb_define_method(StructClass, "initialize", struct_initialize, -1);
503
419
 
504
- rb_define_alloc_func(classStructField, struct_field_allocate);
505
- rb_define_method(classStructField, "initialize", struct_field_initialize, -1);
506
- rb_define_method(classStructField, "offset", struct_field_offset, 0);
420
+ rb_define_alias(rb_singleton_class(StructClass), "alloc_in", "new");
421
+ rb_define_alias(rb_singleton_class(StructClass), "alloc_out", "new");
422
+ rb_define_alias(rb_singleton_class(StructClass), "alloc_inout", "new");
423
+ rb_define_alias(rb_singleton_class(StructClass), "new_in", "new");
424
+ rb_define_alias(rb_singleton_class(StructClass), "new_out", "new");
425
+ rb_define_alias(rb_singleton_class(StructClass), "new_inout", "new");
426
+
427
+ rb_define_method(StructClass, "pointer", struct_get_pointer, 0);
428
+ rb_define_private_method(StructClass, "pointer=", struct_set_pointer, 1);
429
+
430
+ rb_define_method(StructClass, "layout", struct_get_layout, 0);
431
+ rb_define_private_method(StructClass, "layout=", struct_set_layout, 1);
432
+
433
+ rb_define_method(StructClass, "[]", struct_get_field, 1);
434
+ rb_define_method(StructClass, "[]=", struct_put_field, 2);
507
435
 
508
- rb_define_alloc_func(classStructLayout, struct_layout_allocate);
509
- rb_define_method(classStructLayout, "initialize", struct_layout_initialize, 4);
510
- rb_define_method(classStructLayout, "[]", struct_layout_aref, 1);
511
-
512
- pointerID = rb_intern("@pointer");
513
- layoutID = rb_intern("@layout");
514
- getID = rb_intern("get");
515
- putID = rb_intern("put");
436
+ rb_define_alloc_func(StructFieldClass, struct_field_allocate);
437
+ rb_define_method(StructFieldClass, "initialize", struct_field_initialize, -1);
438
+ rb_define_method(StructFieldClass, "offset", struct_field_offset, 0);
439
+ rb_define_method(StructFieldClass, "put", struct_field_put, 2);
440
+ rb_define_method(StructFieldClass, "get", struct_field_get, 1);
441
+
442
+ rb_define_alloc_func(StructLayoutClass, struct_layout_allocate);
443
+ rb_define_method(StructLayoutClass, "initialize", struct_layout_initialize, 4);
444
+ rb_define_method(StructLayoutClass, "[]", struct_layout_aref, 1);
445
+
446
+ pointer_var_id = rb_intern("@pointer");
447
+ layout_var_id = rb_intern("@layout");
448
+ layout_id = rb_intern("layout");
449
+ get_id = rb_intern("get");
450
+ put_id = rb_intern("put");
516
451
  to_ptr = rb_intern("to_ptr");
452
+ to_s = rb_intern("to_s");
517
453
  SIZE_ID = rb_intern("SIZE");
518
454
  ALIGN_ID = rb_intern("ALIGN");
455
+ TYPE_ID = rb_intern("TYPE");
519
456
  #undef FIELD
520
457
  #define FIELD(name, typeName, nativeType, T) do { \
521
458
  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)); \
459
+ klass = rb_define_class_under(StructLayoutBuilderClass, #name, StructFieldClass); \
460
+ rb_define_const(klass, "ALIGN", INT2NUM((sizeof(s) - sizeof(T)))); \
461
+ rb_define_const(klass, "SIZE", INT2NUM(sizeof(T))); \
462
+ rb_define_const(klass, "TYPE", INT2NUM(nativeType)); \
528
463
  } while(0)
529
464
 
530
465
  FIELD(Signed8, int8, NATIVE_INT8, char);