summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortduehr <td@matasano.com>2014-12-04 14:29:49 -0600
committertduehr <td@matasano.com>2014-12-04 14:29:49 -0600
commit2684dd8615ab1665b2276a7a7eff4315c7677b78 (patch)
tree51ef37faee2bf8ef07993dccfabd879dba796112
parent9dbe4dbe9fbaa2da26f085deb27f2b2d8e2583a8 (diff)
parent60b8c786fddadf8a52020c712875c89a897ebd88 (diff)
downloadffi-2684dd8615ab1665b2276a7a7eff4315c7677b78.tar.gz
Merge pull request #321 from tduehr/typed_enums
Typed enums
-rw-r--r--Gemfile.lock1
-rw-r--r--Rakefile8
-rw-r--r--ext/ffi_c/Call.c109
-rw-r--r--lib/ffi/enum.rb18
-rw-r--r--lib/ffi/library.rb22
-rw-r--r--libtest/EnumTest.c17
-rw-r--r--spec/ffi/enum_spec.rb196
-rw-r--r--spec/ffi/fixtures/EnumTest.c17
8 files changed, 355 insertions, 33 deletions
diff --git a/Gemfile.lock b/Gemfile.lock
index 6d09b4a..66378c3 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -17,6 +17,7 @@ GEM
PLATFORMS
java
+ ruby
DEPENDENCIES
rake (~> 10.1)
diff --git a/Rakefile b/Rakefile
index 0945913..62b4ca2 100644
--- a/Rakefile
+++ b/Rakefile
@@ -82,8 +82,8 @@ end
TEST_DEPS = [ LIBTEST ]
if RUBY_PLATFORM == "java"
desc "Run all specs"
- task :specs => TEST_DEPS do
- sh %{#{Gem.ruby} -w -S rspec #{Dir["spec/ffi/*_spec.rb"].join(" ")} -fs --color}
+ task :specs, [:options] => TEST_DEPS do |t, args|
+ sh %{#{Gem.ruby} -w -S rspec #{args.options || Dir["spec/ffi/*_spec.rb"].join(" ")} -fs --color}
end
desc "Run rubinius specs"
task :rbxspecs => TEST_DEPS do
@@ -92,9 +92,9 @@ if RUBY_PLATFORM == "java"
else
TEST_DEPS.unshift :compile
desc "Run all specs"
- task :specs => TEST_DEPS do
+ task :specs, [:options] => TEST_DEPS do |t, args|
ENV["MRI_FFI"] = "1"
- sh %{#{Gem.ruby} -w -Ilib -I#{BUILD_EXT_DIR} -S rspec #{Dir["spec/ffi/*_spec.rb"].join(" ")} -fs --color}
+ sh %{#{Gem.ruby} -w -Ilib -I#{BUILD_EXT_DIR} -S rspec #{args.options || Dir["spec/ffi/*_spec.rb"].join(" ")} -fs --color}
end
desc "Run rubinius specs"
task :rbxspecs => TEST_DEPS do
diff --git a/ext/ffi_c/Call.c b/ext/ffi_c/Call.c
index 679bfba..08e38dd 100644
--- a/ext/ffi_c/Call.c
+++ b/ext/ffi_c/Call.c
@@ -126,19 +126,30 @@ rbffi_SetupCallParams(int argc, VALUE* argv, int paramCount, Type** paramTypes,
switch (paramType->nativeType) {
case NATIVE_INT8:
- param->s8 = NUM2INT(argv[argidx]);
+ if (unlikely(type == T_SYMBOL && enums != Qnil)) {
+ VALUE value = rb_funcall(enums, id_map_symbol, 1, argv[argidx]);
+ param->s8 = NUM2INT(value);
+ } else {
+ param->s8 = NUM2INT(argv[argidx]);
+ }
+
++argidx;
ADJ(param, INT8);
break;
-
case NATIVE_INT16:
- param->s16 = NUM2INT(argv[argidx]);
+ if (unlikely(type == T_SYMBOL && enums != Qnil)) {
+ VALUE value = rb_funcall(enums, id_map_symbol, 1, argv[argidx]);
+ param->s16 = NUM2INT(value);
+
+ } else {
+ param->s16 = NUM2INT(argv[argidx]);
+ }
+
++argidx;
ADJ(param, INT16);
break;
-
case NATIVE_INT32:
if (unlikely(type == T_SYMBOL && enums != Qnil)) {
VALUE value = rb_funcall(enums, id_map_symbol, 1, argv[argidx]);
@@ -152,7 +163,6 @@ rbffi_SetupCallParams(int argc, VALUE* argv, int paramCount, Type** paramTypes,
ADJ(param, INT32);
break;
-
case NATIVE_BOOL:
if (type != T_TRUE && type != T_FALSE) {
rb_raise(rb_eTypeError, "wrong argument type (expected a boolean parameter)");
@@ -161,67 +171,122 @@ rbffi_SetupCallParams(int argc, VALUE* argv, int paramCount, Type** paramTypes,
ADJ(param, INT8);
break;
-
case NATIVE_UINT8:
- param->u8 = NUM2UINT(argv[argidx]);
+ if (unlikely(type == T_SYMBOL && enums != Qnil)) {
+ VALUE value = rb_funcall(enums, id_map_symbol, 1, argv[argidx]);
+ param->u8 = NUM2UINT(value);
+ } else {
+ param->u8 = NUM2UINT(argv[argidx]);
+ }
+
ADJ(param, INT8);
++argidx;
break;
-
case NATIVE_UINT16:
- param->u16 = NUM2UINT(argv[argidx]);
+ if (unlikely(type == T_SYMBOL && enums != Qnil)) {
+ VALUE value = rb_funcall(enums, id_map_symbol, 1, argv[argidx]);
+ param->u16 = NUM2UINT(value);
+ } else {
+ param->u16 = NUM2UINT(argv[argidx]);
+ }
+
ADJ(param, INT16);
++argidx;
break;
-
case NATIVE_UINT32:
- param->u32 = NUM2UINT(argv[argidx]);
- ADJ(param, INT32);
+ if (unlikely(type == T_SYMBOL && enums != Qnil)) {
+ VALUE value = rb_funcall(enums, id_map_symbol, 1, argv[argidx]);
+ param->u32 = NUM2UINT(value);
+ } else {
+ param->u32 = NUM2UINT(argv[argidx]);
+ }
+
+ ADJ(param, UINT32);
++argidx;
break;
-
case NATIVE_INT64:
- param->i64 = NUM2LL(argv[argidx]);
+ if (unlikely(type == T_SYMBOL && enums != Qnil)) {
+ VALUE value = rb_funcall(enums, id_map_symbol, 1, argv[argidx]);
+ param->i64 = NUM2LL(value);
+ } else {
+ param->i64 = NUM2LL(argv[argidx]);
+ }
+
ADJ(param, INT64);
++argidx;
break;
-
case NATIVE_UINT64:
- param->u64 = NUM2ULL(argv[argidx]);
- ADJ(param, INT64);
+ if (unlikely(type == T_SYMBOL && enums != Qnil)) {
+ VALUE value = rb_funcall(enums, id_map_symbol, 1, argv[argidx]);
+ param->u64 = NUM2ULL(value);
+ } else {
+ param->u64 = NUM2ULL(argv[argidx]);
+ }
+
+ ADJ(param, UINT64);
++argidx;
break;
case NATIVE_LONG:
- *(ffi_sarg *) param = NUM2LONG(argv[argidx]);
+ if (unlikely(type == T_SYMBOL && enums != Qnil)) {
+ VALUE value = rb_funcall(enums, id_map_symbol, 1, argv[argidx]);
+ *(ffi_sarg *) param = NUM2LONG(value);
+ } else {
+ *(ffi_sarg *) param = NUM2LONG(argv[argidx]);
+ }
+
ADJ(param, LONG);
++argidx;
break;
case NATIVE_ULONG:
- *(ffi_arg *) param = NUM2ULONG(argv[argidx]);
+ if (unlikely(type == T_SYMBOL && enums != Qnil)) {
+ VALUE value = rb_funcall(enums, id_map_symbol, 1, argv[argidx]);
+ *(ffi_arg *) param = NUM2ULONG(value);
+ } else {
+ *(ffi_arg *) param = NUM2ULONG(argv[argidx]);
+ }
+
ADJ(param, LONG);
++argidx;
break;
case NATIVE_FLOAT32:
- param->f32 = (float) NUM2DBL(argv[argidx]);
+ if (unlikely(type == T_SYMBOL && enums != Qnil)) {
+ VALUE value = rb_funcall(enums, id_map_symbol, 1, argv[argidx]);
+ param->f32 = (float) NUM2DBL(value);
+ } else {
+ param->f32 = (float) NUM2DBL(argv[argidx]);
+ }
+
ADJ(param, FLOAT32);
++argidx;
break;
case NATIVE_FLOAT64:
- param->f64 = NUM2DBL(argv[argidx]);
+ if (unlikely(type == T_SYMBOL && enums != Qnil)) {
+ VALUE value = rb_funcall(enums, id_map_symbol, 1, argv[argidx]);
+ param->f64 = NUM2DBL(value);
+ } else {
+ param->f64 = NUM2DBL(argv[argidx]);
+ }
+
ADJ(param, FLOAT64);
++argidx;
break;
case NATIVE_LONGDOUBLE:
- param->ld = rbffi_num2longdouble(argv[argidx]);
+ if (unlikely(type == T_SYMBOL && enums != Qnil)) {
+ VALUE value = rb_funcall(enums, id_map_symbol, 1, argv[argidx]);
+ param->ld = rbffi_num2longdouble(value);
+ } else {
+ param->ld = rbffi_num2longdouble(argv[argidx]);
+ }
+
ADJ(param, LONGDOUBLE);
++argidx;
break;
diff --git a/lib/ffi/enum.rb b/lib/ffi/enum.rb
index 9dcf4fa..1b0b898 100644
--- a/lib/ffi/enum.rb
+++ b/lib/ffi/enum.rb
@@ -86,10 +86,16 @@ module FFI
attr_reader :tag
- # @param [nil, Enumerable] info
- # @param tag enum tag
- def initialize(info, tag=nil)
- @tag = tag
+ # @overload initialize(info, tag=nil)
+ # @param [nil, Enumerable] info
+ # @param [nil, Symbol] tag enum tag
+ # @overload initialize(native_type, info, tag=nil)
+ # @param [FFI::Type] native_type Native type for new Enum
+ # @param [nil, Enumerable] info symbols and values for new Enum
+ # @param [nil, Symbol] tag name of new Enum
+ def initialize(*args)
+ @native_type = args.shift if args.first.kind_of?(FFI::Type)
+ info, @tag = *args
@kv_map = Hash.new
unless info.nil?
last_cst = nil
@@ -144,9 +150,9 @@ module FFI
alias to_hash symbol_map
# Get native type of Enum
- # @return [Type::INT]
+ # @return [Type]
def native_type
- Type::INT
+ @native_type || Type::INT
end
# @param [Symbol, Integer, #to_int] val
diff --git a/lib/ffi/library.rb b/lib/ffi/library.rb
index 47a0fa8..53eb87d 100644
--- a/lib/ffi/library.rb
+++ b/lib/ffi/library.rb
@@ -444,9 +444,29 @@ module FFI
# @example
# enum [:zero, :one, :two] # unnamed enum, equivalent to above example
# @param [Array] values values for enum
+ # @overload enum(native_type, name, values)
+ # Create a named enum and specify the native type.
+ # @example
+ # enum FFI::Type::UINT64, :foo, [:zero, :one, :two] # named enum
+ # @param [FFI::Type] native_type native type for new enum
+ # @param [Symbol] name name for new enum
+ # @param [Array] values values for enum
+ # @overload enum(native_type, *args)
+ # Create an unnamed enum and specify the native type.
+ # @example
+ # enum FFI::Type::UINT64, :zero, :one, :two # unnamed enum
+ # @param [FFI::Type] native_type native type for new enum
+ # @param args values for enum
+ # @overload enum(native_type, values)
+ # Create an unnamed enum and specify the native type.
+ # @example
+ # enum Type::UINT64, [:zero, :one, :two] # unnamed enum, equivalent to above example
+ # @param [FFI::Type] native_type native type for new enum
+ # @param [Array] values values for enum
# @return [FFI::Enum]
# Create a new {FFI::Enum}.
def enum(*args)
+ native_type = args.first.kind_of?(FFI::Type) ? args.shift : nil
name, values = if args[0].kind_of?(Symbol) && args[1].kind_of?(Array)
[ args[0], args[1] ]
elsif args[0].kind_of?(Array)
@@ -455,7 +475,7 @@ module FFI
[ nil, args ]
end
@ffi_enums = FFI::Enums.new unless defined?(@ffi_enums)
- @ffi_enums << (e = FFI::Enum.new(values, name))
+ @ffi_enums << (e = native_type ? FFI::Enum.new(native_type, values, name) : FFI::Enum.new(values, name))
# If called as enum :foo, [ :zero, :one, :two ], add a typedef alias
typedef(e, name) if name
diff --git a/libtest/EnumTest.c b/libtest/EnumTest.c
index 4c9dda9..4bf8d23 100644
--- a/libtest/EnumTest.c
+++ b/libtest/EnumTest.c
@@ -3,6 +3,7 @@
*
* For licensing, see LICENSE.SPECS
*/
+#include <stdint.h>
int test_untagged_enum(int val) {
return val;
@@ -12,6 +13,22 @@ int test_untagged_typedef_enum(int val) {
return val;
}
+uint8_t test_untagged_nonint_enum(uint8_t val) {
+ return val;
+}
+
+uint16_t test_tagged_nonint_enum1(uint16_t val) {
+ return val;
+}
+
+uint32_t test_tagged_nonint_enum2(uint32_t val) {
+ return val;
+}
+
+uint64_t test_tagged_nonint_enum3(uint64_t val) {
+ return val;
+}
+
typedef enum {c1, c2, c3, c4} enum_type1;
enum_type1 test_tagged_typedef_enum1(enum_type1 val) {
return val;
diff --git a/spec/ffi/enum_spec.rb b/spec/ffi/enum_spec.rb
index b65b1fb..55ff13a 100644
--- a/spec/ffi/enum_spec.rb
+++ b/spec/ffi/enum_spec.rb
@@ -36,6 +36,28 @@ module TestEnum3
attach_function :test_tagged_typedef_enum4, [:enum_type4], :enum_type4
end
+module TestEnum4
+ extend FFI::Library
+ ffi_lib TestLibrary::PATH
+
+ enum [:c1, :c2, :c3, :c4]
+ enum :enum_type1, [:c5, 0x42, :c6, :c7, :c8]
+ enum :enum_type2, [:c9, 0x42, :c10, :c11, 0x4242, :c12]
+ enum :enum_type3, [:c13, 0x42, :c14, 0x4242, :c15, 0x42424242, :c16, 0x4242424242424242]
+ enum FFI::Type::UINT16, :enum_type4, [:c17, 0x42, :c18, :c19, :c20]
+ enum FFI::Type::UINT32, :enum_type5, [:c21, 0x42, :c22, :c23, 0x4242, :c24]
+ enum FFI::Type::UINT64, :enum_type6, [:c25, 0x42, :c26, 0x4242, :c27, 0x42424242, :c28, 0x4242424242424242]
+ enum FFI::Type::UINT64, [:c29, 0x4242424242424242, :c30, :c31, :c32]
+
+ attach_function :test_untagged_nonint_enum, [:uint8], :uint8
+ attach_function :test_tagged_nonint_enum1, [:uint16], :uint16
+ attach_function :test_tagged_nonint_enum2, [:uint32], :uint32
+ attach_function :test_tagged_nonint_enum3, [:uint64], :uint64
+ attach_function :test_tagged_nonint_enum4, :test_tagged_nonint_enum1, [:enum_type4], :enum_type4
+ attach_function :test_tagged_nonint_enum5, :test_tagged_nonint_enum2, [:enum_type5], :enum_type5
+ attach_function :test_tagged_nonint_enum6, :test_tagged_nonint_enum3, [:enum_type6], :enum_type6
+end
+
describe "A library with no enum defined" do
it "returns nil when asked for an enum" do
expect(TestEnum0.enum_type(:foo)).to be_nil
@@ -60,6 +82,14 @@ describe "An untagged enum" do
expect(TestEnum1.test_untagged_enum(:c14)).to eq(4242)
expect(TestEnum1.test_untagged_enum(:c15)).to eq(424242)
expect(TestEnum1.test_untagged_enum(:c16)).to eq(42424242)
+ expect(TestEnum4.test_untagged_nonint_enum(:c1)).to eq(0)
+ expect(TestEnum4.test_untagged_nonint_enum(:c2)).to eq(1)
+ expect(TestEnum4.test_untagged_nonint_enum(:c3)).to eq(2)
+ expect(TestEnum4.test_untagged_nonint_enum(:c4)).to eq(3)
+ expect(TestEnum4.test_tagged_nonint_enum3(:c29)).to eq(0x4242424242424242)
+ expect(TestEnum4.test_tagged_nonint_enum3(:c30)).to eq(0x4242424242424243)
+ expect(TestEnum4.test_tagged_nonint_enum3(:c31)).to eq(0x4242424242424244)
+ expect(TestEnum4.test_tagged_nonint_enum3(:c32)).to eq(0x4242424242424245)
end
end
@@ -69,6 +99,12 @@ describe "A tagged typedef enum" do
expect(TestEnum3.enum_type(:enum_type2)).not_to be_nil
expect(TestEnum3.enum_type(:enum_type3)).not_to be_nil
expect(TestEnum3.enum_type(:enum_type4)).not_to be_nil
+ expect(TestEnum4.enum_type(:enum_type1)).not_to be_nil
+ expect(TestEnum4.enum_type(:enum_type2)).not_to be_nil
+ expect(TestEnum4.enum_type(:enum_type3)).not_to be_nil
+ expect(TestEnum4.enum_type(:enum_type4)).not_to be_nil
+ expect(TestEnum4.enum_type(:enum_type5)).not_to be_nil
+ expect(TestEnum4.enum_type(:enum_type6)).not_to be_nil
end
it "contains enum constants" do
@@ -76,6 +112,12 @@ describe "A tagged typedef enum" do
expect(TestEnum3.enum_type(:enum_type2).symbols.length).to eq(4)
expect(TestEnum3.enum_type(:enum_type3).symbols.length).to eq(4)
expect(TestEnum3.enum_type(:enum_type4).symbols.length).to eq(4)
+ expect(TestEnum4.enum_type(:enum_type1).symbols.length).to eq(4)
+ expect(TestEnum4.enum_type(:enum_type2).symbols.length).to eq(4)
+ expect(TestEnum4.enum_type(:enum_type3).symbols.length).to eq(4)
+ expect(TestEnum4.enum_type(:enum_type4).symbols.length).to eq(4)
+ expect(TestEnum4.enum_type(:enum_type5).symbols.length).to eq(4)
+ expect(TestEnum4.enum_type(:enum_type6).symbols.length).to eq(4)
end
it "constants can be used as function parameters and return value" do
@@ -95,6 +137,30 @@ describe "A tagged typedef enum" do
expect(TestEnum3.test_tagged_typedef_enum4(:c14)).to be :c14
expect(TestEnum3.test_tagged_typedef_enum4(:c15)).to be :c15
expect(TestEnum3.test_tagged_typedef_enum4(:c16)).to be :c16
+ expect(TestEnum4.test_tagged_nonint_enum1(:c5)).to eq(0x42)
+ expect(TestEnum4.test_tagged_nonint_enum1(:c6)).to eq(0x43)
+ expect(TestEnum4.test_tagged_nonint_enum1(:c7)).to eq(0x44)
+ expect(TestEnum4.test_tagged_nonint_enum1(:c8)).to eq(0x45)
+ expect(TestEnum4.test_tagged_nonint_enum2(:c9)).to eq(0x42)
+ expect(TestEnum4.test_tagged_nonint_enum2(:c10)).to eq(0x43)
+ expect(TestEnum4.test_tagged_nonint_enum2(:c11)).to eq(0x4242)
+ expect(TestEnum4.test_tagged_nonint_enum2(:c12)).to eq(0x4243)
+ expect(TestEnum4.test_tagged_nonint_enum3(:c13)).to eq(0x42)
+ expect(TestEnum4.test_tagged_nonint_enum3(:c14)).to eq(0x4242)
+ expect(TestEnum4.test_tagged_nonint_enum3(:c15)).to eq(0x42424242)
+ expect(TestEnum4.test_tagged_nonint_enum3(:c16)).to eq(0x4242424242424242)
+ expect(TestEnum4.test_tagged_nonint_enum4(:c17)).to eq(:c17)
+ expect(TestEnum4.test_tagged_nonint_enum4(:c18)).to eq(:c18)
+ expect(TestEnum4.test_tagged_nonint_enum4(:c19)).to eq(:c19)
+ expect(TestEnum4.test_tagged_nonint_enum4(:c20)).to eq(:c20)
+ expect(TestEnum4.test_tagged_nonint_enum5(:c21)).to eq(:c21)
+ expect(TestEnum4.test_tagged_nonint_enum5(:c22)).to eq(:c22)
+ expect(TestEnum4.test_tagged_nonint_enum5(:c23)).to eq(:c23)
+ expect(TestEnum4.test_tagged_nonint_enum5(:c24)).to eq(:c24)
+ expect(TestEnum4.test_tagged_nonint_enum6(:c25)).to eq(:c25)
+ expect(TestEnum4.test_tagged_nonint_enum6(:c26)).to eq(:c26)
+ expect(TestEnum4.test_tagged_nonint_enum6(:c27)).to eq(:c27)
+ expect(TestEnum4.test_tagged_nonint_enum6(:c28)).to eq(:c28)
end
it "integers can be used instead of constants" do
@@ -114,6 +180,18 @@ describe "A tagged typedef enum" do
expect(TestEnum3.test_tagged_typedef_enum4(4242)).to be :c14
expect(TestEnum3.test_tagged_typedef_enum4(424242)).to be :c15
expect(TestEnum3.test_tagged_typedef_enum4(42424242)).to be :c16
+ expect(TestEnum4.test_tagged_nonint_enum4(0x42)).to eq(:c17)
+ expect(TestEnum4.test_tagged_nonint_enum4(0x43)).to eq(:c18)
+ expect(TestEnum4.test_tagged_nonint_enum4(0x44)).to eq(:c19)
+ expect(TestEnum4.test_tagged_nonint_enum4(0x45)).to eq(:c20)
+ expect(TestEnum4.test_tagged_nonint_enum5(0x42)).to eq(:c21)
+ expect(TestEnum4.test_tagged_nonint_enum5(0x43)).to eq(:c22)
+ expect(TestEnum4.test_tagged_nonint_enum5(0x4242)).to eq(:c23)
+ expect(TestEnum4.test_tagged_nonint_enum5(0x4243)).to eq(:c24)
+ expect(TestEnum4.test_tagged_nonint_enum6(0x42)).to eq(:c25)
+ expect(TestEnum4.test_tagged_nonint_enum6(0x4242)).to eq(:c26)
+ expect(TestEnum4.test_tagged_nonint_enum6(0x42424242)).to eq(:c27)
+ expect(TestEnum4.test_tagged_nonint_enum6(0x4242424242424242)).to eq(:c28)
end
end
@@ -128,6 +206,11 @@ describe "All enums" do
expect(TestEnum3.enum_value(:c2)).to eq(1)
expect(TestEnum3.enum_value(:c3)).to eq(2)
expect(TestEnum3.enum_value(:c4)).to eq(3)
+
+ expect(TestEnum4.enum_value(:c1)).to eq(0)
+ expect(TestEnum4.enum_value(:c2)).to eq(1)
+ expect(TestEnum4.enum_value(:c3)).to eq(2)
+ expect(TestEnum4.enum_value(:c4)).to eq(3)
end
it "can have an explicit first constant and autonumbered subsequent constants" do
@@ -140,6 +223,16 @@ describe "All enums" do
expect(TestEnum3.enum_value(:c6)).to eq(43)
expect(TestEnum3.enum_value(:c7)).to eq(44)
expect(TestEnum3.enum_value(:c8)).to eq(45)
+
+ expect(TestEnum4.enum_value(:c5)).to eq(0x42)
+ expect(TestEnum4.enum_value(:c6)).to eq(0x43)
+ expect(TestEnum4.enum_value(:c7)).to eq(0x44)
+ expect(TestEnum4.enum_value(:c8)).to eq(0x45)
+
+ expect(TestEnum4.enum_value(:c29)).to eq(0x4242424242424242)
+ expect(TestEnum4.enum_value(:c30)).to eq(0x4242424242424243)
+ expect(TestEnum4.enum_value(:c31)).to eq(0x4242424242424244)
+ expect(TestEnum4.enum_value(:c32)).to eq(0x4242424242424245)
end
it "can have a mix of explicit and autonumbered constants" do
@@ -152,6 +245,16 @@ describe "All enums" do
expect(TestEnum3.enum_value(:c10)).to eq(43)
expect(TestEnum3.enum_value(:c11)).to eq(4242)
expect(TestEnum3.enum_value(:c12)).to eq(4243)
+
+ expect(TestEnum4.enum_value(:c9)).to eq(0x42)
+ expect(TestEnum4.enum_value(:c10)).to eq(0x43)
+ expect(TestEnum4.enum_value(:c11)).to eq(0x4242)
+ expect(TestEnum4.enum_value(:c12)).to eq(0x4243)
+
+ expect(TestEnum4.enum_value(:c21)).to eq(0x42)
+ expect(TestEnum4.enum_value(:c22)).to eq(0x43)
+ expect(TestEnum4.enum_value(:c23)).to eq(0x4242)
+ expect(TestEnum4.enum_value(:c24)).to eq(0x4243)
end
it "can have all its constants explicitely valued" do
@@ -164,6 +267,16 @@ describe "All enums" do
expect(TestEnum3.enum_value(:c14)).to eq(4242)
expect(TestEnum3.enum_value(:c15)).to eq(424242)
expect(TestEnum3.enum_value(:c16)).to eq(42424242)
+
+ expect(TestEnum4.enum_value(:c13)).to eq(0x42)
+ expect(TestEnum4.enum_value(:c14)).to eq(0x4242)
+ expect(TestEnum4.enum_value(:c15)).to eq(0x42424242)
+ expect(TestEnum4.enum_value(:c16)).to eq(0x4242424242424242)
+
+ expect(TestEnum4.enum_value(:c25)).to eq(0x42)
+ expect(TestEnum4.enum_value(:c26)).to eq(0x4242)
+ expect(TestEnum4.enum_value(:c27)).to eq(0x42424242)
+ expect(TestEnum4.enum_value(:c28)).to eq(0x4242424242424242)
end
it "return the constant corresponding to a specific value" do
@@ -190,6 +303,42 @@ describe "All enums" do
expect(enum[4242]).to be :c14
expect(enum[424242]).to be :c15
expect(enum[42424242]).to be :c16
+
+ enum = TestEnum4.enum_type(:enum_type1)
+ expect(enum[0x42]).to eq(:c5)
+ expect(enum[0x43]).to eq(:c6)
+ expect(enum[0x44]).to eq(:c7)
+ expect(enum[0x45]).to eq(:c8)
+
+ enum = TestEnum4.enum_type(:enum_type2)
+ expect(enum[0x42]).to eq(:c9)
+ expect(enum[0x43]).to eq(:c10)
+ expect(enum[0x4242]).to eq(:c11)
+ expect(enum[0x4243]).to eq(:c12)
+
+ enum = TestEnum4.enum_type(:enum_type3)
+ expect(enum[0x42]).to eq(:c13)
+ expect(enum[0x4242]).to eq(:c14)
+ expect(enum[0x42424242]).to eq(:c15)
+ expect(enum[0x4242424242424242]).to eq(:c16)
+
+ enum = TestEnum4.enum_type(:enum_type4)
+ expect(enum[0x42]).to eq(:c17)
+ expect(enum[0x43]).to eq(:c18)
+ expect(enum[0x44]).to eq(:c19)
+ expect(enum[0x45]).to eq(:c20)
+
+ enum = TestEnum4.enum_type(:enum_type5)
+ expect(enum[0x42]).to eq(:c21)
+ expect(enum[0x43]).to eq(:c22)
+ expect(enum[0x4242]).to eq(:c23)
+ expect(enum[0x4243]).to eq(:c24)
+
+ enum = TestEnum4.enum_type(:enum_type6)
+ expect(enum[0x42]).to eq(:c25)
+ expect(enum[0x4242]).to eq(:c26)
+ expect(enum[0x42424242]).to eq(:c27)
+ expect(enum[0x4242424242424242]).to eq(:c28)
end
it "return nil for values that don't have a symbol" do
@@ -219,9 +368,56 @@ describe "All enums" do
expect(enum[424243]).to be_nil
expect(enum[42424241]).to be_nil
expect(enum[42424243]).to be_nil
+
+ enum = TestEnum4.enum_type(:enum_type1)
+ expect(enum[0x0]).to be_nil
+ expect(enum[0x41]).to be_nil
+ expect(enum[0x46]).to be_nil
+
+ enum = TestEnum4.enum_type(:enum_type2)
+ expect(enum[0x0]).to be_nil
+ expect(enum[0x41]).to be_nil
+ expect(enum[0x44]).to be_nil
+ expect(enum[0x4241]).to be_nil
+ expect(enum[0x4244]).to be_nil
+
+ enum = TestEnum4.enum_type(:enum_type3)
+ expect(enum[0x0]).to be_nil
+ expect(enum[0x41]).to be_nil
+ expect(enum[0x43]).to be_nil
+ expect(enum[0x4241]).to be_nil
+ expect(enum[0x4243]).to be_nil
+ expect(enum[0x42424241]).to be_nil
+ expect(enum[0x42424243]).to be_nil
+ expect(enum[0x4242424242424241]).to be_nil
+ expect(enum[0x4242424242424243]).to be_nil
+
+ enum = TestEnum4.enum_type(:enum_type4)
+ expect(enum[0x0]).to be_nil
+ expect(enum[0x41]).to be_nil
+ expect(enum[0x46]).to be_nil
+
+ enum = TestEnum4.enum_type(:enum_type5)
+ expect(enum[0x0]).to be_nil
+ expect(enum[0x41]).to be_nil
+ expect(enum[0x44]).to be_nil
+ expect(enum[0x4241]).to be_nil
+ expect(enum[0x4244]).to be_nil
+
+ enum = TestEnum4.enum_type(:enum_type6)
+ expect(enum[0x0]).to be_nil
+ expect(enum[0x41]).to be_nil
+ expect(enum[0x43]).to be_nil
+ expect(enum[0x4241]).to be_nil
+ expect(enum[0x4243]).to be_nil
+ expect(enum[0x42424241]).to be_nil
+ expect(enum[0x42424243]).to be_nil
+ expect(enum[0x4242424242424241]).to be_nil
+ expect(enum[0x4242424242424243]).to be_nil
end
it "duplicate enum keys rejected" do
expect { enum [ :a, 0xfee1dead, :b, 0xdeadbeef, :a, 0 ] }.to raise_error
+ expect { enum FFI::Type::UINT64, [ :a, 0xfee1dead, :b, 0xdeadbeef, :a, 0 ] }.to raise_error
end
end
diff --git a/spec/ffi/fixtures/EnumTest.c b/spec/ffi/fixtures/EnumTest.c
index 4c9dda9..4bf8d23 100644
--- a/spec/ffi/fixtures/EnumTest.c
+++ b/spec/ffi/fixtures/EnumTest.c
@@ -3,6 +3,7 @@
*
* For licensing, see LICENSE.SPECS
*/
+#include <stdint.h>
int test_untagged_enum(int val) {
return val;
@@ -12,6 +13,22 @@ int test_untagged_typedef_enum(int val) {
return val;
}
+uint8_t test_untagged_nonint_enum(uint8_t val) {
+ return val;
+}
+
+uint16_t test_tagged_nonint_enum1(uint16_t val) {
+ return val;
+}
+
+uint32_t test_tagged_nonint_enum2(uint32_t val) {
+ return val;
+}
+
+uint64_t test_tagged_nonint_enum3(uint64_t val) {
+ return val;
+}
+
typedef enum {c1, c2, c3, c4} enum_type1;
enum_type1 test_tagged_typedef_enum1(enum_type1 val) {
return val;