ffi-bitfield 0.0.7 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6e82e912397a405df792824503984be18325c6c22b76307a0fc9d7fe65c5a95f
4
- data.tar.gz: a3bbf7a5ecdcba6e4627c80e9a108788e281fc18f9d4abededf5d47833b0783d
3
+ metadata.gz: 50775cc156bce79d4d20153303484ba80d19d23707d5413ea2557676260e8b38
4
+ data.tar.gz: 941e057d7cd548da1fd133f81143e573d7795c060d7678334c74cd1ed7cdaa31
5
5
  SHA512:
6
- metadata.gz: 76c80c9d0444042ad7ca1b8c28b084562c84b9ac843f0f23a3253444fefee3f4a959da752395d4fa43fc663aab4b1854bb5bd3e21b2550fca2b5c4cc8560ad4a
7
- data.tar.gz: 33b72012820da5d15fcf1f753cd2a1203c3bd467b0d4596b429e7c46ba485bee91d45424142c4411996545054eb8f3bd368d53fa477cf7bde330c680689a9276
6
+ metadata.gz: 7329ad0a6bf66f580af0fdbbc3219774a53e7624a78e8e3891562150444282c0b2aae26b5eb4382edf8f67e27e66224aaf32592757f6e813105ab432a5e646a5
7
+ data.tar.gz: 3e4bb498d57114b6f9ccaf140d5789239609ff402f3be888d419fefa66957547659f1d5ab8577439f9fb98ad89fa6d56869f30a985b04486bc9bc90799c9b82a
data/README.md CHANGED
@@ -99,7 +99,7 @@ bundle exec rake test
99
99
  Your feedback is important.
100
100
 
101
101
  ffi-bitfield is a library under development, so even small improvements like typofix are welcome! Please feel free to send us your pull requests.
102
- Bug reports and pull requests are welcome on GitHub at https://github.com/kojix2/bitstruct.
102
+ Bug reports and pull requests are welcome on GitHub at https://github.com/kojix2/ffi-bitfield.
103
103
 
104
104
  Do you need commit rights to my repository?
105
105
  Do you want to get admin rights and take over the project?
@@ -2,10 +2,24 @@
2
2
 
3
3
  module FFI
4
4
  module BitField
5
- # Layout provides the `bit_fields` method for registering field members.
5
+ # Layout provides methods for defining bit field layouts.
6
+ # This module is extended by BitStruct and ManagedBitStruct classes.
6
7
  module Layout
7
- # @param [Array] layout_args
8
- # @return [Symbol] parent_name
8
+ # Defines bit fields within a parent field.
9
+ #
10
+ # @param [Array] layout_args An array where the first element is the parent field name,
11
+ # followed by alternating field name and bit width pairs
12
+ # @return [Symbol] parent_name The name of the parent field
13
+ #
14
+ # @example Define bit fields in an 8-bit integer
15
+ # bit_fields :flags,
16
+ # :read, 1, # 1 bit for read permission
17
+ # :write, 1, # 1 bit for write permission
18
+ # :execute, 1, # 1 bit for execute permission
19
+ # :unused, 5 # 5 unused bits
20
+ #
21
+ # @note The total bit width should not exceed the size of the parent field.
22
+ # For example, a :uint8 field can hold at most 8 bits.
9
23
  def bit_fields(*layout_args)
10
24
  # The reason for using class instance variable here instead of class variable
11
25
  # is not because class instance variables are clean,
@@ -2,36 +2,95 @@
2
2
 
3
3
  module FFI
4
4
  module BitField
5
- # Properties provides methods to read and write bit fields.
5
+ # Property provides methods for reading and writing bit field values.
6
+ # This module is included in BitStruct and ManagedBitStruct classes.
6
7
  module Property
7
- # @param [Symbol] member_name
8
- # @return [Integer] value
8
+ # Reads a value from a bit field or regular field.
9
+ #
10
+ # @param [Symbol] member_name The name of the field to read
11
+ # @return [Integer] The value of the field
12
+ #
13
+ # @example Reading a bit field
14
+ # struct[:flag1] # => 1
9
15
  def [](member_name)
10
16
  parent_name, start, width = member_value_info(member_name)
11
17
  if parent_name
12
18
  value = get_member_value(parent_name)
13
- value[start, width]
19
+ (value >> start) & ((1 << width) - 1)
14
20
  else
15
21
  get_member_value(member_name)
16
22
  end
17
23
  end
18
24
 
25
+ # Writes a value to a bit field or regular field.
26
+ #
27
+ # @param [Symbol] member_name The name of the field to write
28
+ # @param [Integer] value The value to write
29
+ # @return [Integer] The written value
30
+ # @raise [ArgumentError] If the value is too large for the bit field
31
+ # @raise [ArgumentError] If the value is too small (negative) for the bit field
32
+ # @raise [ArgumentError] If the member name is not a valid bit field
33
+ # @raise [TypeError] If the value is not an Integer
34
+ #
35
+ # @example Writing to a bit field
36
+ # struct[:flag1] = 1
37
+ # @example Writing a negative value (bit-flipped)
38
+ # struct[:field] = -1 # Sets all bits to 1
19
39
  def []=(member_name, value)
20
- parent_name, start, width = member_value_info(member_name)
21
- if parent_name
22
- raise ArgumentError, "Value #{value} is larger than bit_length: #{width}" if value.bit_length > width
40
+ # Ensure value is an Integer
41
+ raise TypeError, "Value must be an Integer, got #{value.class}" unless value.is_a?(Integer)
23
42
 
24
- parent_value = get_member_value(parent_name)
25
- new_value = (((1 << width) - 1 << start) & parent_value ^ parent_value) |
26
- (value << start)
27
- set_member_value(parent_name, new_value)
28
- else
29
- set_member_value(member_name, value)
43
+ # Get bit field information
44
+ field_info = member_value_info(member_name)
45
+
46
+ # If not a bit field, delegate to regular field setter
47
+ return set_member_value(member_name, value) unless field_info
48
+
49
+ # Extract bit field information
50
+ parent_name, start, width = field_info
51
+
52
+ # Calculate max value for this bit width
53
+ max_value = (1 << width) - 1
54
+
55
+ # Handle negative values by bit-flipping
56
+ if value.negative?
57
+ # For negative values, we interpret them as bit-flipped positive values
58
+ # For example, with 4 bits, -1 becomes 1111 (15), -2 becomes 1110 (14), etc.
59
+
60
+ # Check if the negative value is within range
61
+ # For bit-flipping, valid range is -(2^n) to -1
62
+ min_value = -(1 << width)
63
+ if value < min_value
64
+ raise ArgumentError, "Value #{value} is too small for bit_length: #{width}, minimum is #{min_value}"
65
+ end
66
+
67
+ # Convert negative value to bit-flipped positive value
68
+ # -1 -> 15, -2 -> 14, etc.
69
+ value = max_value + value + 1
70
+
71
+ # Sanity check after conversion
72
+ if value.negative? || value > max_value
73
+ raise ArgumentError, "Internal error: converted value #{value} is out of range for bit_length: #{width}"
74
+ end
75
+ elsif value > max_value
76
+ # For positive values, check if they fit in the bit width
77
+ raise ArgumentError, "Value #{value} is too large for bit_length: #{width}, maximum is #{max_value}"
30
78
  end
79
+
80
+ # Update the parent field with the new bit field value
81
+ parent_value = get_member_value(parent_name)
82
+ mask = ((1 << width) - 1) << start
83
+ new_value = (parent_value & ~mask) | ((value & ((1 << width) - 1)) << start)
84
+
85
+ set_member_value(parent_name, new_value)
31
86
  end
32
87
 
33
88
  private
34
89
 
90
+ # Gets information about a bit field member.
91
+ #
92
+ # @param [Symbol] member_name The name of the bit field
93
+ # @return [Array, nil] An array containing [parent_name, start_bit, width] or nil if not a bit field
35
94
  def member_value_info(member_name)
36
95
  self.class.instance_variable_get(:@bit_field_hash_table)[member_name]
37
96
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  module FFI
4
4
  module BitField
5
- VERSION = '0.0.7'
5
+ # Current version of the ffi-bitfield gem.
6
+ VERSION = '0.0.8'
6
7
  end
7
8
  end
data/lib/ffi/bit_field.rb CHANGED
@@ -4,8 +4,26 @@ require_relative 'bit_field/version'
4
4
  require_relative 'bit_struct'
5
5
  require_relative 'managed_bit_struct'
6
6
 
7
+ # Foreign Function Interface module for Ruby.
8
+ # This is the main namespace for the Ruby-FFI library.
7
9
  module FFI
8
- # This module is just a namespace.
10
+ # BitField provides bit field functionality for Ruby-FFI.
11
+ # It allows defining, reading, and writing bit fields within FFI structs.
12
+ #
13
+ # @example Basic usage
14
+ # class MyStruct < FFI::BitStruct
15
+ # layout \
16
+ # :flags, :uint8
17
+ #
18
+ # bit_fields :flags,
19
+ # :flag1, 1,
20
+ # :flag2, 1,
21
+ # :value, 6
22
+ # end
23
+ #
24
+ # struct = MyStruct.new
25
+ # struct[:flag1] = 1
26
+ # struct[:value] = 42
9
27
  module BitField
10
28
  end
11
29
  end
@@ -6,7 +6,25 @@ require_relative 'bit_field/layout'
6
6
  require_relative 'bit_field/property'
7
7
 
8
8
  module FFI
9
- # Subclass of FFI::Struct that support bit fields.
9
+ # Subclass of FFI::Struct that supports bit fields.
10
+ # Allows defining and accessing individual bits within integer fields.
11
+ #
12
+ # @example Define a struct with bit fields
13
+ # class Flags < FFI::BitStruct
14
+ # layout \
15
+ # :value, :uint8
16
+ #
17
+ # bit_fields :value,
18
+ # :read, 1, # 1 bit for read permission
19
+ # :write, 1, # 1 bit for write permission
20
+ # :execute, 1, # 1 bit for execute permission
21
+ # :unused, 5 # 5 unused bits
22
+ # end
23
+ #
24
+ # flags = Flags.new
25
+ # flags[:read] = 1
26
+ # flags[:write] = 1
27
+ # puts flags[:value] # => 3
10
28
  class BitStruct < Struct
11
29
  # [] is defined in FFI::Struct
12
30
  alias get_member_value []
@@ -6,7 +6,28 @@ require_relative 'bit_field/layout'
6
6
  require_relative 'bit_field/property'
7
7
 
8
8
  module FFI
9
- # Subclass of FFI::ManagedStruct that support bit fields.
9
+ # Subclass of FFI::ManagedStruct that supports bit fields.
10
+ # Combines memory management with bit field functionality.
11
+ #
12
+ # Use this class when you need automatic memory management for your structs
13
+ # with bit fields. You must implement the self.release method to handle
14
+ # memory cleanup.
15
+ #
16
+ # @example Define a managed struct with bit fields
17
+ # class ManagedFlags < FFI::ManagedBitStruct
18
+ # layout \
19
+ # :value, :uint8
20
+ #
21
+ # bit_fields :value,
22
+ # :read, 1,
23
+ # :write, 1,
24
+ # :execute, 1,
25
+ # :unused, 5
26
+ #
27
+ # def self.release(ptr)
28
+ # # Custom memory cleanup code
29
+ # end
30
+ # end
10
31
  class ManagedBitStruct < ManagedStruct
11
32
  # [] is defined in FFI::Struct
12
33
  alias get_member_value []
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ffi-bitfield
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - kojix2
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2022-05-16 00:00:00.000000000 Z
10
+ date: 2025-03-21 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: ffi
@@ -43,7 +42,6 @@ homepage: https://github.com/kojix2/ffi-bitfield
43
42
  licenses:
44
43
  - MIT
45
44
  metadata: {}
46
- post_install_message:
47
45
  rdoc_options: []
48
46
  require_paths:
49
47
  - lib
@@ -58,8 +56,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
58
56
  - !ruby/object:Gem::Version
59
57
  version: '0'
60
58
  requirements: []
61
- rubygems_version: 3.3.7
62
- signing_key:
59
+ rubygems_version: 3.6.2
63
60
  specification_version: 4
64
61
  summary: bit fields for Ruby-FFI
65
62
  test_files: []