ffi 1.12.2-java → 1.13.0-java
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +3 -3
- data/.appveyor.yml +30 -0
- data/.github/workflows/ci.yml +64 -0
- data/.gitignore +25 -0
- data/.gitmodules +4 -0
- data/.travis.yml +58 -0
- data/.yardopts +5 -0
- data/CHANGELOG.md +30 -0
- data/Gemfile +17 -0
- data/LICENSE.SPECS +22 -0
- data/Rakefile +24 -43
- data/ffi.gemspec +43 -0
- data/lib/ffi.rb +28 -0
- data/lib/ffi/autopointer.rb +203 -0
- data/lib/ffi/buffer.rb +4 -0
- data/lib/ffi/callback.rb +4 -0
- data/lib/ffi/data_converter.rb +67 -0
- data/lib/ffi/enum.rb +296 -0
- data/lib/ffi/errno.rb +43 -0
- data/lib/ffi/ffi.rb +46 -0
- data/lib/ffi/io.rb +62 -0
- data/lib/ffi/library.rb +592 -0
- data/lib/ffi/managedstruct.rb +84 -0
- data/lib/ffi/memorypointer.rb +1 -0
- data/lib/ffi/platform.rb +175 -0
- data/lib/ffi/platform/aarch64-freebsd/types.conf +128 -0
- data/lib/ffi/platform/aarch64-freebsd12/types.conf +128 -0
- data/lib/ffi/platform/aarch64-linux/types.conf +104 -0
- data/lib/ffi/platform/arm-freebsd/types.conf +152 -0
- data/lib/ffi/platform/arm-freebsd12/types.conf +152 -0
- data/lib/ffi/platform/arm-linux/types.conf +132 -0
- data/lib/ffi/platform/i386-cygwin/types.conf +3 -0
- data/lib/ffi/platform/i386-darwin/types.conf +100 -0
- data/lib/ffi/platform/i386-freebsd/types.conf +152 -0
- data/lib/ffi/platform/i386-freebsd12/types.conf +152 -0
- data/lib/ffi/platform/i386-gnu/types.conf +107 -0
- data/lib/ffi/platform/i386-linux/types.conf +103 -0
- data/lib/ffi/platform/i386-netbsd/types.conf +126 -0
- data/lib/ffi/platform/i386-openbsd/types.conf +128 -0
- data/lib/ffi/platform/i386-solaris/types.conf +122 -0
- data/lib/ffi/platform/i386-windows/types.conf +52 -0
- data/lib/ffi/platform/ia64-linux/types.conf +104 -0
- data/lib/ffi/platform/mips-linux/types.conf +102 -0
- data/lib/ffi/platform/mips64-linux/types.conf +104 -0
- data/lib/ffi/platform/mips64el-linux/types.conf +104 -0
- data/lib/ffi/platform/mipsel-linux/types.conf +102 -0
- data/lib/ffi/platform/mipsisa32r6-linux/types.conf +102 -0
- data/lib/ffi/platform/mipsisa32r6el-linux/types.conf +102 -0
- data/lib/ffi/platform/mipsisa64r6-linux/types.conf +104 -0
- data/lib/ffi/platform/mipsisa64r6el-linux/types.conf +104 -0
- data/lib/ffi/platform/powerpc-aix/types.conf +180 -0
- data/lib/ffi/platform/powerpc-darwin/types.conf +100 -0
- data/lib/ffi/platform/powerpc-linux/types.conf +130 -0
- data/lib/ffi/platform/powerpc-openbsd/types.conf +156 -0
- data/lib/ffi/platform/powerpc64-linux/types.conf +104 -0
- data/lib/ffi/platform/s390-linux/types.conf +102 -0
- data/lib/ffi/platform/s390x-linux/types.conf +102 -0
- data/lib/ffi/platform/sparc-linux/types.conf +102 -0
- data/lib/ffi/platform/sparc-solaris/types.conf +128 -0
- data/lib/ffi/platform/sparc64-linux/types.conf +102 -0
- data/lib/ffi/platform/sparcv9-openbsd/types.conf +156 -0
- data/lib/ffi/platform/sparcv9-solaris/types.conf +128 -0
- data/lib/ffi/platform/x86_64-cygwin/types.conf +3 -0
- data/lib/ffi/platform/x86_64-darwin/types.conf +130 -0
- data/lib/ffi/platform/x86_64-dragonflybsd/types.conf +148 -0
- data/lib/ffi/platform/x86_64-freebsd/types.conf +128 -0
- data/lib/ffi/platform/x86_64-freebsd12/types.conf +158 -0
- data/lib/ffi/platform/x86_64-linux/types.conf +132 -0
- data/lib/ffi/platform/x86_64-netbsd/types.conf +128 -0
- data/lib/ffi/platform/x86_64-openbsd/types.conf +134 -0
- data/lib/ffi/platform/x86_64-solaris/types.conf +122 -0
- data/lib/ffi/platform/x86_64-windows/types.conf +52 -0
- data/lib/ffi/pointer.rb +167 -0
- data/lib/ffi/struct.rb +316 -0
- data/lib/ffi/struct_by_reference.rb +72 -0
- data/lib/ffi/struct_layout.rb +96 -0
- data/lib/ffi/struct_layout_builder.rb +227 -0
- data/lib/ffi/tools/const_generator.rb +230 -0
- data/lib/ffi/tools/generator.rb +105 -0
- data/lib/ffi/tools/generator_task.rb +32 -0
- data/lib/ffi/tools/struct_generator.rb +194 -0
- data/lib/ffi/tools/types_generator.rb +137 -0
- data/lib/ffi/types.rb +194 -0
- data/lib/ffi/union.rb +43 -0
- data/lib/ffi/variadic.rb +78 -0
- data/lib/ffi/version.rb +3 -0
- data/samples/getlogin.rb +8 -0
- data/samples/getpid.rb +8 -0
- data/samples/gettimeofday.rb +18 -0
- data/samples/hello.rb +8 -0
- data/samples/inotify.rb +60 -0
- data/samples/pty.rb +75 -0
- data/samples/qsort.rb +20 -0
- metadata +192 -24
- metadata.gz.sig +0 -0
data/lib/ffi.rb
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
if RUBY_ENGINE == 'ruby' || RUBY_ENGINE == 'rbx'
|
|
2
|
+
Object.send(:remove_const, :FFI) if defined?(::FFI)
|
|
3
|
+
begin
|
|
4
|
+
require RUBY_VERSION.split('.')[0, 2].join('.') + '/ffi_c'
|
|
5
|
+
rescue Exception
|
|
6
|
+
require 'ffi_c'
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
require 'ffi/ffi'
|
|
10
|
+
|
|
11
|
+
elsif RUBY_ENGINE == 'jruby' && Gem::Version.new(RUBY_ENGINE_VERSION) >= Gem::Version.new("9.3.pre")
|
|
12
|
+
JRuby::Util.load_ext("org.jruby.ext.ffi.FFIService")
|
|
13
|
+
require 'ffi/ffi'
|
|
14
|
+
|
|
15
|
+
elsif RUBY_ENGINE == 'truffleruby' && Gem::Version.new(RUBY_ENGINE_VERSION) >= Gem::Version.new("20.1.0-dev-a")
|
|
16
|
+
require 'truffleruby/ffi_backend'
|
|
17
|
+
require 'ffi/ffi'
|
|
18
|
+
|
|
19
|
+
else
|
|
20
|
+
# Remove the ffi gem dir from the load path, then reload the internal ffi implementation
|
|
21
|
+
$LOAD_PATH.delete(File.dirname(__FILE__))
|
|
22
|
+
$LOAD_PATH.delete(File.join(File.dirname(__FILE__), 'ffi'))
|
|
23
|
+
unless $LOADED_FEATURES.nil?
|
|
24
|
+
$LOADED_FEATURES.delete(__FILE__)
|
|
25
|
+
$LOADED_FEATURES.delete('ffi.rb')
|
|
26
|
+
end
|
|
27
|
+
require 'ffi.rb'
|
|
28
|
+
end
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (C) 2008-2010 Wayne Meissner
|
|
3
|
+
# Copyright (C) 2008 Mike Dalessio
|
|
4
|
+
#
|
|
5
|
+
# This file is part of ruby-ffi.
|
|
6
|
+
#
|
|
7
|
+
# All rights reserved.
|
|
8
|
+
#
|
|
9
|
+
# Redistribution and use in source and binary forms, with or without
|
|
10
|
+
# modification, are permitted provided that the following conditions are met:
|
|
11
|
+
#
|
|
12
|
+
# * Redistributions of source code must retain the above copyright notice, this
|
|
13
|
+
# list of conditions and the following disclaimer.
|
|
14
|
+
# * Redistributions in binary form must reproduce the above copyright notice
|
|
15
|
+
# this list of conditions and the following disclaimer in the documentation
|
|
16
|
+
# and/or other materials provided with the distribution.
|
|
17
|
+
# * Neither the name of the Ruby FFI project nor the names of its contributors
|
|
18
|
+
# may be used to endorse or promote products derived from this software
|
|
19
|
+
# without specific prior written permission.
|
|
20
|
+
#
|
|
21
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
22
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
23
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
24
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
|
25
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
26
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
27
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
28
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
29
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
30
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
31
|
+
|
|
32
|
+
module FFI
|
|
33
|
+
class AutoPointer < Pointer
|
|
34
|
+
extend DataConverter
|
|
35
|
+
|
|
36
|
+
# @overload initialize(pointer, method)
|
|
37
|
+
# @param pointer [Pointer]
|
|
38
|
+
# @param method [Method]
|
|
39
|
+
# @return [self]
|
|
40
|
+
# The passed Method will be invoked at GC time.
|
|
41
|
+
# @overload initialize(pointer, proc)
|
|
42
|
+
# @param pointer [Pointer]
|
|
43
|
+
# @return [self]
|
|
44
|
+
# The passed Proc will be invoked at GC time (SEE WARNING BELOW!)
|
|
45
|
+
# @note WARNING: passing a proc _may_ cause your pointer to never be
|
|
46
|
+
# GC'd, unless you're careful to avoid trapping a reference to the
|
|
47
|
+
# pointer in the proc. See the test specs for examples.
|
|
48
|
+
# @overload initialize(pointer) { |p| ... }
|
|
49
|
+
# @param pointer [Pointer]
|
|
50
|
+
# @yieldparam [Pointer] p +pointer+ passed to the block
|
|
51
|
+
# @return [self]
|
|
52
|
+
# The passed block will be invoked at GC time.
|
|
53
|
+
# @note
|
|
54
|
+
# WARNING: passing a block will cause your pointer to never be GC'd.
|
|
55
|
+
# This is bad.
|
|
56
|
+
# @overload initialize(pointer)
|
|
57
|
+
# @param pointer [Pointer]
|
|
58
|
+
# @return [self]
|
|
59
|
+
# The pointer's release() class method will be invoked at GC time.
|
|
60
|
+
#
|
|
61
|
+
# @note The safest, and therefore preferred, calling
|
|
62
|
+
# idiom is to pass a Method as the second parameter. Example usage:
|
|
63
|
+
#
|
|
64
|
+
# class PointerHelper
|
|
65
|
+
# def self.release(pointer)
|
|
66
|
+
# ...
|
|
67
|
+
# end
|
|
68
|
+
# end
|
|
69
|
+
#
|
|
70
|
+
# p = AutoPointer.new(other_pointer, PointerHelper.method(:release))
|
|
71
|
+
#
|
|
72
|
+
# The above code will cause PointerHelper#release to be invoked at GC time.
|
|
73
|
+
#
|
|
74
|
+
# @note
|
|
75
|
+
# The last calling idiom (only one parameter) is generally only
|
|
76
|
+
# going to be useful if you subclass {AutoPointer}, and override
|
|
77
|
+
# #release, which by default does nothing.
|
|
78
|
+
def initialize(ptr, proc=nil, &block)
|
|
79
|
+
super(ptr.type_size, ptr)
|
|
80
|
+
raise TypeError, "Invalid pointer" if ptr.nil? || !ptr.kind_of?(Pointer) \
|
|
81
|
+
|| ptr.kind_of?(MemoryPointer) || ptr.kind_of?(AutoPointer)
|
|
82
|
+
|
|
83
|
+
@releaser = if proc
|
|
84
|
+
if not proc.respond_to?(:call)
|
|
85
|
+
raise RuntimeError.new("proc must be callable")
|
|
86
|
+
end
|
|
87
|
+
CallableReleaser.new(ptr, proc)
|
|
88
|
+
|
|
89
|
+
else
|
|
90
|
+
if not self.class.respond_to?(:release)
|
|
91
|
+
raise RuntimeError.new("no release method defined")
|
|
92
|
+
end
|
|
93
|
+
DefaultReleaser.new(ptr, self.class)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
ObjectSpace.define_finalizer(self, @releaser)
|
|
97
|
+
self
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# @return [nil]
|
|
101
|
+
# Free the pointer.
|
|
102
|
+
def free
|
|
103
|
+
@releaser.free
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# @param [Boolean] autorelease
|
|
107
|
+
# @return [Boolean] +autorelease+
|
|
108
|
+
# Set +autorelease+ property. See {Pointer Autorelease section at Pointer}.
|
|
109
|
+
def autorelease=(autorelease)
|
|
110
|
+
@releaser.autorelease=(autorelease)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# @return [Boolean] +autorelease+
|
|
114
|
+
# Get +autorelease+ property. See {Pointer Autorelease section at Pointer}.
|
|
115
|
+
def autorelease?
|
|
116
|
+
@releaser.autorelease
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# @abstract Base class for {AutoPointer}'s releasers.
|
|
120
|
+
#
|
|
121
|
+
# All subclasses of Releaser should define a +#release(ptr)+ method.
|
|
122
|
+
# A releaser is an object in charge of release an {AutoPointer}.
|
|
123
|
+
class Releaser
|
|
124
|
+
attr_accessor :autorelease
|
|
125
|
+
|
|
126
|
+
# @param [Pointer] ptr
|
|
127
|
+
# @param [#call] proc
|
|
128
|
+
# @return [nil]
|
|
129
|
+
# A new instance of Releaser.
|
|
130
|
+
def initialize(ptr, proc)
|
|
131
|
+
@ptr = ptr
|
|
132
|
+
@proc = proc
|
|
133
|
+
@autorelease = true
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# @return [nil]
|
|
137
|
+
# Free pointer.
|
|
138
|
+
def free
|
|
139
|
+
if @ptr
|
|
140
|
+
release(@ptr)
|
|
141
|
+
@autorelease = false
|
|
142
|
+
@ptr = nil
|
|
143
|
+
@proc = nil
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# @param args
|
|
148
|
+
# Release pointer if +autorelease+ is set.
|
|
149
|
+
def call(*args)
|
|
150
|
+
release(@ptr) if @autorelease && @ptr
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# DefaultReleaser is a {Releaser} used when an {AutoPointer} is defined
|
|
155
|
+
# without Proc or Method. In this case, the pointer to release must be of
|
|
156
|
+
# a class derived from AutoPointer with a {release} class method.
|
|
157
|
+
class DefaultReleaser < Releaser
|
|
158
|
+
# @param [Pointer] ptr
|
|
159
|
+
# @return [nil]
|
|
160
|
+
# Release +ptr+ using the {release} class method of its class.
|
|
161
|
+
def release(ptr)
|
|
162
|
+
@proc.release(ptr)
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# CallableReleaser is a {Releaser} used when an {AutoPointer} is defined with a
|
|
167
|
+
# Proc or a Method.
|
|
168
|
+
class CallableReleaser < Releaser
|
|
169
|
+
# Release +ptr+ by using Proc or Method defined at +ptr+
|
|
170
|
+
# {AutoPointer#initialize initialization}.
|
|
171
|
+
#
|
|
172
|
+
# @param [Pointer] ptr
|
|
173
|
+
# @return [nil]
|
|
174
|
+
def release(ptr)
|
|
175
|
+
@proc.call(ptr)
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Return native type of AutoPointer.
|
|
180
|
+
#
|
|
181
|
+
# Override {DataConverter#native_type}.
|
|
182
|
+
# @return [Type::POINTER]
|
|
183
|
+
# @raise {RuntimeError} if class does not implement a +#release+ method
|
|
184
|
+
def self.native_type
|
|
185
|
+
if not self.respond_to?(:release)
|
|
186
|
+
raise RuntimeError.new("no release method defined for #{self.inspect}")
|
|
187
|
+
end
|
|
188
|
+
Type::POINTER
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# Create a new AutoPointer.
|
|
192
|
+
#
|
|
193
|
+
# Override {DataConverter#from_native}.
|
|
194
|
+
# @overload self.from_native(ptr, ctx)
|
|
195
|
+
# @param [Pointer] ptr
|
|
196
|
+
# @param ctx not used. Please set +nil+.
|
|
197
|
+
# @return [AutoPointer]
|
|
198
|
+
def self.from_native(val, ctx)
|
|
199
|
+
self.new(val)
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
end
|
data/lib/ffi/buffer.rb
ADDED
data/lib/ffi/callback.rb
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (C) 2008-2010 Wayne Meissner
|
|
3
|
+
#
|
|
4
|
+
# This file is part of ruby-ffi.
|
|
5
|
+
#
|
|
6
|
+
# All rights reserved.
|
|
7
|
+
#
|
|
8
|
+
# Redistribution and use in source and binary forms, with or without
|
|
9
|
+
# modification, are permitted provided that the following conditions are met:
|
|
10
|
+
#
|
|
11
|
+
# * Redistributions of source code must retain the above copyright notice, this
|
|
12
|
+
# list of conditions and the following disclaimer.
|
|
13
|
+
# * Redistributions in binary form must reproduce the above copyright notice
|
|
14
|
+
# this list of conditions and the following disclaimer in the documentation
|
|
15
|
+
# and/or other materials provided with the distribution.
|
|
16
|
+
# * Neither the name of the Ruby FFI project nor the names of its contributors
|
|
17
|
+
# may be used to endorse or promote products derived from this software
|
|
18
|
+
# without specific prior written permission.
|
|
19
|
+
#
|
|
20
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
21
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
22
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
23
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
|
24
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
25
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
26
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
27
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
28
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
29
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.#
|
|
30
|
+
|
|
31
|
+
module FFI
|
|
32
|
+
# This module is used to extend somes classes and give then a common API.
|
|
33
|
+
#
|
|
34
|
+
# Most of methods defined here must be overriden.
|
|
35
|
+
module DataConverter
|
|
36
|
+
# Get native type.
|
|
37
|
+
#
|
|
38
|
+
# @overload native_type(type)
|
|
39
|
+
# @param [String, Symbol, Type] type
|
|
40
|
+
# @return [Type]
|
|
41
|
+
# Get native type from +type+.
|
|
42
|
+
#
|
|
43
|
+
# @overload native_type
|
|
44
|
+
# @raise {NotImplementedError} This method must be overriden.
|
|
45
|
+
def native_type(type = nil)
|
|
46
|
+
if type
|
|
47
|
+
@native_type = FFI.find_type(type)
|
|
48
|
+
else
|
|
49
|
+
native_type = @native_type
|
|
50
|
+
unless native_type
|
|
51
|
+
raise NotImplementedError, 'native_type method not overridden and no native_type set'
|
|
52
|
+
end
|
|
53
|
+
native_type
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Convert to a native type.
|
|
58
|
+
def to_native(value, ctx)
|
|
59
|
+
value
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Convert from a native type.
|
|
63
|
+
def from_native(value, ctx)
|
|
64
|
+
value
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
data/lib/ffi/enum.rb
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (C) 2009, 2010 Wayne Meissner
|
|
3
|
+
# Copyright (C) 2009 Luc Heinrich
|
|
4
|
+
#
|
|
5
|
+
# This file is part of ruby-ffi.
|
|
6
|
+
#
|
|
7
|
+
# All rights reserved.
|
|
8
|
+
#
|
|
9
|
+
# Redistribution and use in source and binary forms, with or without
|
|
10
|
+
# modification, are permitted provided that the following conditions are met:
|
|
11
|
+
#
|
|
12
|
+
# * Redistributions of source code must retain the above copyright notice, this
|
|
13
|
+
# list of conditions and the following disclaimer.
|
|
14
|
+
# * Redistributions in binary form must reproduce the above copyright notice
|
|
15
|
+
# this list of conditions and the following disclaimer in the documentation
|
|
16
|
+
# and/or other materials provided with the distribution.
|
|
17
|
+
# * Neither the name of the Ruby FFI project nor the names of its contributors
|
|
18
|
+
# may be used to endorse or promote products derived from this software
|
|
19
|
+
# without specific prior written permission.
|
|
20
|
+
#
|
|
21
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
22
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
23
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
24
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
|
25
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
26
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
27
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
28
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
29
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
30
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
31
|
+
#
|
|
32
|
+
|
|
33
|
+
module FFI
|
|
34
|
+
|
|
35
|
+
# An instance of this class permits to manage {Enum}s. In fact, Enums is a collection of {Enum}s.
|
|
36
|
+
class Enums
|
|
37
|
+
|
|
38
|
+
# @return [nil]
|
|
39
|
+
def initialize
|
|
40
|
+
@all_enums = Array.new
|
|
41
|
+
@tagged_enums = Hash.new
|
|
42
|
+
@symbol_map = Hash.new
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @param [Enum] enum
|
|
46
|
+
# Add an {Enum} to the collection.
|
|
47
|
+
def <<(enum)
|
|
48
|
+
@all_enums << enum
|
|
49
|
+
@tagged_enums[enum.tag] = enum unless enum.tag.nil?
|
|
50
|
+
@symbol_map.merge!(enum.symbol_map)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# @param query enum tag or part of an enum name
|
|
54
|
+
# @return [Enum]
|
|
55
|
+
# Find a {Enum} in collection.
|
|
56
|
+
def find(query)
|
|
57
|
+
if @tagged_enums.has_key?(query)
|
|
58
|
+
@tagged_enums[query]
|
|
59
|
+
else
|
|
60
|
+
@all_enums.detect { |enum| enum.symbols.include?(query) }
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# @param symbol a symbol to find in merge symbol maps of all enums.
|
|
65
|
+
# @return a symbol
|
|
66
|
+
def __map_symbol(symbol)
|
|
67
|
+
@symbol_map[symbol]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Represents a C enum.
|
|
73
|
+
#
|
|
74
|
+
# For a C enum:
|
|
75
|
+
# enum fruits {
|
|
76
|
+
# apple,
|
|
77
|
+
# banana,
|
|
78
|
+
# orange,
|
|
79
|
+
# pineapple
|
|
80
|
+
# };
|
|
81
|
+
# are defined this vocabulary:
|
|
82
|
+
# * a _symbol_ is a word from the enumeration (ie. _apple_, by example);
|
|
83
|
+
# * a _value_ is the value of a symbol in the enumeration (by example, apple has value _0_ and banana _1_).
|
|
84
|
+
class Enum
|
|
85
|
+
include DataConverter
|
|
86
|
+
|
|
87
|
+
attr_reader :tag
|
|
88
|
+
attr_reader :native_type
|
|
89
|
+
|
|
90
|
+
# @overload initialize(info, tag=nil)
|
|
91
|
+
# @param [nil, Enumerable] info
|
|
92
|
+
# @param [nil, Symbol] tag enum tag
|
|
93
|
+
# @overload initialize(native_type, info, tag=nil)
|
|
94
|
+
# @param [FFI::Type] native_type Native type for new Enum
|
|
95
|
+
# @param [nil, Enumerable] info symbols and values for new Enum
|
|
96
|
+
# @param [nil, Symbol] tag name of new Enum
|
|
97
|
+
def initialize(*args)
|
|
98
|
+
@native_type = args.first.kind_of?(FFI::Type) ? args.shift : Type::INT
|
|
99
|
+
info, @tag = *args
|
|
100
|
+
@kv_map = Hash.new
|
|
101
|
+
unless info.nil?
|
|
102
|
+
last_cst = nil
|
|
103
|
+
value = 0
|
|
104
|
+
info.each do |i|
|
|
105
|
+
case i
|
|
106
|
+
when Symbol
|
|
107
|
+
raise ArgumentError, "duplicate enum key" if @kv_map.has_key?(i)
|
|
108
|
+
@kv_map[i] = value
|
|
109
|
+
last_cst = i
|
|
110
|
+
value += 1
|
|
111
|
+
when Integer
|
|
112
|
+
@kv_map[last_cst] = i
|
|
113
|
+
value = i+1
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
@vk_map = @kv_map.invert
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# @return [Array] enum symbol names
|
|
121
|
+
def symbols
|
|
122
|
+
@kv_map.keys
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Get a symbol or a value from the enum.
|
|
126
|
+
# @overload [](query)
|
|
127
|
+
# Get enum value from symbol.
|
|
128
|
+
# @param [Symbol] query
|
|
129
|
+
# @return [Integer]
|
|
130
|
+
# @overload [](query)
|
|
131
|
+
# Get enum symbol from value.
|
|
132
|
+
# @param [Integer] query
|
|
133
|
+
# @return [Symbol]
|
|
134
|
+
def [](query)
|
|
135
|
+
case query
|
|
136
|
+
when Symbol
|
|
137
|
+
@kv_map[query]
|
|
138
|
+
when Integer
|
|
139
|
+
@vk_map[query]
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
alias find []
|
|
143
|
+
|
|
144
|
+
# Get the symbol map.
|
|
145
|
+
# @return [Hash]
|
|
146
|
+
def symbol_map
|
|
147
|
+
@kv_map
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
alias to_h symbol_map
|
|
151
|
+
alias to_hash symbol_map
|
|
152
|
+
|
|
153
|
+
# @param [Symbol, Integer, #to_int] val
|
|
154
|
+
# @param ctx unused
|
|
155
|
+
# @return [Integer] value of a enum symbol
|
|
156
|
+
def to_native(val, ctx)
|
|
157
|
+
@kv_map[val] || if val.is_a?(Integer)
|
|
158
|
+
val
|
|
159
|
+
elsif val.respond_to?(:to_int)
|
|
160
|
+
val.to_int
|
|
161
|
+
else
|
|
162
|
+
raise ArgumentError, "invalid enum value, #{val.inspect}"
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# @param val
|
|
167
|
+
# @return symbol name if it exists for +val+.
|
|
168
|
+
def from_native(val, ctx)
|
|
169
|
+
@vk_map[val] || val
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Represents a C enum whose values are power of 2
|
|
174
|
+
#
|
|
175
|
+
# @example
|
|
176
|
+
# enum {
|
|
177
|
+
# red = (1<<0),
|
|
178
|
+
# green = (1<<1),
|
|
179
|
+
# blue = (1<<2)
|
|
180
|
+
# }
|
|
181
|
+
#
|
|
182
|
+
# Contrary to classical enums, bitmask values are usually combined
|
|
183
|
+
# when used.
|
|
184
|
+
class Bitmask < Enum
|
|
185
|
+
|
|
186
|
+
# @overload initialize(info, tag=nil)
|
|
187
|
+
# @param [nil, Enumerable] info symbols and bit rank for new Bitmask
|
|
188
|
+
# @param [nil, Symbol] tag name of new Bitmask
|
|
189
|
+
# @overload initialize(native_type, info, tag=nil)
|
|
190
|
+
# @param [FFI::Type] native_type Native type for new Bitmask
|
|
191
|
+
# @param [nil, Enumerable] info symbols and bit rank for new Bitmask
|
|
192
|
+
# @param [nil, Symbol] tag name of new Bitmask
|
|
193
|
+
def initialize(*args)
|
|
194
|
+
@native_type = args.first.kind_of?(FFI::Type) ? args.shift : Type::INT
|
|
195
|
+
info, @tag = *args
|
|
196
|
+
@kv_map = Hash.new
|
|
197
|
+
unless info.nil?
|
|
198
|
+
last_cst = nil
|
|
199
|
+
value = 0
|
|
200
|
+
info.each do |i|
|
|
201
|
+
case i
|
|
202
|
+
when Symbol
|
|
203
|
+
raise ArgumentError, "duplicate bitmask key" if @kv_map.has_key?(i)
|
|
204
|
+
@kv_map[i] = 1 << value
|
|
205
|
+
last_cst = i
|
|
206
|
+
value += 1
|
|
207
|
+
when Integer
|
|
208
|
+
raise ArgumentError, "bitmask index should be positive" if i<0
|
|
209
|
+
@kv_map[last_cst] = 1 << i
|
|
210
|
+
value = i+1
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
@vk_map = @kv_map.invert
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# Get a symbol list or a value from the bitmask
|
|
218
|
+
# @overload [](*query)
|
|
219
|
+
# Get bitmask value from symbol list
|
|
220
|
+
# @param [Symbol] query
|
|
221
|
+
# @return [Integer]
|
|
222
|
+
# @overload [](query)
|
|
223
|
+
# Get bitmaks value from symbol array
|
|
224
|
+
# @param [Array<Symbol>] query
|
|
225
|
+
# @return [Integer]
|
|
226
|
+
# @overload [](*query)
|
|
227
|
+
# Get a list of bitmask symbols corresponding to
|
|
228
|
+
# the or reduction of a list of integer
|
|
229
|
+
# @param [Integer] query
|
|
230
|
+
# @return [Array<Symbol>]
|
|
231
|
+
# @overload [](query)
|
|
232
|
+
# Get a list of bitmask symbols corresponding to
|
|
233
|
+
# the or reduction of a list of integer
|
|
234
|
+
# @param [Array<Integer>] query
|
|
235
|
+
# @return [Array<Symbol>]
|
|
236
|
+
def [](*query)
|
|
237
|
+
flat_query = query.flatten
|
|
238
|
+
raise ArgumentError, "query should be homogeneous, #{query.inspect}" unless flat_query.all? { |o| o.is_a?(Symbol) } || flat_query.all? { |o| o.is_a?(Integer) || o.respond_to?(:to_int) }
|
|
239
|
+
case flat_query[0]
|
|
240
|
+
when Symbol
|
|
241
|
+
flat_query.inject(0) do |val, o|
|
|
242
|
+
v = @kv_map[o]
|
|
243
|
+
if v then val |= v else val end
|
|
244
|
+
end
|
|
245
|
+
when Integer, ->(o) { o.respond_to?(:to_int) }
|
|
246
|
+
val = flat_query.inject(0) { |mask, o| mask |= o.to_int }
|
|
247
|
+
@kv_map.select { |_, v| v & val != 0 }.keys
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# Get the native value of a bitmask
|
|
252
|
+
# @overload to_native(query, ctx)
|
|
253
|
+
# @param [Symbol, Integer, #to_int] query
|
|
254
|
+
# @param ctx unused
|
|
255
|
+
# @return [Integer] value of a bitmask
|
|
256
|
+
# @overload to_native(query, ctx)
|
|
257
|
+
# @param [Array<Symbol, Integer, #to_int>] query
|
|
258
|
+
# @param ctx unused
|
|
259
|
+
# @return [Integer] value of a bitmask
|
|
260
|
+
def to_native(query, ctx)
|
|
261
|
+
return 0 if query.nil?
|
|
262
|
+
flat_query = [query].flatten
|
|
263
|
+
flat_query.inject(0) do |val, o|
|
|
264
|
+
case o
|
|
265
|
+
when Symbol
|
|
266
|
+
v = @kv_map[o]
|
|
267
|
+
raise ArgumentError, "invalid bitmask value, #{o.inspect}" unless v
|
|
268
|
+
val |= v
|
|
269
|
+
when Integer
|
|
270
|
+
val |= o
|
|
271
|
+
when ->(obj) { obj.respond_to?(:to_int) }
|
|
272
|
+
val |= o.to_int
|
|
273
|
+
else
|
|
274
|
+
raise ArgumentError, "invalid bitmask value, #{o.inspect}"
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
# @param [Integer] val
|
|
280
|
+
# @param ctx unused
|
|
281
|
+
# @return [Array<Symbol, Integer>] list of symbol names corresponding to val, plus an optional remainder if some bits don't match any constant
|
|
282
|
+
def from_native(val, ctx)
|
|
283
|
+
list = @kv_map.select { |_, v| v & val != 0 }.keys
|
|
284
|
+
# If there are unmatch flags,
|
|
285
|
+
# return them in an integer,
|
|
286
|
+
# else information can be lost.
|
|
287
|
+
# Similar to Enum behavior.
|
|
288
|
+
remainder = val ^ list.inject(0) do |tmp, o|
|
|
289
|
+
v = @kv_map[o]
|
|
290
|
+
if v then tmp |= v else tmp end
|
|
291
|
+
end
|
|
292
|
+
list.push remainder unless remainder == 0
|
|
293
|
+
return list
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
end
|