ffi_dry 0.1.3 → 0.1.4
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.
- data/History.txt +5 -0
- data/Rakefile +3 -2
- data/VERSION +1 -1
- data/ffi_dry.gemspec +8 -4
- data/lib/ffi/dry.rb +116 -24
- metadata +15 -4
data/History.txt
ADDED
data/Rakefile
CHANGED
@@ -7,11 +7,11 @@ begin
|
|
7
7
|
Jeweler::Tasks.new do |gem|
|
8
8
|
gem.name = "ffi_dry"
|
9
9
|
gem.summary = %Q{Syntactic sugar and helper utilities for FFI}
|
10
|
-
gem.description = %Q{Provides
|
10
|
+
gem.description = %Q{Provides some useful modules, classes, and methods for FFI bindings as well as a DSL-like syntax for FFI::Struct layouts}
|
11
11
|
gem.email = "emonti@matasano.com"
|
12
12
|
gem.homepage = "http://github.com/emonti/ffi_dry"
|
13
13
|
gem.authors = ["Eric Monti"]
|
14
|
-
|
14
|
+
gem.add_dependency "ffi", ">= 0.5.0"
|
15
15
|
gem.add_development_dependency "rspec"
|
16
16
|
gem.add_development_dependency "yard"
|
17
17
|
end
|
@@ -55,6 +55,7 @@ Rake::RDocTask.new do |rdoc|
|
|
55
55
|
rdoc.rdoc_dir = 'rdoc'
|
56
56
|
rdoc.title = "ffi_dry #{version}"
|
57
57
|
rdoc.rdoc_files.include('README*')
|
58
|
+
rdoc.rdoc_files.include('History.txt')
|
58
59
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
59
60
|
end
|
60
61
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.4
|
data/ffi_dry.gemspec
CHANGED
@@ -5,12 +5,12 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{ffi_dry}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.4"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Eric Monti"]
|
12
|
-
s.date = %q{
|
13
|
-
s.description = %q{Provides
|
12
|
+
s.date = %q{2010-01-02}
|
13
|
+
s.description = %q{Provides some useful modules, classes, and methods for FFI bindings as well as a DSL-like syntax for FFI::Struct layouts}
|
14
14
|
s.email = %q{emonti@matasano.com}
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"LICENSE",
|
@@ -19,6 +19,7 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.files = [
|
20
20
|
".document",
|
21
21
|
".gitignore",
|
22
|
+
"History.txt",
|
22
23
|
"LICENSE",
|
23
24
|
"README.rdoc",
|
24
25
|
"Rakefile",
|
@@ -35,7 +36,7 @@ Gem::Specification.new do |s|
|
|
35
36
|
s.homepage = %q{http://github.com/emonti/ffi_dry}
|
36
37
|
s.rdoc_options = ["--charset=UTF-8"]
|
37
38
|
s.require_paths = ["lib"]
|
38
|
-
s.rubygems_version = %q{1.3.
|
39
|
+
s.rubygems_version = %q{1.3.5}
|
39
40
|
s.summary = %q{Syntactic sugar and helper utilities for FFI}
|
40
41
|
s.test_files = [
|
41
42
|
"spec/ffi_dry_spec.rb",
|
@@ -47,13 +48,16 @@ Gem::Specification.new do |s|
|
|
47
48
|
s.specification_version = 3
|
48
49
|
|
49
50
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
51
|
+
s.add_runtime_dependency(%q<ffi>, [">= 0.5.0"])
|
50
52
|
s.add_development_dependency(%q<rspec>, [">= 0"])
|
51
53
|
s.add_development_dependency(%q<yard>, [">= 0"])
|
52
54
|
else
|
55
|
+
s.add_dependency(%q<ffi>, [">= 0.5.0"])
|
53
56
|
s.add_dependency(%q<rspec>, [">= 0"])
|
54
57
|
s.add_dependency(%q<yard>, [">= 0"])
|
55
58
|
end
|
56
59
|
else
|
60
|
+
s.add_dependency(%q<ffi>, [">= 0.5.0"])
|
57
61
|
s.add_dependency(%q<rspec>, [">= 0"])
|
58
62
|
s.add_dependency(%q<yard>, [">= 0"])
|
59
63
|
end
|
data/lib/ffi/dry.rb
CHANGED
@@ -5,7 +5,7 @@ require 'ffi'
|
|
5
5
|
module FFI::DRY
|
6
6
|
|
7
7
|
# A module to add syntactic sugar and some nice automatic getter/setter
|
8
|
-
#
|
8
|
+
# methods to FFI::Struct, FFI::ManagedStruct, etc.
|
9
9
|
#
|
10
10
|
# For example:
|
11
11
|
# require 'rubygems'
|
@@ -54,16 +54,20 @@ module FFI::DRY
|
|
54
54
|
# # ["ss3", [1, 0]]
|
55
55
|
# # ["ss4", [1, 65535]]
|
56
56
|
#
|
57
|
-
module StructHelper
|
57
|
+
module StructHelper
|
58
58
|
|
59
59
|
attr_reader :dsl_metadata
|
60
60
|
|
61
|
-
#
|
62
|
-
# a "yield(self) if block_given?" at the end.
|
61
|
+
# Allows setting structure fields on initialization to ::FFI::Struct.new
|
62
|
+
# as well as a "yield(self) if block_given?" at the end.
|
63
63
|
#
|
64
|
-
#
|
65
|
-
#
|
64
|
+
# Field initialization happens if there is only one argument and it is
|
65
|
+
# a Hash.
|
66
66
|
#
|
67
|
+
# The params hash is taken as a set of values for fields where the hash
|
68
|
+
# keys specify the field names to set.
|
69
|
+
#
|
70
|
+
# @param [Hash] params
|
67
71
|
# Note:
|
68
72
|
# The :raw parameter is a special tag in the hash. The value is taken as a
|
69
73
|
# string and initialized into a new FFI::MemoryPointer which this Struct
|
@@ -148,15 +152,13 @@ module FFI::DRY
|
|
148
152
|
|
149
153
|
private
|
150
154
|
|
151
|
-
# This passes a block to an instance of
|
152
|
-
# for a more declarative syntax.
|
155
|
+
# This passes a block to an instance of DSLStructLayoutBuilder, allowing
|
156
|
+
# for a more declarative syntax with extra metadata.
|
153
157
|
#
|
154
158
|
# It is a replacement to layout() and stores the dsl_metadata gathered
|
155
159
|
# about structure members locally.
|
156
|
-
#
|
157
|
-
#
|
158
160
|
def dsl_layout &block
|
159
|
-
builder =
|
161
|
+
builder = DSLStructLayoutBuilder.new(self)
|
160
162
|
builder.instance_eval(&block)
|
161
163
|
@layout = builder.build
|
162
164
|
@size = @layout.size
|
@@ -197,7 +199,7 @@ module FFI::DRY
|
|
197
199
|
#
|
198
200
|
# See the individual method descriptions for more info.
|
199
201
|
#
|
200
|
-
class
|
202
|
+
class DSLStructLayoutBuilder
|
201
203
|
attr_reader :builder, :metadata
|
202
204
|
|
203
205
|
# Initializes the builder with a reference to the structure using it
|
@@ -277,25 +279,39 @@ module FFI::DRY
|
|
277
279
|
return ret
|
278
280
|
end
|
279
281
|
|
282
|
+
# This is a support method used similarly as in the actual builder.
|
283
|
+
# XXX Note, as of 0.5.0-final, this became a protected method in the
|
284
|
+
# FFI builder. We probably need to figure out another, *supported*, way to
|
285
|
+
# do this without meddling into back-end FFI implementations.
|
280
286
|
def find_type(*args)
|
281
|
-
@pbind.find_type(*args)
|
287
|
+
@pbind.instance_eval { find_type(*args) }
|
282
288
|
end
|
283
289
|
|
290
|
+
# This is a support method used similarly as in the actual builder.
|
291
|
+
# XXX Note, as of 0.5.0-final, this became a protected method in the
|
292
|
+
# FFI builder. We probably need to figure out another, *supported*, way to
|
293
|
+
# do this without meddling into back-end FFI implementations.
|
284
294
|
def enclosing_module(*args)
|
285
|
-
@pbind.enclosing_module(*args)
|
295
|
+
@pbind.instance_eval { enclosing_module(*args) }
|
286
296
|
end
|
287
297
|
|
288
298
|
end
|
289
299
|
|
290
|
-
#
|
300
|
+
# ConstMap can be used to organize and lookup value to constant mappings and
|
301
|
+
# vice versa. Constants can be imported from a namespace based on a regular
|
302
|
+
# expression or other means.
|
291
303
|
module ConstMap
|
292
304
|
|
293
305
|
def self.included(klass)
|
294
306
|
klass.extend(ConstMap)
|
295
307
|
end
|
296
308
|
|
297
|
-
# A flexible
|
298
|
-
#
|
309
|
+
# A flexible name to value lookup.
|
310
|
+
#
|
311
|
+
# @param [String, Symbol, Integer] arg
|
312
|
+
# Use a Symbol or String as a name to lookup its value. Use an
|
313
|
+
# Integer to lookup the corresponding name.
|
314
|
+
#
|
299
315
|
def [](arg)
|
300
316
|
if arg.is_a? Integer
|
301
317
|
list.invert[arg]
|
@@ -305,9 +321,10 @@ module FFI::DRY
|
|
305
321
|
end
|
306
322
|
|
307
323
|
# Generates a hash of all the constant names mapped to value. Usually,
|
308
|
-
# it's a good idea to override this like so in
|
324
|
+
# it's a good idea to override this like so to cache results in
|
325
|
+
# derived modules:
|
309
326
|
#
|
310
|
-
# def list; @@list
|
327
|
+
# def list; @@list ||= super() ; end
|
311
328
|
#
|
312
329
|
def list
|
313
330
|
constants.inject({}){|h,c| h.merge! c => const_get(c) }
|
@@ -333,8 +350,8 @@ module FFI::DRY
|
|
333
350
|
end
|
334
351
|
end
|
335
352
|
|
336
|
-
# Behaves just like ConstFlags, except that
|
337
|
-
# of names for the flags
|
353
|
+
# Behaves just like ConstFlags, except that it returns a list
|
354
|
+
# of names for the flags. Name string lookups work same way as
|
338
355
|
# ConstFlags.
|
339
356
|
module ConstFlagsMap
|
340
357
|
include ConstMap
|
@@ -343,9 +360,11 @@ module FFI::DRY
|
|
343
360
|
klass.extend(ConstFlagsMap)
|
344
361
|
end
|
345
362
|
|
346
|
-
# A flexible lookup
|
347
|
-
#
|
348
|
-
#
|
363
|
+
# A flexible lookup method for name to bit-flag mappings.
|
364
|
+
#
|
365
|
+
# @param [String, Symbol, Integer] arg
|
366
|
+
# Symbol or String as a name to lookup a bit-flag value, or an
|
367
|
+
# Integer to lookup a corresponding names for the flags present in it.
|
349
368
|
def [](arg)
|
350
369
|
if arg.is_a? Integer
|
351
370
|
ret = []
|
@@ -361,6 +380,79 @@ module FFI::DRY
|
|
361
380
|
end
|
362
381
|
end
|
363
382
|
end
|
383
|
+
|
384
|
+
|
385
|
+
module NetEndian
|
386
|
+
extend ::FFI::Library
|
387
|
+
|
388
|
+
attach_function :htons, [:uint16], :uint16
|
389
|
+
attach_function :ntohs, [:uint16], :uint16
|
390
|
+
attach_function :htonl, [:uint32], :uint32
|
391
|
+
attach_function :ntohl, [:uint32], :uint32
|
392
|
+
|
393
|
+
I16_convert = [method(:ntohs), method(:htons)]
|
394
|
+
I32_convert = [method(:ntohl), method(:htonl)]
|
395
|
+
|
396
|
+
ENDIAN_METHS = {
|
397
|
+
::FFI.find_type(:int16) => I16_convert,
|
398
|
+
::FFI.find_type(:uint16) => I16_convert,
|
399
|
+
::FFI.find_type(:int32) => I32_convert,
|
400
|
+
::FFI.find_type(:uint32) => I32_convert,
|
401
|
+
}
|
402
|
+
end
|
403
|
+
|
404
|
+
|
405
|
+
# A special helper for network packet structures that use big-endian or
|
406
|
+
# "network" byte-order. This helper generates read/write accessors that
|
407
|
+
# automatically call the appropriate byte conversion function, ntohs/ntohl
|
408
|
+
# for 'reading' a 16/32 bit field, and htons/htonl for writing to one.
|
409
|
+
#
|
410
|
+
# NOTE this helper does not currently do anything special for 64-bit or
|
411
|
+
# higher values.
|
412
|
+
#
|
413
|
+
module NetStructHelper
|
414
|
+
def self.included(base)
|
415
|
+
base.instance_eval { include StructHelper }
|
416
|
+
base.extend(ClassMethods)
|
417
|
+
end
|
418
|
+
|
419
|
+
module ClassMethods
|
420
|
+
|
421
|
+
private
|
422
|
+
|
423
|
+
def _class_meths_from_dsl_metadata(meta)
|
424
|
+
(@dsl_metadata = meta).each do |spec|
|
425
|
+
name = spec[:name]
|
426
|
+
type = spec[:type]
|
427
|
+
|
428
|
+
# Create endian swapper accessors methods for each applicable
|
429
|
+
# field
|
430
|
+
if( type.kind_of?(Symbol) and
|
431
|
+
cnv=NetEndian::ENDIAN_METHS[ ::FFI.find_type(type) ] )
|
432
|
+
|
433
|
+
unless instance_methods.include?(:"#{name}")
|
434
|
+
define_method(:"#{name}"){ cnv[0].call(self[name]) }
|
435
|
+
end
|
436
|
+
unless instance_methods.include?(:"#{name}=")
|
437
|
+
define_method(:"#{name}="){|val| self[name] = cnv[1].call(val) }
|
438
|
+
end
|
439
|
+
|
440
|
+
else
|
441
|
+
|
442
|
+
unless instance_methods.include?(:"#{name}")
|
443
|
+
define_method(:"#{name}"){ self[name] }
|
444
|
+
end
|
445
|
+
unless instance_methods.include?(:"#{name}=")
|
446
|
+
define_method(:"#{name}="){|val| self[name]=val }
|
447
|
+
end
|
448
|
+
|
449
|
+
end
|
450
|
+
|
451
|
+
end
|
452
|
+
end
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
364
456
|
end
|
365
457
|
|
366
458
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ffi_dry
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Monti
|
@@ -9,9 +9,19 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2010-01-02 00:00:00 -06:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: ffi
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.5.0
|
24
|
+
version:
|
15
25
|
- !ruby/object:Gem::Dependency
|
16
26
|
name: rspec
|
17
27
|
type: :development
|
@@ -32,7 +42,7 @@ dependencies:
|
|
32
42
|
- !ruby/object:Gem::Version
|
33
43
|
version: "0"
|
34
44
|
version:
|
35
|
-
description: Provides
|
45
|
+
description: Provides some useful modules, classes, and methods for FFI bindings as well as a DSL-like syntax for FFI::Struct layouts
|
36
46
|
email: emonti@matasano.com
|
37
47
|
executables: []
|
38
48
|
|
@@ -44,6 +54,7 @@ extra_rdoc_files:
|
|
44
54
|
files:
|
45
55
|
- .document
|
46
56
|
- .gitignore
|
57
|
+
- History.txt
|
47
58
|
- LICENSE
|
48
59
|
- README.rdoc
|
49
60
|
- Rakefile
|
@@ -80,7 +91,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
80
91
|
requirements: []
|
81
92
|
|
82
93
|
rubyforge_project:
|
83
|
-
rubygems_version: 1.3.
|
94
|
+
rubygems_version: 1.3.5
|
84
95
|
signing_key:
|
85
96
|
specification_version: 3
|
86
97
|
summary: Syntactic sugar and helper utilities for FFI
|