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!

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay