ffi-bitfield - read/write bit fields with Ruby-FFI
Tags: ruby
Published: 2021-07-27 06:14:22

---
title: ffi-bitfield - read/write bit fields with Ruby-FFI
published: true
description: Bit field for Ruby-FFI
tags: ruby
---

![neko](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/90hcdgppxjjk6sxfbnqg.png)

github: https://github.com/kojix2/ffi-bitfield

## What is Ruby-FFI?

[Ruby-FFI](https://github.com/ffi/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](https://github.com/ffi/ffi/wiki/Features-at-a-Glance#unsupported-features). I contacted the developer, and they replied that [bit fields are not yet supported](https://github.com/ffi/ffi/issues/874), 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](https://github.com/kojix2/ruby-htslib). [htslib](https://github.com/samtools/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

```ruby
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. 

```ruby
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.

```ruby
a = Struct1.new
```

### Reading bit filed

Same as Ruby-FFI.

```ruby
p a[:a0] # 0
```

### Writing bit field

Same as Ruby-FFI.

```ruby
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](https://github.com/kojix2/ffi-bitfield/issues). 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!