nice-ffi 0.1 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog.txt +493 -0
- data/README.rdoc +23 -11
- data/docs/usage.rdoc +144 -37
- data/lib/nice-ffi.rb +10 -4
- data/lib/nice-ffi/autorelease.rb +112 -0
- data/lib/nice-ffi/{nicelibrary.rb → library.rb} +73 -45
- data/lib/nice-ffi/opaquestruct.rb +109 -0
- data/lib/nice-ffi/pathset.rb +404 -144
- data/lib/nice-ffi/{nicestruct.rb → struct.rb} +64 -19
- data/lib/nice-ffi/typedpointer.rb +20 -7
- metadata +11 -20
@@ -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
|
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
|
-
|
258
|
-
|
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,
|
310
|
-
# or wrapping (not copying!) a
|
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
|
-
|
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
|
349
|
+
when String
|
329
350
|
super() # Create empty struct
|
330
|
-
|
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 ).
|
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::
|
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
|
-
|
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
|
67
|
+
# Wrap a FFI::Pointer in a new struct of this type.
|
60
68
|
def wrap( pointer )
|
61
|
-
unless pointer.is_a? FFI::Pointer
|
69
|
+
unless pointer.is_a? FFI::Pointer
|
62
70
|
raise TypeError, "#{self.class}[ #{@type} ] cannot wrap #{pointer.type}"
|
63
71
|
end
|
64
|
-
|
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.
|
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-
|
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.
|
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
|
-
|
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/
|
42
|
+
- lib/nice-ffi/struct.rb
|
43
|
+
- lib/nice-ffi/opaquestruct.rb
|
53
44
|
- lib/nice-ffi/typedpointer.rb
|
54
|
-
- lib/nice-ffi/
|
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.
|
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
|