summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrice Videau <bvideau@anl.gov>2022-04-12 22:09:53 -0500
committerBrice Videau <bvideau@anl.gov>2022-04-12 22:20:43 -0500
commit5f71e6f9624e00bc0618005d5593a0b422df73b7 (patch)
tree01f8a0e31d110979772fc788ed61a18112f7b3c2
parentbdb4edeae927b1bf4d867175c21d110c17812fbd (diff)
downloadffi-5f71e6f9624e00bc0618005d5593a0b422df73b7.tar.gz
Simplify from_native and test corner case.
-rw-r--r--lib/ffi/enum.rb8
-rw-r--r--spec/ffi/bitmask_spec.rb17
2 files changed, 20 insertions, 5 deletions
diff --git a/lib/ffi/enum.rb b/lib/ffi/enum.rb
index 903525e..83b6d89 100644
--- a/lib/ffi/enum.rb
+++ b/lib/ffi/enum.rb
@@ -280,15 +280,13 @@ module FFI
# @param ctx unused
# @return [Array<Symbol, Integer>] list of symbol names corresponding to val, plus an optional remainder if some bits don't match any constant
def from_native(val, ctx)
- list = @kv_map.select { |_, v| v & val != 0 }.keys
+ flags = @kv_map.select { |_, v| v & val != 0 }
+ list = flags.keys
# If there are unmatch flags,
# return them in an integer,
# else information can be lost.
# Similar to Enum behavior.
- remainder = val ^ list.inject(0) do |tmp, o|
- v = @kv_map[o]
- if v then tmp |= v else tmp end
- end
+ remainder = val ^ flags.values.reduce(0, :|)
list.push remainder unless remainder == 0
return list
end
diff --git a/spec/ffi/bitmask_spec.rb b/spec/ffi/bitmask_spec.rb
index 4a404b0..0cbccfa 100644
--- a/spec/ffi/bitmask_spec.rb
+++ b/spec/ffi/bitmask_spec.rb
@@ -248,6 +248,23 @@ describe "A tagged typedef bitmask" do
expect(TestBitmask4.test_tagged_nonint_bitmask6([1<<14,1<<42,1<<43])).to eq([:c26,:c28,1<<43])
end
+ it "only remainder is given if only undefined mask are returned" do
+ expect(TestBitmask3.test_tagged_typedef_bitmask1(1<<4)).to eq([1<<4])
+ expect(TestBitmask3.test_tagged_typedef_bitmask1([1<<4])).to eq([1<<4])
+ expect(TestBitmask3.test_tagged_typedef_bitmask2(1<<6)).to eq([1<<6])
+ expect(TestBitmask3.test_tagged_typedef_bitmask2([1<<6])).to eq([1<<6])
+ expect(TestBitmask3.test_tagged_typedef_bitmask3(1<<7)).to eq([1<<7])
+ expect(TestBitmask3.test_tagged_typedef_bitmask3([1<<7])).to eq([1<<7])
+ expect(TestBitmask3.test_tagged_typedef_bitmask4(1<<9)).to eq([1<<9])
+ expect(TestBitmask3.test_tagged_typedef_bitmask4([1<<9])).to eq([1<<9])
+ expect(TestBitmask4.test_tagged_nonint_bitmask4(1<<10)).to eq([1<<10])
+ expect(TestBitmask4.test_tagged_nonint_bitmask4([1<<10])).to eq([1<<10])
+ expect(TestBitmask4.test_tagged_nonint_bitmask5(1<<16)).to eq([1<<16])
+ expect(TestBitmask4.test_tagged_nonint_bitmask5([1<<16])).to eq([1<<16])
+ expect(TestBitmask4.test_tagged_nonint_bitmask6(1<<43)).to eq([1<<43])
+ expect(TestBitmask4.test_tagged_nonint_bitmask6([1<<43])).to eq([1<<43])
+ end
+
it "wrong constants rejected" do
expect { TestBitmask3.test_tagged_typedef_bitmask1([:c2,:c4,:c5]) }.to raise_error(ArgumentError)
expect { TestBitmask3.test_tagged_typedef_bitmask2([:c6,:c8,:c9]) }.to raise_error(ArgumentError)