Skip to content

Instantly share code, notes, and snippets.

@kojix2
Last active February 15, 2021 07:26
Show Gist options
  • Save kojix2/5e7102a0818261e1f840ff04b7fb7bc5 to your computer and use it in GitHub Desktop.
Save kojix2/5e7102a0818261e1f840ff04b7fb7bc5 to your computer and use it in GitHub Desktop.
Ruby FFI bitfields
# frozen_string_literal: true
require "ffi"
module FFI
class BitStruct < Struct
class << self
# def union_layout(*args)
# Class.new(FFI::Union) { layout(*args) }
# end
# def struct_layout(*args)
# Class.new(FFI::Struct) { layout(*args) }
# end
module BitFieldsModule
def [](name)
bit_fields = self.class.bit_fields_map
parent, start, width = bit_fields[name]
if parent
(super(parent) >> start) & ((1 << width) - 1)
else
super(name)
end
end
end
private_constant :BitFieldsModule
attr_reader :bit_fields_map
def bitfields(*args)
unless instance_variable_defined?(:@bit_fields)
@bit_fields_map = {}
prepend BitFieldsModule
end
parent = args.shift
labels = []
widths = []
args.each_slice(2) do |l, w|
labels << l
widths << w
end
starts = widths.inject([0]) do |result, w|
result << (result.last + w)
end
labels.zip(starts, widths).each do |l, s, w|
@bit_fields_map[l] = [parent, s, w]
end
end
end
end
end
@kojix2
Copy link
Author

kojix2 commented Jan 28, 2021

    class Sample < ::FFI::Struct
      layout \
        :aaaaaaa,            :uint32,
        :bbbbbbb,            :int32,
        :ccccccc,            :int32,
        :ddddddd,            :int32,

      bitfields :aaaaaaa, 
        :a,       2,
        :b,       2,
        :c,       3

      bitfields :bbbbbbb, 
        :d,       2,
        :e,       2,
        :f,       3
    end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment