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



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/bin_struct/bit_attr.rb', line 126

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_key do |name|
    @data[name] = opts[name] || 0
  end
  @bit_methods.freeze
end

Class Attribute Details

.bit_methods::Array[Symbol] (readonly)

Returns:

  • (::Array[Symbol])

Since:

  • 0.3.0



48
49
50
# File 'lib/bin_struct/bit_attr.rb', line 48

def bit_methods
  @bit_methods
end

.parametersParameters (readonly)

Returns:

Since:

  • 0.3.0



44
45
46
# File 'lib/bin_struct/bit_attr.rb', line 44

def parameters
  @parameters
end

Instance Attribute Details

#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



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

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] = create_subclass(width, endian, fields.dup.freeze)
end

Instance Method Details

#bit_methods::Array[Symbol]

Returns:

  • (::Array[Symbol])

Since:

  • 0.3.0



147
148
149
# File 'lib/bin_struct/bit_attr.rb', line 147

def bit_methods
  self.class.bit_methods
end

#format_inspectObject

Since:

  • 0.3.0



201
202
203
204
# File 'lib/bin_struct/bit_attr.rb', line 201

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



197
198
199
# File 'lib/bin_struct/bit_attr.rb', line 197

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

#initialize_copy(_other) ⇒ Object

Since:

  • 0.3.0



142
143
144
# File 'lib/bin_struct/bit_attr.rb', line 142

def initialize_copy(_other)
  @data = @data.dup
end

#read(str) ⇒ self

Populate bit attribute from str

Parameters:

Returns:

  • (self)

Since:

  • 0.3.0



167
168
169
170
171
172
# File 'lib/bin_struct/bit_attr.rb', line 167

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



176
177
178
179
180
181
182
183
184
# File 'lib/bin_struct/bit_attr.rb', line 176

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



189
190
191
192
# File 'lib/bin_struct/bit_attr.rb', line 189

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

#type_name::String

Get type name

Returns:

  • (::String)

Since:

  • 0.3.0



153
154
155
156
157
158
159
160
161
162
# File 'lib/bin_struct/bit_attr.rb', line 153

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