nice-ffi 0.1 → 0.2

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.
@@ -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