Module: FFI::BitField::Property

Included in:
FFI::BitStruct, ManagedBitStruct
Defined in:
lib/ffi/bit_field/property.rb

Overview

Property provides methods for reading and writing bit field values. This module is included in BitStruct and ManagedBitStruct classes.

Instance Method Summary collapse

Instance Method Details

#[](member_name) ⇒ Integer

Reads a value from a bit field or regular field.

Examples:

Reading a bit field

struct[:flag1]  # => 1

Parameters:

  • member_name (Symbol)

    The name of the field to read

Returns:

  • (Integer)

    The value of the field



15
16
17
18
19
20
21
22
23
# File 'lib/ffi/bit_field/property.rb', line 15

def [](member_name)
  parent_name, start, width = member_value_info(member_name)
  if parent_name
    value = get_member_value(parent_name)
    (value >> start) & ((1 << width) - 1)
  else
    get_member_value(member_name)
  end
end

#[]=(member_name, value) ⇒ Integer

Writes a value to a bit field or regular field.

Examples:

Writing to a bit field

struct[:flag1] = 1

Writing a negative value (bit-flipped)

struct[:field] = -1  # Sets all bits to 1

Parameters:

  • member_name (Symbol)

    The name of the field to write

  • value (Integer)

    The value to write

Returns:

  • (Integer)

    The written value

Raises:

  • (ArgumentError)

    If the value is too large for the bit field

  • (ArgumentError)

    If the value is too small (negative) for the bit field

  • (ArgumentError)

    If the member name is not a valid bit field

  • (TypeError)

    If the value is not an Integer



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/ffi/bit_field/property.rb', line 39

def []=(member_name, value)
  # Ensure value is an Integer
  raise TypeError, "Value must be an Integer, got #{value.class}" unless value.is_a?(Integer)

  # Get bit field information
  field_info = member_value_info(member_name)

  # If not a bit field, delegate to regular field setter
  return set_member_value(member_name, value) unless field_info

  # Extract bit field information
  parent_name, start, width = field_info

  # Calculate max value for this bit width
  max_value = (1 << width) - 1

  # Handle negative values by bit-flipping
  if value.negative?
    # For negative values, we interpret them as bit-flipped positive values
    # For example, with 4 bits, -1 becomes 1111 (15), -2 becomes 1110 (14), etc.

    # Check if the negative value is within range
    # For bit-flipping, valid range is -(2^n) to -1
    min_value = -(1 << width)
    if value < min_value
      raise ArgumentError, "Value #{value} is too small for bit_length: #{width}, minimum is #{min_value}"
    end

    # Convert negative value to bit-flipped positive value
    # -1 -> 15, -2 -> 14, etc.
    value = max_value + value + 1

    # Sanity check after conversion
    if value.negative? || value > max_value
      raise ArgumentError, "Internal error: converted value #{value} is out of range for bit_length: #{width}"
    end
  elsif value > max_value
    # For positive values, check if they fit in the bit width
    raise ArgumentError, "Value #{value} is too large for bit_length: #{width}, maximum is #{max_value}"
  end

  # Update the parent field with the new bit field value
  parent_value = get_member_value(parent_name)
  mask = ((1 << width) - 1) << start
  new_value = (parent_value & ~mask) | ((value & ((1 << width) - 1)) << start)

  set_member_value(parent_name, new_value)
end