DEV Community

kojix2
kojix2

Posted on • Edited on

2 1

ffi-bitfield - read/write bit fields with Ruby-FFI

neko

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

bit_field is an alias for bit_fileds. You can use either of them.

Creating a struct

Same as Ruby-FFI.

a = Struct1.new
Enter fullscreen mode Exit fullscreen mode

Reading bit filed

Same as Ruby-FFI.

p a[:a0] # 0
Enter fullscreen mode Exit fullscreen mode

Writing bit field

Same as Ruby-FFI.

a[:a7] = 1
p a[:0] # 128
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

To take advantage of this, ffi-bitfield only supports newer versions of Ruby(>= 2.7).

Thank you for reading. Have a nice day!

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read more

Top comments (0)

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more