github: https://github.com/kojix2/ffi-bitfield
What is Ruby-FFI?
Ruby-FFI is a powerful tool to create bindings for C language libraries in Ruby.
Ruby-FFI did not support bit fields
However, as of July 2021, Ruby-FFI does not support struct bit field. The fact that bit field is not supported is written in the Wiki. I contacted the developer, and they replied that bit fields are not yet supported, and suggested adding a custom method instead.
If the number of bitfields used in the c library for which you want to create bindings is small enough, you can add a custom method. However, if a large number of bit fields are provided, you have to write many custom methods. This requires a lot of work and increases the likelihood of errors.
Motivation
I'm working on a bioinformatics-related binding called ruby-htslib. htslib makes heavy use of bit fields throughout the library, so supporting bit fields is inevitable.
I would like to create a gem to solve this problem.
ffi-bitfield gem
So I created a gem to read or write bit fields in Ruby/FFI.
github: https://github.com/kojix2/ffi-bitfield
I didn't know anything about bitwise operations, so I managed to understand the elementary part after thinking about it for several hours.
I couldn't write efficient code by myself, so I asked other people to write better code on Ruby-JP slack and Stack Overflow. At times like this, the Internet community is really helpful.
Install
gem install ffi-bitfield
How to use
loading
require 'ffi/bit_struct'
# FFI::BitStruct
require 'ffi/managed_bit_struct'
# FFI::ManagedBitStruct
require 'ffi/bit_structs'
# Both FFI::BitStruct and FFI::ManagedBitStruct
Structures and bitfields are defined as follows.
require 'ffi/bit_struct'
class Struct1 < FFI::BitStruct
layout \
:a, :uint8,
:b, :uint8
bit_fields :a,
:a0, 1,
:a1, 1,
:a2, 1,
:a3, 1,
:a4, 1,
:a5, 1,
:a6, 1,
:a7, 1
bit_fields :b,
:b0, 1,
:b1, 1,
:b2, 2,
:b3, 4
end
bit_field
is an alias for bit_fileds
. You can use either of them.
Creating a struct
Same as Ruby-FFI.
a = Struct1.new
Reading bit filed
Same as Ruby-FFI.
p a[:a0] # 0
Writing bit field
Same as Ruby-FFI.
a[:a7] = 1
p a[:0] # 128
It ’s very easy, isn’t it?
If you find a bug, please report it
I wrote a test to check that it works. In most cases, it will work fine, I think.
However, there may be undiscovered bugs in some corner cases. If you find any strange behavior, please report it to the github issue. I would be very grateful.
Tips
Ruby allows you to call bits with Integer#[]
. Did you know that?
128[0] # 0
128[7] # 1
128[6..7] # 2
128[6, 2] # 2
To take advantage of this, ffi-bitfield only supports newer versions of Ruby(>= 2.7).
Thank you for reading. Have a nice day!
Top comments (0)