nice-ffi 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -28,11 +28,6 @@
28
28
  #++
29
29
 
30
30
 
31
- require 'ffi'
32
-
33
- need{ 'typedpointer' }
34
-
35
-
36
31
  # A class to be used as a baseclass where you would use FFI::Struct.
37
32
  # It acts mostly like FFI::Struct, but with nice extra features and
38
33
  # conveniences to make life easier:
@@ -49,16 +44,32 @@ need{ 'typedpointer' }
49
44
  # * Implements a nicer #new method which allows you to create a new
50
45
  # struct and set its data in one shot by passing an Array, Hash, or
51
46
  # another instance of the class (to copy data). You can also use it
52
- # to wrap a FFI::Pointer or FFI::MemoryPointer like FFI::Struct can.
47
+ # to wrap a FFI::Pointer like FFI::Struct can.
53
48
  #
54
49
  # * Implements #to_ary and #to_hash to dump the struct data.
55
50
  #
56
51
  # * Implements #to_s and #inspect for nice debugging output.
57
52
  #
53
+ # * Adds ::typed_pointer convenience alias to create a TypedPointer
54
+ # for this klass.
55
+ #
56
+ # * Provides automatic memory management for Pointers if you define
57
+ # MyClass.release( pointer). (This can be disabled per-instance by
58
+ # providing {:autorelease => false} as an option to #new).
59
+ #
58
60
  class NiceFFI::Struct < FFI::Struct
61
+ include NiceFFI::AutoRelease
59
62
 
60
63
  class << self
61
64
 
65
+ # Returns a NiceFFI::TypedPointer instance for this class.
66
+ # Equivalent to NiceFFI::TypedPointer.new( this_class, options )
67
+ #
68
+ def typed_pointer( options={} )
69
+ NiceFFI::TypedPointer.new(self, options)
70
+ end
71
+
72
+
62
73
  # Same syntax as FFI::Struct#layout, but also defines nice
63
74
  # accessors for the attributes.
64
75
  #
@@ -254,11 +265,8 @@ class NiceFFI::Struct < FFI::Struct
254
265
  else
255
266
  self.class_eval do
256
267
  define_method( member ) do
257
- begin
258
- self[member]
259
- rescue FFI::NullPointerError
260
- nil
261
- end
268
+ return nil if self.pointer.null?
269
+ return self[member]
262
270
  end
263
271
  end
264
272
  end
@@ -306,14 +314,27 @@ class NiceFFI::Struct < FFI::Struct
306
314
 
307
315
 
308
316
  # Create a new instance of the class, reading data from a Hash or
309
- # Array of attributes, copying from another instance of the class,
310
- # or wrapping (not copying!) a FFI::Pointer or FFI::MemoryPointer.
317
+ # Array of attributes, a bytestring of raw data, copying from
318
+ # another instance of the class, or wrapping (not copying!) a
319
+ # FFI::Pointer.
320
+ #
321
+ # If val is an instance of FFI::Pointer and you have defined
322
+ # MyClass.release, the pointer will be passed to MyClass.release
323
+ # when the memory is no longer being used. Use MyClass.release to
324
+ # free the memory for the struct, as appropriate for your class. To
325
+ # disable autorelease for this instance, set {:autorelease => false}
326
+ # in +options+.
311
327
  #
312
- def initialize( val )
328
+ # (Note: FFI::MemoryPointer and FFI::Buffer have built-in memory
329
+ # management, so MyClass.release is never called for them.)
330
+ #
331
+ def initialize( val, options={} )
313
332
  # Stores certain kinds of member values so that we don't need
314
333
  # to create a new object every time they are read.
315
334
  @member_cache = {}
316
335
 
336
+ options = {:autorelease => true}.merge!( options )
337
+
317
338
  case val
318
339
 
319
340
  when Hash
@@ -325,11 +346,17 @@ class NiceFFI::Struct < FFI::Struct
325
346
  super() # Create empty struct
326
347
  init_from_array( val ) # Read the values from an Array.
327
348
 
328
- when self.class
349
+ when String
329
350
  super() # Create empty struct
330
- init_from_array( val.to_ary ) # Read the values from another instance.
351
+ init_from_bytes( val ) # Read the values from a bytestring.
352
+
353
+ when self.class
354
+ super() # Create empty struct
355
+ init_from_bytes( val.to_bytes ) # Read the values from another instance.
356
+
357
+ when FFI::Pointer
358
+ val = _make_autopointer( val, options[:autorelease] )
331
359
 
332
- when FFI::Pointer, FFI::MemoryPointer
333
360
  # Normal FFI::Struct behavior to wrap the pointer.
334
361
  super( val )
335
362
 
@@ -356,6 +383,12 @@ class NiceFFI::Struct < FFI::Struct
356
383
  private :init_from_array
357
384
 
358
385
 
386
+ def init_from_bytes( val ) # :nodoc:
387
+ self.pointer.put_bytes(0, val)
388
+ end
389
+ private :init_from_bytes
390
+
391
+
359
392
 
360
393
  # Dump this instance as an Array of its struct data.
361
394
  # The array contains only the data, not the member names.
@@ -372,12 +405,20 @@ class NiceFFI::Struct < FFI::Struct
372
405
  members.collect{ |m| self[m] }
373
406
  end
374
407
 
408
+
409
+ # Dump this instance as a string of raw bytes of its struct data.
410
+ #
411
+ def to_bytes
412
+ return self.pointer.get_bytes(0, self.size)
413
+ end
414
+
415
+
375
416
  # Dump this instance as a Hash containing {member => data} pairs
376
417
  # for every member in the struct.
377
418
  #
378
419
  # Example:
379
420
  #
380
- # Rect.new( :x=>1, :y=>2, :w=>3, :h=>4 ).to_ary
421
+ # Rect.new( :x=>1, :y=>2, :w=>3, :h=>4 ).to_hash
381
422
  # # => {:h=>4, :w=>3, :x=>1, :y=>2}
382
423
  #
383
424
  def to_hash
@@ -387,12 +428,16 @@ class NiceFFI::Struct < FFI::Struct
387
428
 
388
429
 
389
430
  def to_s
431
+ if self.pointer.null?
432
+ return "#<NULL %s:%#.x>"%[self.class.name, self.object_id]
433
+ end
434
+
390
435
  mems = members.collect{ |m|
391
436
  unless self.class.hidden?( m )
392
437
  val = self.send(m)
393
438
 
394
439
  # Cleanup/simplify for display
395
- if val.is_a? FFI::NullPointer or val.nil?
440
+ if val.nil? or (val.is_a? FFI::Pointer and val.null?)
396
441
  val = "NULL"
397
442
  elsif val.kind_of? FFI::Struct
398
443
  val = "#<#{val.class}:%#.x>"%val.object_id
@@ -28,9 +28,6 @@
28
28
  #++
29
29
 
30
30
 
31
- require 'ffi'
32
-
33
-
34
31
  # TypedPointer represents a :pointer (FFI type) that is a specific
35
32
  # struct type. You can use TypedPointer( SomeStructClass ) instead
36
33
  # of :pointer in these situations:
@@ -46,22 +43,38 @@ class NiceFFI::TypedPointer
46
43
  # type must be a class (not an instance) which is a descendent of
47
44
  # FFI::Struct (or is FFI::Struct itself).
48
45
  #
49
- def initialize( type )
46
+ # options must be a Hash of zero or more options.
47
+ # The current meaningful options are:
48
+ #
49
+ # * :autorelease - If false, instances of NiceStruct and
50
+ # OpaqueStruct (and subclasses) created via this TypedPointer will
51
+ # be passed {:autorelease => false} to disable automatic memory
52
+ # management. Use this for return values of functions that should
53
+ # not be autoreleased.
54
+ #
55
+ def initialize( type, options={} )
50
56
  # unless type.is_a? Class and type.ancestors.include? FFI::Struct
51
57
  # raise TypeError, "#{self.class} only wraps FFI::Struct and subclasses."
52
58
  # end
53
59
  @type = type
60
+ options = {:autorelease => true}.merge!( options )
61
+ @autorelease = options[:autorelease]
54
62
  end
55
63
 
56
64
  attr_reader :type
57
65
 
58
66
 
59
- # Wrap a FFI::Pointer or FFI::MemoryPointer in a new struct of this type.
67
+ # Wrap a FFI::Pointer in a new struct of this type.
60
68
  def wrap( pointer )
61
- unless pointer.is_a? FFI::Pointer or pointer.is_a? FFI::MemoryPointer
69
+ unless pointer.is_a? FFI::Pointer
62
70
  raise TypeError, "#{self.class}[ #{@type} ] cannot wrap #{pointer.type}"
63
71
  end
64
- @type.new( pointer )
72
+
73
+ if @type.included_modules.include?( NiceFFI::AutoRelease )
74
+ @type.new( pointer, :autorelease => @autorelease )
75
+ else
76
+ @type.new( pointer )
77
+ end
65
78
  end
66
79
 
67
80
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nice-ffi
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.1"
4
+ version: "0.2"
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Croisant
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-05 00:00:00 -05:00
12
+ date: 2009-10-24 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -20,22 +20,11 @@ dependencies:
20
20
  requirements:
21
21
  - - ">="
22
22
  - !ruby/object:Gem::Version
23
- version: 0.3.0
24
- version:
25
- - !ruby/object:Gem::Dependency
26
- name: need
27
- type: :runtime
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: 1.1.0
23
+ version: 0.5.0
34
24
  version:
35
25
  description: |
36
- Nice-FFI is a layer on top of Ruby-FFI (and compatible FFI
37
- systems) to augment that library with features to aide
38
- development of FFI-based libraries.
26
+ Nice-FFI is a layer on top of Ruby-FFI (and compatible FFI systems)
27
+ with features to ease development of FFI-based libraries.
39
28
 
40
29
  email: jacius@gmail.com
41
30
  executables: []
@@ -48,10 +37,12 @@ files:
48
37
  - docs/usage.rdoc
49
38
  - TODO.rdoc
50
39
  - README.rdoc
40
+ - lib/nice-ffi/autorelease.rb
51
41
  - lib/nice-ffi/pathset.rb
52
- - lib/nice-ffi/nicelibrary.rb
42
+ - lib/nice-ffi/struct.rb
43
+ - lib/nice-ffi/opaquestruct.rb
53
44
  - lib/nice-ffi/typedpointer.rb
54
- - lib/nice-ffi/nicestruct.rb
45
+ - lib/nice-ffi/library.rb
55
46
  - lib/nice-ffi.rb
56
47
  - ChangeLog.txt
57
48
  has_rdoc: true
@@ -77,8 +68,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
77
68
  version:
78
69
  requirements: []
79
70
 
80
- rubyforge_project:
81
- rubygems_version: 1.3.3
71
+ rubyforge_project: nice-ffi
72
+ rubygems_version: 1.3.5
82
73
  signing_key:
83
74
  specification_version: 3
84
75
  summary: Convenience layer atop Ruby-FFI