ffi 1.12.2-java → 1.13.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +3 -3
  4. data/.appveyor.yml +30 -0
  5. data/.github/workflows/ci.yml +64 -0
  6. data/.gitignore +25 -0
  7. data/.gitmodules +4 -0
  8. data/.travis.yml +58 -0
  9. data/.yardopts +5 -0
  10. data/CHANGELOG.md +30 -0
  11. data/Gemfile +17 -0
  12. data/LICENSE.SPECS +22 -0
  13. data/Rakefile +24 -43
  14. data/ffi.gemspec +43 -0
  15. data/lib/ffi.rb +28 -0
  16. data/lib/ffi/autopointer.rb +203 -0
  17. data/lib/ffi/buffer.rb +4 -0
  18. data/lib/ffi/callback.rb +4 -0
  19. data/lib/ffi/data_converter.rb +67 -0
  20. data/lib/ffi/enum.rb +296 -0
  21. data/lib/ffi/errno.rb +43 -0
  22. data/lib/ffi/ffi.rb +46 -0
  23. data/lib/ffi/io.rb +62 -0
  24. data/lib/ffi/library.rb +592 -0
  25. data/lib/ffi/managedstruct.rb +84 -0
  26. data/lib/ffi/memorypointer.rb +1 -0
  27. data/lib/ffi/platform.rb +175 -0
  28. data/lib/ffi/platform/aarch64-freebsd/types.conf +128 -0
  29. data/lib/ffi/platform/aarch64-freebsd12/types.conf +128 -0
  30. data/lib/ffi/platform/aarch64-linux/types.conf +104 -0
  31. data/lib/ffi/platform/arm-freebsd/types.conf +152 -0
  32. data/lib/ffi/platform/arm-freebsd12/types.conf +152 -0
  33. data/lib/ffi/platform/arm-linux/types.conf +132 -0
  34. data/lib/ffi/platform/i386-cygwin/types.conf +3 -0
  35. data/lib/ffi/platform/i386-darwin/types.conf +100 -0
  36. data/lib/ffi/platform/i386-freebsd/types.conf +152 -0
  37. data/lib/ffi/platform/i386-freebsd12/types.conf +152 -0
  38. data/lib/ffi/platform/i386-gnu/types.conf +107 -0
  39. data/lib/ffi/platform/i386-linux/types.conf +103 -0
  40. data/lib/ffi/platform/i386-netbsd/types.conf +126 -0
  41. data/lib/ffi/platform/i386-openbsd/types.conf +128 -0
  42. data/lib/ffi/platform/i386-solaris/types.conf +122 -0
  43. data/lib/ffi/platform/i386-windows/types.conf +52 -0
  44. data/lib/ffi/platform/ia64-linux/types.conf +104 -0
  45. data/lib/ffi/platform/mips-linux/types.conf +102 -0
  46. data/lib/ffi/platform/mips64-linux/types.conf +104 -0
  47. data/lib/ffi/platform/mips64el-linux/types.conf +104 -0
  48. data/lib/ffi/platform/mipsel-linux/types.conf +102 -0
  49. data/lib/ffi/platform/mipsisa32r6-linux/types.conf +102 -0
  50. data/lib/ffi/platform/mipsisa32r6el-linux/types.conf +102 -0
  51. data/lib/ffi/platform/mipsisa64r6-linux/types.conf +104 -0
  52. data/lib/ffi/platform/mipsisa64r6el-linux/types.conf +104 -0
  53. data/lib/ffi/platform/powerpc-aix/types.conf +180 -0
  54. data/lib/ffi/platform/powerpc-darwin/types.conf +100 -0
  55. data/lib/ffi/platform/powerpc-linux/types.conf +130 -0
  56. data/lib/ffi/platform/powerpc-openbsd/types.conf +156 -0
  57. data/lib/ffi/platform/powerpc64-linux/types.conf +104 -0
  58. data/lib/ffi/platform/s390-linux/types.conf +102 -0
  59. data/lib/ffi/platform/s390x-linux/types.conf +102 -0
  60. data/lib/ffi/platform/sparc-linux/types.conf +102 -0
  61. data/lib/ffi/platform/sparc-solaris/types.conf +128 -0
  62. data/lib/ffi/platform/sparc64-linux/types.conf +102 -0
  63. data/lib/ffi/platform/sparcv9-openbsd/types.conf +156 -0
  64. data/lib/ffi/platform/sparcv9-solaris/types.conf +128 -0
  65. data/lib/ffi/platform/x86_64-cygwin/types.conf +3 -0
  66. data/lib/ffi/platform/x86_64-darwin/types.conf +130 -0
  67. data/lib/ffi/platform/x86_64-dragonflybsd/types.conf +148 -0
  68. data/lib/ffi/platform/x86_64-freebsd/types.conf +128 -0
  69. data/lib/ffi/platform/x86_64-freebsd12/types.conf +158 -0
  70. data/lib/ffi/platform/x86_64-linux/types.conf +132 -0
  71. data/lib/ffi/platform/x86_64-netbsd/types.conf +128 -0
  72. data/lib/ffi/platform/x86_64-openbsd/types.conf +134 -0
  73. data/lib/ffi/platform/x86_64-solaris/types.conf +122 -0
  74. data/lib/ffi/platform/x86_64-windows/types.conf +52 -0
  75. data/lib/ffi/pointer.rb +167 -0
  76. data/lib/ffi/struct.rb +316 -0
  77. data/lib/ffi/struct_by_reference.rb +72 -0
  78. data/lib/ffi/struct_layout.rb +96 -0
  79. data/lib/ffi/struct_layout_builder.rb +227 -0
  80. data/lib/ffi/tools/const_generator.rb +230 -0
  81. data/lib/ffi/tools/generator.rb +105 -0
  82. data/lib/ffi/tools/generator_task.rb +32 -0
  83. data/lib/ffi/tools/struct_generator.rb +194 -0
  84. data/lib/ffi/tools/types_generator.rb +137 -0
  85. data/lib/ffi/types.rb +194 -0
  86. data/lib/ffi/union.rb +43 -0
  87. data/lib/ffi/variadic.rb +78 -0
  88. data/lib/ffi/version.rb +3 -0
  89. data/samples/getlogin.rb +8 -0
  90. data/samples/getpid.rb +8 -0
  91. data/samples/gettimeofday.rb +18 -0
  92. data/samples/hello.rb +8 -0
  93. data/samples/inotify.rb +60 -0
  94. data/samples/pty.rb +75 -0
  95. data/samples/qsort.rb +20 -0
  96. metadata +192 -24
  97. metadata.gz.sig +0 -0
@@ -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
@@ -0,0 +1,4 @@
1
+ #
2
+ # All the code from this file is now implemented in C. This file remains
3
+ # to satisfy any leftover require 'ffi/buffer' in user code
4
+ #
@@ -0,0 +1,4 @@
1
+ #
2
+ # All the code from this file is now implemented in C. This file remains
3
+ # to satisfy any leftover require 'ffi/callback' in user code
4
+ #
@@ -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
@@ -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