Class: BinStruct::BitAttr Abstract

Inherits:
Object
  • Object
show all
Includes:
Structable
Defined in:
lib/bin_struct/bit_attr.rb

Overview

This class is abstract.

Subclasses must de derived using BitAttr.create.

Define a bitfield attribute to embed in a Struct. Use it through Struct.define_bit_attr

Examples:

class MyStruct < BinStruct::Struct
  # Create a 32-bit bitfield attribute, with fields a (16 bits), b and c (4 bits each) and d (8 bits).
  # a is the leftmost field in bitfield, and d the rightmost one.
  define_bit_attr :int32, width: 32, a: 16, b: 4, c: 4, d:8
end

s1 = MyStruct.new(int32: 0x12345678)
s1.a #=> 0x1234
s1.b #=> 5
s1.c #=> 6
s1.d #=> 0x78

s2 = MyStruct.new(a: 0x1234, d: 0x42)
s2.to_s #=> "\x12\x34\x00\x42".b

Author:

  • LemonTree55

Since:

  • 0.3.0

Defined Under Namespace

Classes: Parameters

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Structable

#sz

Constructor Details

#initialize(opts = {}) ⇒ self

Initialize bit attribute

Parameters:

  • opts (Hash{Symbol=>Integer}) (defaults to: {})

    initialization values for fields, where keys are field names and values are initialization values

Raises:

Since:

  • 0.3.0



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/bin_struct/bit_attr.rb', line 94

def initialize(opts = {})
  parameters = self.class.parameters
  raise NotImplementedError, "#initialize may only be called on subclass of #{self.class}" if parameters.nil?

  @width = parameters.width
  @fields = parameters.fields
  @int = parameters.int.dup
  @data = {}
  @bit_methods = []

  parameters.fields.each do |name, size|
    @data[name] = opts[name] || 0
    define_methods(name, size)
  end
  @bit_methods.freeze
end

Class Attribute Details

.parametersParameters (readonly)

Returns:

Since:

  • 0.3.0



46
47
48
# File 'lib/bin_struct/bit_attr.rb', line 46

def parameters
  @parameters
end

Instance Attribute Details

#bit_methods::Array[Symbol] (readonly)

Returns:

  • (::Array[Symbol])

Since:

  • 0.3.0



36
37
38
# File 'lib/bin_struct/bit_attr.rb', line 36

def bit_methods
  @bit_methods
end

#widthInteger (readonly)

Returns width in bits of bit attribute.

Returns:

  • (Integer)

    width in bits of bit attribute

Since:

  • 0.3.0



34
35
36
# File 'lib/bin_struct/bit_attr.rb', line 34

def width
  @width
end

Class Method Details

.create(width:, endian: :big, **fields) ⇒ Class

Create a new BinStruct::BitAttr subclass with specified parameters

Parameters:

  • width (Integer)

    size of bitfields in bits. Must be a size of an Int (8, 16, 24, 32 or 64 bits).

  • endian (:big, :little, :native) (defaults to: :big)

    endianess of bit attribute as an integer

  • fields (Hash{Symbol=>Integer})

    hash associating field names with their size. Total size MUST be equal to width.

Returns:

  • (Class)

Raises:

  • (ArgumentError)

    raise if:

    • width is not a size of one of Int subclasses,

    • sum of bitfield sizes is not equal to width

Since:

  • 0.3.0



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/bin_struct/bit_attr.rb', line 57

def create(width:, endian: :big, **fields)
  raise ArgumentError, 'with must be 8, 16, 24, 32 or 64' unless [8, 16, 24, 32, 64].include?(width)

  hsh = compute_hash(width, endian, fields)
  cached = cache[hsh]
  return cached if cached

  total_size = fields.reduce(0) { |acc, ary| acc + ary.last }
  raise ArgumentError, "sum of bitfield sizes is not equal to #{width}" unless total_size == width

  cache[hsh] = Class.new(self) do
    int_klass = BinStruct.const_get("Int#{width}")
    @parameters = Parameters.new(width, fields, int_klass.new(endian: endian)).freeze
  end
end

Instance Method Details

#format_inspectObject

Since:

  • 0.3.0



161
162
163
164
# File 'lib/bin_struct/bit_attr.rb', line 161

def format_inspect
  str = @int.format_inspect << "\n"
  str << @data.map { |name, value| "#{name}:#{value}" }.join(' ')
end

#from_human(value) ⇒ self

Set fields from associated integer

Parameters:

Returns:

  • (self)

Since:

  • 0.3.0



157
158
159
# File 'lib/bin_struct/bit_attr.rb', line 157

def from_human(value)
  compute_data(value.to_i)
end

#read(str) ⇒ self

Populate bit attribute from str

Parameters:

Returns:

  • (self)

Since:

  • 0.3.0



127
128
129
130
131
132
# File 'lib/bin_struct/bit_attr.rb', line 127

def read(str)
  return self if str.nil?

  @int.read(str)
  compute_data(@int.to_i)
end

#to_iInteger Also known as: to_human

Give integer associated to this attribute

Returns:

  • (Integer)

Since:

  • 0.3.0



136
137
138
139
140
141
142
143
144
# File 'lib/bin_struct/bit_attr.rb', line 136

def to_i
  v = 0
  @fields.each do |name, size|
    v <<= size
    v |= @data[name]
  end

  v
end

#to_s::String

Return binary string

Returns:

  • (::String)

Since:

  • 0.3.0



149
150
151
152
# File 'lib/bin_struct/bit_attr.rb', line 149

def to_s
  @int.value = to_i
  @int.to_s
end

#type_name::String

Get type name

Returns:

  • (::String)

Since:

  • 0.3.0



113
114
115
116
117
118
119
120
121
122
# File 'lib/bin_struct/bit_attr.rb', line 113

def type_name
  return @type_name if defined? @type_name

  endian_suffix = case @int.endian
                  when :big then ''
                  when :little then 'le'
                  when :native then 'n'
                  end
  @type_name = "BitAttr#{@width}#{endian_suffix}"
end