ffi 0.4.0 → 0.5.0

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

Potentially problematic release.


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

Files changed (55) hide show
  1. data/README.rdoc +15 -15
  2. data/Rakefile +57 -8
  3. data/ext/ffi_c/AbstractMemory.c +101 -24
  4. data/ext/ffi_c/AbstractMemory.h +98 -6
  5. data/ext/ffi_c/ArrayType.c +129 -0
  6. data/ext/ffi_c/ArrayType.h +58 -0
  7. data/ext/ffi_c/AutoPointer.c +1 -0
  8. data/ext/ffi_c/Buffer.c +59 -43
  9. data/ext/ffi_c/Call.c +853 -0
  10. data/ext/ffi_c/Call.h +86 -0
  11. data/ext/ffi_c/ClosurePool.c +302 -0
  12. data/ext/ffi_c/ClosurePool.h +29 -0
  13. data/ext/ffi_c/DynamicLibrary.c +3 -0
  14. data/ext/ffi_c/Function.c +478 -0
  15. data/ext/ffi_c/Function.h +80 -0
  16. data/ext/ffi_c/FunctionInfo.c +221 -0
  17. data/ext/ffi_c/LastError.c +30 -6
  18. data/ext/ffi_c/MemoryPointer.c +50 -28
  19. data/ext/ffi_c/MethodHandle.c +346 -0
  20. data/ext/ffi_c/MethodHandle.h +53 -0
  21. data/ext/ffi_c/Pointer.c +73 -13
  22. data/ext/ffi_c/Pointer.h +31 -7
  23. data/ext/ffi_c/Struct.c +517 -224
  24. data/ext/ffi_c/Struct.h +60 -6
  25. data/ext/ffi_c/StructByValue.c +140 -0
  26. data/ext/ffi_c/StructByValue.h +53 -0
  27. data/ext/ffi_c/StructLayout.c +450 -0
  28. data/ext/ffi_c/Type.c +121 -22
  29. data/ext/ffi_c/Type.h +37 -8
  30. data/ext/ffi_c/Types.c +46 -61
  31. data/ext/ffi_c/Types.h +38 -7
  32. data/ext/ffi_c/Variadic.c +260 -0
  33. data/ext/ffi_c/compat.h +53 -3
  34. data/ext/ffi_c/extconf.rb +6 -7
  35. data/ext/ffi_c/ffi.c +45 -39
  36. data/ext/ffi_c/libffi.darwin.mk +2 -2
  37. data/ext/ffi_c/rbffi.h +3 -0
  38. data/lib/ffi/ffi.rb +7 -4
  39. data/lib/ffi/library.rb +34 -59
  40. data/lib/ffi/platform.rb +14 -4
  41. data/lib/ffi/struct.rb +110 -281
  42. data/lib/ffi/union.rb +4 -9
  43. data/lib/ffi/variadic.rb +1 -6
  44. data/spec/ffi/buffer_spec.rb +6 -0
  45. data/spec/ffi/callback_spec.rb +34 -3
  46. data/spec/ffi/function_spec.rb +73 -0
  47. data/spec/ffi/library_spec.rb +56 -52
  48. data/spec/ffi/pointer_spec.rb +3 -3
  49. data/spec/ffi/struct_callback_spec.rb +26 -3
  50. data/spec/ffi/struct_spec.rb +56 -3
  51. metadata +42 -11
  52. data/ext/ffi_c/Callback.c +0 -374
  53. data/ext/ffi_c/Callback.h +0 -47
  54. data/ext/ffi_c/Invoker.c +0 -962
  55. data/ext/ffi_c/NullPointer.c +0 -143
data/ext/ffi_c/Pointer.h CHANGED
@@ -1,6 +1,33 @@
1
-
2
- #ifndef _POINTER_H
3
- #define _POINTER_H
1
+ /*
2
+ * Copyright (c) 2008, 2009, Wayne Meissner
3
+ *
4
+ * All rights reserved.
5
+ *
6
+ * Redistribution and use in source and binary forms, with or without
7
+ * modification, are permitted provided that the following conditions are met:
8
+ *
9
+ * * Redistributions of source code must retain the above copyright notice, this
10
+ * list of conditions and the following disclaimer.
11
+ * * Redistributions in binary form must reproduce the above copyright notice
12
+ * this list of conditions and the following disclaimer in the documentation
13
+ * and/or other materials provided with the distribution.
14
+ * * The name of the author or authors may not be used to endorse or promote
15
+ * products derived from this software without specific prior written permission.
16
+ *
17
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ */
28
+
29
+ #ifndef RBFFI_POINTER_H
30
+ #define RBFFI_POINTER_H
4
31
 
5
32
  #ifdef __cplusplus
6
33
  extern "C" {
@@ -9,17 +36,14 @@ extern "C" {
9
36
  #include "AbstractMemory.h"
10
37
 
11
38
  extern void rbffi_Pointer_Init(VALUE moduleFFI);
12
- extern void rbffi_NullPointer_Init(VALUE moduleFFI);
13
39
  extern VALUE rbffi_Pointer_NewInstance(void* addr);
14
40
  extern VALUE rbffi_PointerClass;
15
- extern VALUE rbffi_NullPointerClass;
16
41
  extern VALUE rbffi_NullPointerSingleton;
17
- extern MemoryOps rbffi_NullPointerOps;
18
42
 
19
43
 
20
44
  #ifdef __cplusplus
21
45
  }
22
46
  #endif
23
47
 
24
- #endif /* _POINTER_H */
48
+ #endif /* RBFFI_POINTER_H */
25
49
 
data/ext/ffi_c/Struct.c CHANGED
@@ -1,4 +1,35 @@
1
+ /*
2
+ * Copyright (c) 2008, 2009, Wayne Meissner
3
+ * Copyright (c) 2009, Luc Heinrich <luc@honk-honk.com>
4
+ *
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions are met:
9
+ *
10
+ * * Redistributions of source code must retain the above copyright notice, this
11
+ * list of conditions and the following disclaimer.
12
+ * * Redistributions in binary form must reproduce the above copyright notice
13
+ * this list of conditions and the following disclaimer in the documentation
14
+ * and/or other materials provided with the distribution.
15
+ * * The name of the author or authors may not be used to endorse or promote
16
+ * products derived from this software without specific prior written permission.
17
+ *
18
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
22
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+ */
29
+
1
30
  #include <sys/types.h>
31
+
32
+ #include "Function.h"
2
33
  #include <sys/param.h>
3
34
  #include <stdint.h>
4
35
  #include <stdbool.h>
@@ -8,117 +39,46 @@
8
39
  #include "AbstractMemory.h"
9
40
  #include "Pointer.h"
10
41
  #include "MemoryPointer.h"
42
+ #include "Function.h"
11
43
  #include "Types.h"
12
44
  #include "Struct.h"
45
+ #include "StructByValue.h"
46
+ #include "ArrayType.h"
13
47
 
14
- typedef struct StructField {
15
- unsigned int type;
16
- unsigned int offset;
17
- unsigned int size;
18
- unsigned int align;
19
- } StructField;
20
-
21
- typedef struct StructLayout {
22
- VALUE rbFields;
23
- unsigned int fieldCount;
24
- int size;
25
- int align;
26
- } StructLayout;
48
+ #define FFI_ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1)
27
49
 
28
50
  typedef struct StructLayoutBuilder {
29
- unsigned int offset;
51
+ VALUE rbFieldNames;
52
+ VALUE rbFieldMap;
53
+ unsigned int size;
54
+ unsigned int alignment;
55
+ bool isUnion;
30
56
  } StructLayoutBuilder;
31
57
 
32
- static void struct_mark(Struct *);
33
- static void struct_layout_mark(StructLayout *);
34
- static inline MemoryOp* ptr_get_op(AbstractMemory* ptr, int type);
35
-
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;
41
-
42
- static VALUE
43
- struct_field_allocate(VALUE klass)
44
- {
45
- StructField* field;
46
- return Data_Make_Struct(klass, StructField, NULL, -1, field);
47
- }
58
+ typedef struct InlineArray_ {
59
+ VALUE rbMemory;
60
+ VALUE rbField;
48
61
 
49
- static VALUE
50
- struct_field_initialize(int argc, VALUE* argv, VALUE self)
51
- {
52
- VALUE offset = Qnil, info = Qnil;
62
+ AbstractMemory* memory;
53
63
  StructField* field;
54
- int nargs;
55
-
56
- Data_Get_Struct(self, StructField, field);
57
-
58
- nargs = rb_scan_args(argc, argv, "11", &offset, &info);
59
-
60
- field->offset = NUM2UINT(offset);
61
- if (rb_const_defined(CLASS_OF(self), TYPE_ID)) {
62
- field->type = NUM2UINT(rb_const_get(CLASS_OF(self), TYPE_ID));
63
- } else {
64
- field->type = ~0;
65
- }
66
-
67
- #ifdef notyet
68
- field->size = NUM2UINT(rb_const_get(klass, SIZE_ID));
69
- field->align = NUM2UINT(rb_const_get(klass, ALIGN_ID));
70
- #endif
71
- rb_iv_set(self, "@off", offset);
72
- rb_iv_set(self, "@info", info);
73
-
74
- return self;
75
- }
64
+ MemoryOp *op;
65
+ Type* componentType;
66
+ } InlineArray;
76
67
 
77
- static VALUE
78
- struct_field_offset(VALUE self)
79
- {
80
- StructField* field;
81
- Data_Get_Struct(self, StructField, field);
82
- return UINT2NUM(field->offset);
83
- }
84
68
 
85
- static VALUE
86
- struct_field_get(VALUE self, VALUE pointer)
87
- {
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;
98
- }
69
+ static void struct_mark(Struct *);
70
+ static void struct_layout_builder_mark(StructLayoutBuilder *);
71
+ static void struct_layout_builder_free(StructLayoutBuilder *);
72
+ static void inline_array_mark(InlineArray *);
99
73
 
100
- return (*op->get)(memory, f->offset);
101
- }
74
+ static inline int align(int offset, int align);
102
75
 
103
- static VALUE
104
- struct_field_put(VALUE self, VALUE pointer, VALUE value)
105
- {
106
- StructField* f;
107
- MemoryOp* op;
108
- AbstractMemory* memory = MEMORY(pointer);
76
+ VALUE rbffi_StructClass = Qnil;
77
+ static VALUE StructLayoutBuilderClass = Qnil;
109
78
 
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;
116
- }
117
-
118
- (*op->put)(memory, f->offset, value);
119
-
120
- return self;
121
- }
79
+ VALUE rbffi_StructInlineArrayClass = Qnil;
80
+ static ID id_pointer_ivar = 0, id_layout_ivar = 0;
81
+ static ID id_get = 0, id_put = 0, id_to_ptr = 0, id_to_s = 0, id_layout = 0;
122
82
 
123
83
  static inline char*
124
84
  memory_address(VALUE self)
@@ -151,14 +111,14 @@ struct_initialize(int argc, VALUE* argv, VALUE self)
151
111
 
152
112
  /* Call up into ruby code to adjust the layout */
153
113
  if (nargs > 1) {
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);
114
+ s->rbLayout = rb_funcall2(CLASS_OF(self), id_layout, RARRAY_LEN(rest), RARRAY_PTR(rest));
115
+ } else if (rb_cvar_defined(klass, id_layout_ivar)) {
116
+ s->rbLayout = rb_cvar_get(klass, id_layout_ivar);
157
117
  } else {
158
118
  rb_raise(rb_eRuntimeError, "No Struct layout configured");
159
119
  }
160
120
 
161
- if (!rb_obj_is_kind_of(s->rbLayout, StructLayoutClass)) {
121
+ if (!rb_obj_is_kind_of(s->rbLayout, rbffi_StructLayoutClass)) {
162
122
  rb_raise(rb_eRuntimeError, "Invalid Struct layout");
163
123
  }
164
124
 
@@ -196,53 +156,17 @@ struct_field(Struct* s, VALUE fieldName)
196
156
  rb_raise(rb_eRuntimeError, "layout not set for Struct");
197
157
  }
198
158
 
199
- rbField = rb_hash_aref(layout->rbFields, fieldName);
159
+ rbField = rb_hash_aref(layout->rbFieldMap, fieldName);
200
160
  if (rbField == Qnil) {
201
- VALUE str = rb_funcall2(fieldName, to_s, 0, NULL);
161
+ VALUE str = rb_funcall2(fieldName, id_to_s, 0, NULL);
202
162
  rb_raise(rb_eArgError, "No such field '%s'", StringValuePtr(str));
203
163
  }
204
164
 
205
165
  return rbField;
206
166
  }
207
167
 
208
- static inline MemoryOp*
209
- ptr_get_op(AbstractMemory* ptr, int type)
210
- {
211
- if (ptr == NULL || ptr->ops == NULL) {
212
- return NULL;
213
- }
214
- switch (type) {
215
- case NATIVE_INT8:
216
- return ptr->ops->int8;
217
- case NATIVE_UINT8:
218
- return ptr->ops->uint8;
219
- case NATIVE_INT16:
220
- return ptr->ops->int16;
221
- case NATIVE_UINT16:
222
- return ptr->ops->uint16;
223
- case NATIVE_INT32:
224
- return ptr->ops->int32;
225
- case NATIVE_UINT32:
226
- return ptr->ops->uint32;
227
- case NATIVE_INT64:
228
- return ptr->ops->int64;
229
- case NATIVE_UINT64:
230
- return ptr->ops->uint64;
231
- case NATIVE_FLOAT32:
232
- return ptr->ops->float32;
233
- case NATIVE_FLOAT64:
234
- return ptr->ops->float64;
235
- case NATIVE_POINTER:
236
- return ptr->ops->pointer;
237
- case NATIVE_STRING:
238
- return ptr->ops->strptr;
239
- default:
240
- return NULL;
241
- }
242
- }
243
-
244
168
  static VALUE
245
- struct_get_field(VALUE self, VALUE fieldName)
169
+ struct_aref(VALUE self, VALUE fieldName)
246
170
  {
247
171
  Struct* s;
248
172
  VALUE rbField;
@@ -253,17 +177,17 @@ struct_get_field(VALUE self, VALUE fieldName)
253
177
  rbField = struct_field(s, fieldName);
254
178
  f = (StructField *) DATA_PTR(rbField);
255
179
 
256
- op = ptr_get_op(s->pointer, f->type);
180
+ op = memory_get_op(s->pointer, f->type);
257
181
  if (op != NULL) {
258
182
  return (*op->get)(s->pointer, f->offset);
259
183
  }
260
184
 
261
185
  /* call up to the ruby code to fetch the value */
262
- return rb_funcall2(rbField, get_id, 1, &s->rbPointer);
186
+ return rb_funcall2(rbField, id_get, 1, &s->rbPointer);
263
187
  }
264
188
 
265
189
  static VALUE
266
- struct_put_field(VALUE self, VALUE fieldName, VALUE value)
190
+ struct_aset(VALUE self, VALUE fieldName, VALUE value)
267
191
  {
268
192
  Struct* s;
269
193
  VALUE rbField;
@@ -275,7 +199,7 @@ struct_put_field(VALUE self, VALUE fieldName, VALUE value)
275
199
  rbField = struct_field(s, fieldName);
276
200
  f = (StructField *) DATA_PTR(rbField);
277
201
 
278
- op = ptr_get_op(s->pointer, f->type);
202
+ op = memory_get_op(s->pointer, f->type);
279
203
  if (op != NULL) {
280
204
  (*op->put)(s->pointer, f->offset, value);
281
205
  return self;
@@ -284,7 +208,7 @@ struct_put_field(VALUE self, VALUE fieldName, VALUE value)
284
208
  /* call up to the ruby code to set the value */
285
209
  argv[0] = s->rbPointer;
286
210
  argv[1] = value;
287
- rb_funcall2(rbField, put_id, 2, argv);
211
+ rb_funcall2(rbField, id_put, 2, argv);
288
212
 
289
213
  return self;
290
214
  }
@@ -301,7 +225,7 @@ struct_set_pointer(VALUE self, VALUE pointer)
301
225
  Data_Get_Struct(self, Struct, s);
302
226
  s->pointer = MEMORY(pointer);
303
227
  s->rbPointer = pointer;
304
- rb_ivar_set(self, pointer_var_id, pointer);
228
+ rb_ivar_set(self, id_pointer_ivar, pointer);
305
229
 
306
230
  return self;
307
231
  }
@@ -322,12 +246,12 @@ struct_set_layout(VALUE self, VALUE layout)
322
246
  Struct* s;
323
247
  Data_Get_Struct(self, Struct, s);
324
248
 
325
- if (!rb_obj_is_kind_of(layout, StructLayoutClass)) {
249
+ if (!rb_obj_is_kind_of(layout, rbffi_StructLayoutClass)) {
326
250
  rb_raise(rb_eArgError, "Invalid Struct layout");
327
251
  }
328
252
 
329
253
  Data_Get_Struct(layout, StructLayout, s->layout);
330
- rb_ivar_set(self, layout_var_id, layout);
254
+ rb_ivar_set(self, id_layout_ivar, layout);
331
255
 
332
256
  return self;
333
257
  }
@@ -343,76 +267,451 @@ struct_get_layout(VALUE self)
343
267
  }
344
268
 
345
269
  static VALUE
346
- struct_layout_allocate(VALUE klass)
270
+ struct_layout_builder_allocate(VALUE klass)
347
271
  {
348
- StructLayout* layout;
272
+ StructLayoutBuilder* builder;
349
273
  VALUE obj;
350
-
351
- obj = Data_Make_Struct(klass, StructLayout, struct_layout_mark, -1, layout);
352
- layout->rbFields = Qnil;
274
+
275
+ obj = Data_Make_Struct(klass, StructLayoutBuilder, struct_layout_builder_mark, struct_layout_builder_free, builder);
276
+
277
+ builder->size = 0;
278
+ builder->alignment = 1;
279
+ builder->isUnion = false;
280
+ builder->rbFieldNames = rb_ary_new();
281
+ builder->rbFieldMap = rb_hash_new();
353
282
 
354
283
  return obj;
355
284
  }
356
285
 
286
+ static void
287
+ struct_layout_builder_mark(StructLayoutBuilder* builder)
288
+ {
289
+ rb_gc_mark(builder->rbFieldNames);
290
+ rb_gc_mark(builder->rbFieldMap);
291
+ }
292
+
293
+ static void
294
+ struct_layout_builder_free(StructLayoutBuilder* builder)
295
+ {
296
+ xfree(builder);
297
+ }
298
+
357
299
  static VALUE
358
- struct_layout_initialize(VALUE self, VALUE field_names, VALUE fields, VALUE size, VALUE align)
300
+ struct_layout_builder_initialize(VALUE self)
359
301
  {
360
- StructLayout* layout;
361
- int i;
302
+ StructLayoutBuilder* builder;
303
+
304
+ Data_Get_Struct(self, StructLayoutBuilder, builder);
305
+
306
+ return self;
307
+ }
308
+
309
+ static VALUE
310
+ struct_layout_builder_get_size(VALUE self)
311
+ {
312
+ StructLayoutBuilder* builder;
313
+
314
+ Data_Get_Struct(self, StructLayoutBuilder, builder);
315
+
316
+ return UINT2NUM(builder->size);
317
+ }
318
+
319
+ static VALUE
320
+ struct_layout_builder_set_size(VALUE self, VALUE rbSize)
321
+ {
322
+ StructLayoutBuilder* builder;
323
+ unsigned int size = NUM2UINT(rbSize);
324
+
325
+ Data_Get_Struct(self, StructLayoutBuilder, builder);
326
+ builder->size = MAX(size, builder->size);
327
+
328
+ return UINT2NUM(builder->size);
329
+ }
330
+
331
+ static VALUE
332
+ struct_layout_builder_get_alignment(VALUE self)
333
+ {
334
+ StructLayoutBuilder* builder;
335
+
336
+ Data_Get_Struct(self, StructLayoutBuilder, builder);
337
+
338
+ return UINT2NUM(builder->alignment);
339
+ }
340
+
341
+ static VALUE
342
+ struct_layout_builder_set_alignment(VALUE self, VALUE rbAlign)
343
+ {
344
+ StructLayoutBuilder* builder;
345
+ unsigned int align = NUM2UINT(rbAlign);
346
+
347
+ Data_Get_Struct(self, StructLayoutBuilder, builder);
348
+ builder->size = MAX(align, builder->alignment);
349
+
350
+ return UINT2NUM(builder->alignment);
351
+ }
362
352
 
363
- Data_Get_Struct(self, StructLayout, layout);
364
- layout->rbFields = rb_hash_new();
365
- layout->size = NUM2INT(size);
366
- layout->align = NUM2INT(align);
353
+ static VALUE
354
+ struct_layout_builder_set_union(VALUE self, VALUE rbUnion)
355
+ {
356
+ StructLayoutBuilder* builder;
357
+
358
+
359
+ Data_Get_Struct(self, StructLayoutBuilder, builder);
360
+ builder->isUnion = RTEST(rbUnion);
361
+
362
+ return rbUnion;
363
+ }
364
+
365
+ static VALUE
366
+ struct_layout_builder_union_p(VALUE self)
367
+ {
368
+ StructLayoutBuilder* builder;
369
+
370
+
371
+ Data_Get_Struct(self, StructLayoutBuilder, builder);
372
+
373
+
374
+ return builder->isUnion ? Qtrue : Qfalse;
375
+ }
376
+
377
+ static void
378
+ store_field(StructLayoutBuilder* builder, VALUE rbName, VALUE rbField,
379
+ unsigned int offset, unsigned int size, unsigned int alignment)
380
+ {
381
+ rb_ary_push(builder->rbFieldNames, rbName);
382
+ rb_hash_aset(builder->rbFieldMap, rbName, rbField);
383
+
384
+ builder->alignment = MAX(builder->alignment, alignment);
385
+
386
+ if (builder->isUnion) {
387
+ builder->size = MAX(builder->size, size);
388
+ } else {
389
+ builder->size = MAX(builder->size, offset + size);
390
+ }
391
+ }
392
+
393
+ static int
394
+ calculate_offset(StructLayoutBuilder* builder, int alignment, VALUE rbOffset)
395
+ {
396
+ if (rbOffset != Qnil) {
397
+ return NUM2UINT(rbOffset);
398
+ } else {
399
+ return builder->isUnion ? 0 : align(builder->size, alignment);
400
+ }
401
+ }
402
+
403
+ static VALUE
404
+ struct_layout_builder_add_field(int argc, VALUE* argv, VALUE self)
405
+ {
406
+ StructLayoutBuilder* builder;
407
+ VALUE rbName = Qnil, rbType = Qnil, rbOffset = Qnil, rbField = Qnil;
408
+ unsigned int size, alignment, offset;
409
+ int nargs;
410
+
411
+ nargs = rb_scan_args(argc, argv, "21", &rbName, &rbType, &rbOffset);
367
412
 
368
- rb_iv_set(self, "@field_names", field_names);
369
- rb_iv_set(self, "@fields", fields);
370
- rb_iv_set(self, "@size", size);
371
- rb_iv_set(self, "@align", align);
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");
413
+ Data_Get_Struct(self, StructLayoutBuilder, builder);
414
+
415
+ alignment = NUM2UINT(rb_funcall2(rbType, rb_intern("alignment"), 0, NULL));
416
+ size = NUM2UINT(rb_funcall2(rbType, rb_intern("size"), 0, NULL));
417
+
418
+ offset = calculate_offset(builder, alignment, rbOffset);
419
+
420
+ //
421
+ // If a primitive type was passed in as the type arg, try and convert
422
+ //
423
+ if (!rb_obj_is_kind_of(rbType, rbffi_StructLayoutFieldClass)) {
424
+ VALUE fargv[3], rbFieldClass;
425
+ fargv[0] = rbName;
426
+ fargv[1] = UINT2NUM(offset);
427
+ fargv[2] = rbType;
428
+ if (rb_obj_is_kind_of(rbType, rbffi_FunctionTypeClass)) {
429
+ rbFieldClass = rbffi_StructLayoutFunctionFieldClass;
430
+ } else if (rb_obj_is_kind_of(rbType, rbffi_StructByValueClass)) {
431
+ rbFieldClass = rbffi_StructLayoutStructFieldClass;
432
+ } else if (rb_obj_is_kind_of(rbType, rbffi_ArrayTypeClass)) {
433
+ rbFieldClass = rbffi_StructLayoutArrayFieldClass;
434
+ } else {
435
+ rbFieldClass = rbffi_StructLayoutFieldClass;
378
436
  }
379
- rb_hash_aset(layout->rbFields, name, field);
437
+
438
+ rbField = rb_class_new_instance(3, fargv, rbFieldClass);
439
+ } else {
440
+ rbField = rbType;
441
+ }
442
+
443
+ store_field(builder, rbName, rbField, offset, size, alignment);
444
+
445
+ return self;
446
+ }
447
+
448
+ static VALUE
449
+ struct_layout_builder_add_struct(int argc, VALUE* argv, VALUE self)
450
+ {
451
+ StructLayoutBuilder* builder;
452
+ VALUE rbName = Qnil, rbType = Qnil, rbOffset = Qnil, rbField = Qnil, rbStructClass = Qnil;
453
+ VALUE fargv[3];
454
+ unsigned int size, alignment, offset;
455
+ int nargs;
456
+
457
+ nargs = rb_scan_args(argc, argv, "21", &rbName, &rbStructClass, &rbOffset);
458
+
459
+ if (!rb_obj_is_instance_of(rbStructClass, rb_cClass) || !rb_class_inherited(rbStructClass, rbffi_StructClass)) {
460
+ rb_raise(rb_eTypeError, "wrong argument type. Expected subclass of FFI::Struct");
380
461
  }
462
+
463
+ rbType = rb_class_new_instance(1, &rbStructClass, rbffi_StructByValueClass);
464
+
465
+ alignment = NUM2UINT(rb_funcall2(rbType, rb_intern("alignment"), 0, NULL));
466
+ size = NUM2UINT(rb_funcall2(rbType, rb_intern("size"), 0, NULL));
467
+
468
+ Data_Get_Struct(self, StructLayoutBuilder, builder);
469
+
470
+ offset = calculate_offset(builder, alignment, rbOffset);
471
+
472
+ fargv[0] = rbName;
473
+ fargv[1] = UINT2NUM(offset);
474
+ fargv[2] = rbType;
475
+ rbField = rb_class_new_instance(3, fargv, rbffi_StructLayoutStructFieldClass);
476
+ store_field(builder, rbName, rbField, offset, size, alignment);
477
+
381
478
  return self;
382
479
  }
383
480
 
384
481
  static VALUE
385
- struct_layout_aref(VALUE self, VALUE field)
482
+ struct_layout_builder_add_array(int argc, VALUE* argv, VALUE self)
386
483
  {
387
- StructLayout* layout;
484
+ StructLayoutBuilder* builder;
485
+ VALUE rbName = Qnil, rbType = Qnil, rbLength = Qnil, rbOffset = Qnil, rbField;
486
+ VALUE fargv[3], aargv[2];
487
+ unsigned int size, alignment, offset;
488
+ int nargs;
489
+
490
+ nargs = rb_scan_args(argc, argv, "31", &rbName, &rbType, &rbLength, &rbOffset);
491
+
492
+ Data_Get_Struct(self, StructLayoutBuilder, builder);
493
+
494
+ alignment = NUM2UINT(rb_funcall2(rbType, rb_intern("alignment"), 0, NULL));
495
+ size = NUM2UINT(rb_funcall2(rbType, rb_intern("size"), 0, NULL)) * NUM2UINT(rbLength);
388
496
 
389
- Data_Get_Struct(self, StructLayout, layout);
497
+ offset = calculate_offset(builder, alignment, rbOffset);
390
498
 
391
- return rb_hash_aref(layout->rbFields, field);
499
+ aargv[0] = rbType;
500
+ aargv[1] = rbLength;
501
+ fargv[0] = rbName;
502
+ fargv[1] = UINT2NUM(offset);
503
+ fargv[2] = rb_class_new_instance(2, aargv, rbffi_ArrayTypeClass);
504
+ rbField = rb_class_new_instance(3, fargv, rbffi_StructLayoutArrayFieldClass);
505
+
506
+ store_field(builder, rbName, rbField, offset, size, alignment);
507
+
508
+ return self;
509
+ }
510
+
511
+ static inline int
512
+ align(int offset, int align)
513
+ {
514
+ return align + ((offset - 1) & ~(align - 1));
392
515
  }
393
516
 
517
+ static VALUE
518
+ struct_layout_builder_build(VALUE self)
519
+ {
520
+ StructLayoutBuilder* builder;
521
+ VALUE argv[4];
522
+
523
+ Data_Get_Struct(self, StructLayoutBuilder, builder);
524
+
525
+ argv[0] = builder->rbFieldNames;
526
+ argv[1] = builder->rbFieldMap;
527
+ argv[2] = UINT2NUM(align(builder->size, builder->alignment)); // tail padding
528
+ argv[3] = UINT2NUM(builder->alignment);
529
+
530
+ return rb_class_new_instance(4, argv, rbffi_StructLayoutClass);
531
+ }
532
+
533
+ static VALUE
534
+ inline_array_allocate(VALUE klass)
535
+ {
536
+ InlineArray* array;
537
+ VALUE obj;
538
+
539
+ obj = Data_Make_Struct(klass, InlineArray, inline_array_mark, -1, array);
540
+ array->rbField = Qnil;
541
+ array->rbMemory = Qnil;
542
+
543
+ return obj;
544
+ }
394
545
 
395
546
  static void
396
- struct_layout_mark(StructLayout *layout)
547
+ inline_array_mark(InlineArray* array)
548
+ {
549
+ rb_gc_mark(array->rbField);
550
+ rb_gc_mark(array->rbMemory);
551
+ }
552
+
553
+ static VALUE
554
+ inline_array_initialize(VALUE self, VALUE rbMemory, VALUE rbField)
555
+ {
556
+ InlineArray* array;
557
+ ArrayType* arrayType;
558
+
559
+ Data_Get_Struct(self, InlineArray, array);
560
+ array->rbMemory = rbMemory;
561
+ array->rbField = rbField;
562
+
563
+ Data_Get_Struct(rbMemory, AbstractMemory, array->memory);
564
+ Data_Get_Struct(rbField, StructField, array->field);
565
+ Data_Get_Struct(array->field->rbType, ArrayType, arrayType);
566
+ Data_Get_Struct(arrayType->rbComponentType, Type, array->componentType);
567
+
568
+ array->op = memory_get_op(array->memory, array->componentType);
569
+ if (array->op == NULL) {
570
+ rb_raise(rb_eRuntimeError, "invalid memory ops");
571
+ }
572
+
573
+ return self;
574
+ }
575
+
576
+ static VALUE
577
+ inline_array_size(VALUE self)
578
+ {
579
+ InlineArray* array;
580
+
581
+ Data_Get_Struct(self, InlineArray, array);
582
+
583
+ return UINT2NUM(array->field->type->ffiType->size);
584
+ }
585
+
586
+ static int
587
+ inline_array_offset(InlineArray* array, unsigned int index)
397
588
  {
398
- rb_gc_mark(layout->rbFields);
589
+ return array->field->offset + (index * array->componentType->ffiType->size);
399
590
  }
400
591
 
592
+ static VALUE
593
+ inline_array_aref(VALUE self, VALUE rbIndex)
594
+ {
595
+ InlineArray* array;
596
+
597
+ Data_Get_Struct(self, InlineArray, array);
598
+
599
+ return array->op->get(array->memory, inline_array_offset(array, NUM2UINT(rbIndex)));
600
+ }
601
+
602
+ static VALUE
603
+ inline_array_aset(VALUE self, VALUE rbIndex, VALUE rbValue)
604
+ {
605
+ InlineArray* array;
606
+
607
+ Data_Get_Struct(self, InlineArray, array);
608
+
609
+ array->op->put(array->memory, inline_array_offset(array, NUM2UINT(rbIndex)),
610
+ rbValue);
611
+
612
+ return rbValue;
613
+ }
614
+
615
+ static VALUE
616
+ inline_array_each(VALUE self)
617
+ {
618
+ InlineArray* array;
619
+ ArrayType* arrayType;
620
+
621
+ int i;
622
+
623
+ Data_Get_Struct(self, InlineArray, array);
624
+ Data_Get_Struct(array->field->rbType, ArrayType, arrayType);
625
+
626
+ for (i = 0; i < arrayType->length; ++i) {
627
+ int offset = inline_array_offset(array, i);
628
+ rb_yield(array->op->get(array->memory, offset));
629
+ }
630
+
631
+ return self;
632
+ }
633
+
634
+ static VALUE
635
+ inline_array_to_a(VALUE self)
636
+ {
637
+ InlineArray* array;
638
+ ArrayType* arrayType;
639
+ VALUE obj;
640
+ int i;
641
+
642
+ Data_Get_Struct(self, InlineArray, array);
643
+ Data_Get_Struct(array->field->rbType, ArrayType, arrayType);
644
+ obj = rb_ary_new2(arrayType->length);
645
+
646
+
647
+ for (i = 0; i < arrayType->length; ++i) {
648
+ int offset = inline_array_offset(array, i);
649
+ rb_ary_push(obj, array->op->get(array->memory, offset));
650
+ }
651
+
652
+ return obj;
653
+ }
654
+
655
+ static VALUE
656
+ inline_array_to_s(VALUE self)
657
+ {
658
+ InlineArray* array;
659
+ ArrayType* arrayType;
660
+ VALUE argv[2];
661
+
662
+ Data_Get_Struct(self, InlineArray, array);
663
+ Data_Get_Struct(array->field->rbType, ArrayType, arrayType);
664
+
665
+ if (arrayType->componentType->nativeType != NATIVE_INT8 && arrayType->componentType->nativeType != NATIVE_UINT8) {
666
+ rb_raise(rb_eNoMethodError, "to_s not defined for this array type");
667
+ return Qnil;
668
+ }
669
+
670
+ argv[0] = UINT2NUM(array->field->offset);
671
+ argv[1] = UINT2NUM(arrayType->length);
672
+
673
+ return rb_funcall2(array->rbMemory, rb_intern("get_string"), 2, argv);
674
+ }
675
+
676
+
677
+ static VALUE
678
+ inline_array_to_ptr(VALUE self)
679
+ {
680
+ InlineArray* array;
681
+ AbstractMemory* ptr;
682
+ VALUE rbOffset, rbPointer;
683
+
684
+ Data_Get_Struct(self, InlineArray, array);
685
+
686
+ rbOffset = UINT2NUM(array->field->offset);
687
+ rbPointer = rb_funcall2(array->rbMemory, rb_intern("+"), 1, &rbOffset);
688
+ Data_Get_Struct(rbPointer, AbstractMemory, ptr);
689
+
690
+ // Restrict the size of the pointer so ops like ptr.get_string(0) are bounds checked
691
+ ptr->size = MIN(ptr->size, array->field->type->ffiType->size);
692
+
693
+ return rbPointer;
694
+ }
695
+
696
+
401
697
  void
402
698
  rbffi_Struct_Init(VALUE moduleFFI)
403
699
  {
404
- VALUE klass, StructClass;
700
+ VALUE StructClass;
701
+
702
+ rbffi_StructLayout_Init(moduleFFI);
703
+
405
704
  rbffi_StructClass = StructClass = rb_define_class_under(moduleFFI, "Struct", rb_cObject);
406
705
  rb_global_variable(&rbffi_StructClass);
407
706
 
408
- StructLayoutClass = rb_define_class_under(moduleFFI, "StructLayout", rb_cObject);
409
- rb_global_variable(&StructLayoutClass);
410
707
 
411
708
  StructLayoutBuilderClass = rb_define_class_under(moduleFFI, "StructLayoutBuilder", rb_cObject);
412
709
  rb_global_variable(&StructLayoutBuilderClass);
413
710
 
414
- StructFieldClass = rb_define_class_under(StructLayoutBuilderClass, "Field", rb_cObject);
415
- rb_global_variable(&StructFieldClass);
711
+ rbffi_StructInlineArrayClass = rb_define_class_under(rbffi_StructClass, "InlineArray", rb_cObject);
712
+ rb_global_variable(&rbffi_StructInlineArrayClass);
713
+
714
+
416
715
 
417
716
  rb_define_alloc_func(StructClass, struct_allocate);
418
717
  rb_define_method(StructClass, "initialize", struct_initialize, -1);
@@ -430,48 +729,42 @@ rbffi_Struct_Init(VALUE moduleFFI)
430
729
  rb_define_method(StructClass, "layout", struct_get_layout, 0);
431
730
  rb_define_private_method(StructClass, "layout=", struct_set_layout, 1);
432
731
 
433
- rb_define_method(StructClass, "[]", struct_get_field, 1);
434
- rb_define_method(StructClass, "[]=", struct_put_field, 2);
732
+ rb_define_method(StructClass, "[]", struct_aref, 1);
733
+ rb_define_method(StructClass, "[]=", struct_aset, 2);
435
734
 
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");
451
- to_ptr = rb_intern("to_ptr");
452
- to_s = rb_intern("to_s");
453
- SIZE_ID = rb_intern("SIZE");
454
- ALIGN_ID = rb_intern("ALIGN");
455
- TYPE_ID = rb_intern("TYPE");
456
- #undef FIELD
457
- #define FIELD(name, typeName, nativeType, T) do { \
458
- typedef struct { char c; T v; } s; \
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)); \
463
- } while(0)
464
735
 
465
- FIELD(Signed8, int8, NATIVE_INT8, char);
466
- FIELD(Unsigned8, uint8, NATIVE_UINT8, unsigned char);
467
- FIELD(Signed16, int16, NATIVE_INT16, short);
468
- FIELD(Unsigned16, uint16, NATIVE_UINT16, unsigned short);
469
- FIELD(Signed32, int32, NATIVE_INT32, int);
470
- FIELD(Unsigned32, uint32, NATIVE_UINT32, unsigned int);
471
- FIELD(Signed64, int64, NATIVE_INT64, long long);
472
- FIELD(Unsigned64, uint64, NATIVE_UINT64, unsigned long long);
473
- FIELD(FloatField, float32, NATIVE_FLOAT32, float);
474
- FIELD(DoubleField, float64, NATIVE_FLOAT64, double);
475
- FIELD(PointerField, pointer, NATIVE_POINTER, char *);
476
- FIELD(StringField, string, NATIVE_STRING, char *);
736
+
737
+ rb_define_alloc_func(StructLayoutBuilderClass, struct_layout_builder_allocate);
738
+ rb_define_method(StructLayoutBuilderClass, "initialize", struct_layout_builder_initialize, 0);
739
+ rb_define_method(StructLayoutBuilderClass, "build", struct_layout_builder_build, 0);
740
+
741
+ rb_define_method(StructLayoutBuilderClass, "alignment", struct_layout_builder_get_alignment, 0);
742
+ rb_define_method(StructLayoutBuilderClass, "alignment=", struct_layout_builder_set_alignment, 1);
743
+ rb_define_method(StructLayoutBuilderClass, "size", struct_layout_builder_get_size, 0);
744
+ rb_define_method(StructLayoutBuilderClass, "size=", struct_layout_builder_set_size, 1);
745
+ rb_define_method(StructLayoutBuilderClass, "union=", struct_layout_builder_set_union, 1);
746
+ rb_define_method(StructLayoutBuilderClass, "union?", struct_layout_builder_union_p, 0);
747
+ rb_define_method(StructLayoutBuilderClass, "add_field", struct_layout_builder_add_field, -1);
748
+ rb_define_method(StructLayoutBuilderClass, "add_array", struct_layout_builder_add_array, -1);
749
+ rb_define_method(StructLayoutBuilderClass, "add_struct", struct_layout_builder_add_struct, -1);
750
+
751
+ rb_include_module(rbffi_StructInlineArrayClass, rb_mEnumerable);
752
+ rb_define_alloc_func(rbffi_StructInlineArrayClass, inline_array_allocate);
753
+ rb_define_method(rbffi_StructInlineArrayClass, "initialize", inline_array_initialize, 2);
754
+ rb_define_method(rbffi_StructInlineArrayClass, "[]", inline_array_aref, 1);
755
+ rb_define_method(rbffi_StructInlineArrayClass, "[]=", inline_array_aset, 2);
756
+ rb_define_method(rbffi_StructInlineArrayClass, "each", inline_array_each, 0);
757
+ rb_define_method(rbffi_StructInlineArrayClass, "size", inline_array_size, 0);
758
+ rb_define_method(rbffi_StructInlineArrayClass, "to_a", inline_array_to_a, 0);
759
+ rb_define_method(rbffi_StructInlineArrayClass, "to_s", inline_array_to_s, 0);
760
+ rb_define_alias(rbffi_StructInlineArrayClass, "to_str", "to_s");
761
+ rb_define_method(rbffi_StructInlineArrayClass, "to_ptr", inline_array_to_ptr, 0);
762
+
763
+ id_pointer_ivar = rb_intern("@pointer");
764
+ id_layout_ivar = rb_intern("@layout");
765
+ id_layout = rb_intern("layout");
766
+ id_get = rb_intern("get");
767
+ id_put = rb_intern("put");
768
+ id_to_ptr = rb_intern("to_ptr");
769
+ id_to_s = rb_intern("to_s");
477
770
  }