ffi-bitfield 0.0.8 → 0.0.10

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: 50775cc156bce79d4d20153303484ba80d19d23707d5413ea2557676260e8b38
4
- data.tar.gz: 941e057d7cd548da1fd133f81143e573d7795c060d7678334c74cd1ed7cdaa31
3
+ metadata.gz: 7a7ec1a2c9da825cb036e42ad7b0e3745704e5bb9fba89394993c3043da9e521
4
+ data.tar.gz: 10d2ecd8efcb3312228d684b0e15ccc32654de39dc4399065267ad5866e2d0cb
5
5
  SHA512:
6
- metadata.gz: 7329ad0a6bf66f580af0fdbbc3219774a53e7624a78e8e3891562150444282c0b2aae26b5eb4382edf8f67e27e66224aaf32592757f6e813105ab432a5e646a5
7
- data.tar.gz: 3e4bb498d57114b6f9ccaf140d5789239609ff402f3be888d419fefa66957547659f1d5ab8577439f9fb98ad89fa6d56869f30a985b04486bc9bc90799c9b82a
6
+ metadata.gz: 688c1d48d37dc1d9f619af9da8ee5d8ac5546d8b6dcab618db5df90d603c73a4c80aac58dfc91b385da9f4e8ea90f2442e47d73441564f5e75e579d7b2636b4c
7
+ data.tar.gz: 230ed815df33fe597fdf4fa9dc61afd6b69fa625de30826cb795db58aeebeb31ffecf68ebceed6b764450169dee91949ea86006ee4238d6e058e93ad84ed0b9d
data/README.md CHANGED
@@ -70,6 +70,42 @@ s[:y] = 1
70
70
  p s[:a] # 64
71
71
  ```
72
72
 
73
+ ### Inspecting Bit Fields
74
+
75
+ You can use the `bit_field_members` method to get a hash of bit fields grouped by parent field:
76
+
77
+ ```ruby
78
+ class Flags < FFI::BitStruct
79
+ layout \
80
+ :value, :uint8
81
+
82
+ bit_fields :value,
83
+ :read, 1,
84
+ :write, 1,
85
+ :execute, 1,
86
+ :unused, 5
87
+ end
88
+
89
+ p Flags.bit_field_members
90
+ # => {:value=>[:read, :write, :execute, :unused]}
91
+ ```
92
+
93
+ For more detailed information, you can use the `bit_field_layout` method:
94
+
95
+ ```ruby
96
+ p Flags.bit_field_layout
97
+ # => {
98
+ # :value => {
99
+ # :read => { :start => 0, :width => 1 },
100
+ # :write => { :start => 1, :width => 1 },
101
+ # :execute => { :start => 2, :width => 1 },
102
+ # :unused => { :start => 3, :width => 5 }
103
+ # }
104
+ # }
105
+ ```
106
+
107
+ These methods are useful for custom pretty printing or introspection of your bit struct classes.
108
+
73
109
  ### Loading
74
110
 
75
111
  ```ruby
@@ -0,0 +1,162 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FFI
4
+ module BitField
5
+ # ClassMethods provides methods for defining bit field layouts.
6
+ # This module is extended by BitStruct and ManagedBitStruct classes.
7
+ module ClassMethods
8
+ # Returns a hash of bit fields grouped by parent field.
9
+ #
10
+ # @return [Hash] A hash where keys are parent field names and values are arrays of bit field names
11
+ #
12
+ # @example Get bit field members in a struct
13
+ # class Flags < FFI::BitStruct
14
+ # layout \
15
+ # :value, :uint8
16
+ #
17
+ # bit_fields :value,
18
+ # :read, 1,
19
+ # :write, 1,
20
+ # :execute, 1,
21
+ # :unused, 5
22
+ # end
23
+ #
24
+ # Flags.bit_field_members # => {:value => [:read, :write, :execute, :unused]}
25
+ def bit_field_members
26
+ return {} unless instance_variable_defined?(:@bit_field_hash_table)
27
+
28
+ result = {}
29
+ @bit_field_hash_table.each do |field_name, info|
30
+ parent_name = info[0]
31
+ result[parent_name] ||= []
32
+ result[parent_name] << field_name
33
+ end
34
+ result
35
+ end
36
+
37
+ # Returns a hash of bit fields with detailed layout information.
38
+ #
39
+ # @return [Hash] A hash where keys are parent field names and values are hashes of bit field details
40
+ #
41
+ # @example Get detailed bit field layout in a struct
42
+ # class Flags < FFI::BitStruct
43
+ # layout \
44
+ # :value, :uint8
45
+ #
46
+ # bit_fields :value,
47
+ # :read, 1,
48
+ # :write, 1,
49
+ # :execute, 1,
50
+ # :unused, 5
51
+ # end
52
+ #
53
+ # Flags.bit_field_layout
54
+ # # => {
55
+ # # :value => {
56
+ # # :read => { :start => 0, :width => 1 },
57
+ # # :write => { :start => 1, :width => 1 },
58
+ # # :execute => { :start => 2, :width => 1 },
59
+ # # :unused => { :start => 3, :width => 5 }
60
+ # # }
61
+ # # }
62
+ def bit_field_layout
63
+ return {} unless instance_variable_defined?(:@bit_field_hash_table)
64
+
65
+ result = {}
66
+ @bit_field_hash_table.each do |field_name, info|
67
+ parent_name, start, width = info
68
+ result[parent_name] ||= {}
69
+ result[parent_name][field_name] = { start: start, width: width }
70
+ end
71
+ result
72
+ end
73
+
74
+ # Returns a hash of bit fields with their bit offsets, grouped by parent field.
75
+ #
76
+ # @return [Hash] A hash where keys are parent field names and values are arrays of [bit_field_name, bit_offset] pairs
77
+ #
78
+ # @example Get bit field offsets in a struct
79
+ # class Flags < FFI::BitStruct
80
+ # layout \
81
+ # :value, :uint8
82
+ #
83
+ # bit_fields :value,
84
+ # :read, 1,
85
+ # :write, 1,
86
+ # :execute, 1,
87
+ # :unused, 5
88
+ # end
89
+ #
90
+ # Flags.bit_field_offsets
91
+ # # => {
92
+ # # :value => [[:read, 0], [:write, 1], [:execute, 2], [:unused, 3]]
93
+ # # }
94
+ def bit_field_offsets
95
+ return {} unless instance_variable_defined?(:@bit_field_hash_table)
96
+
97
+ result = {}
98
+
99
+ # Get byte offsets of parent fields
100
+ field_offsets = offsets.to_h
101
+
102
+ # Process each bit field
103
+ @bit_field_hash_table.each do |field_name, info|
104
+ parent_name, start, _width = info
105
+
106
+ # Get byte offset of parent field
107
+ parent_offset = field_offsets[parent_name]
108
+ next unless parent_offset
109
+
110
+ # Convert byte offset to bit offset and add bit field's start position
111
+ bit_offset = parent_offset * 8 + start
112
+
113
+ # Add to result
114
+ result[parent_name] ||= []
115
+ result[parent_name] << [field_name, bit_offset]
116
+ end
117
+
118
+ # Return result
119
+ result
120
+ end
121
+
122
+ # Defines bit fields within a parent field.
123
+ #
124
+ # @param [Array] layout_args An array where the first element is the parent field name,
125
+ # followed by alternating field name and bit width pairs
126
+ # @return [Symbol] parent_name The name of the parent field
127
+ #
128
+ # @example Define bit fields in an 8-bit integer
129
+ # bit_fields :flags,
130
+ # :read, 1, # 1 bit for read permission
131
+ # :write, 1, # 1 bit for write permission
132
+ # :execute, 1, # 1 bit for execute permission
133
+ # :unused, 5 # 5 unused bits
134
+ #
135
+ # @note The total bit width should not exceed the size of the parent field.
136
+ # For example, a :uint8 field can hold at most 8 bits.
137
+ def bit_fields(*layout_args)
138
+ # The reason for using class instance variable here instead of class variable
139
+ # is not because class instance variables are clean,
140
+ # but because sub-class of FFI::Struct cannot be inherited again.
141
+ @bit_field_hash_table = {} unless instance_variable_defined?(:@bit_field_hash_table)
142
+
143
+ parent_name = layout_args.shift.to_sym
144
+ member_names = []
145
+ widths = []
146
+ layout_args.each_slice(2) do |name, width|
147
+ member_names << name.to_sym
148
+ widths << width.to_i
149
+ end
150
+ starts = widths.inject([0]) do |result, width|
151
+ result << (result.last + width)
152
+ end
153
+ member_names.zip(starts, widths).each do |name, start, width|
154
+ @bit_field_hash_table[name] = [parent_name, start, width]
155
+ end
156
+
157
+ parent_name
158
+ end
159
+ alias bit_field bit_fields
160
+ end
161
+ end
162
+ end
@@ -2,9 +2,35 @@
2
2
 
3
3
  module FFI
4
4
  module BitField
5
- # Property provides methods for reading and writing bit field values.
5
+ # InstanceMethods provides methods for reading and writing bit field values.
6
6
  # This module is included in BitStruct and ManagedBitStruct classes.
7
- module Property
7
+ module InstanceMethods
8
+ # Returns a hash of bit fields grouped by parent field.
9
+ # Instance method version of the class method with the same name.
10
+ #
11
+ # @return [Hash] A hash where keys are parent field names and values are arrays of bit field names
12
+ #
13
+ # @example Get bit field members in a struct instance
14
+ # flags = Flags.new
15
+ # flags.bit_field_members # => {:value => [:read, :write, :execute, :unused]}
16
+ def bit_field_members
17
+ self.class.bit_field_members
18
+ end
19
+
20
+ # Returns a hash of bit fields with their bit offsets, grouped by parent field.
21
+ #
22
+ # @return [Hash] A hash where keys are parent field names and values are arrays of [bit_field_name, bit_offset] pairs
23
+ #
24
+ # @example Get bit field offsets in a struct instance
25
+ # flags = Flags.new
26
+ # flags.bit_field_offsets
27
+ # # => {
28
+ # # :value => [[:read, 0], [:write, 1], [:execute, 2], [:unused, 3]]
29
+ # # }
30
+ def bit_field_offsets
31
+ self.class.bit_field_offsets
32
+ end
33
+
8
34
  # Reads a value from a bit field or regular field.
9
35
  #
10
36
  # @param [Symbol] member_name The name of the field to read
@@ -3,6 +3,6 @@
3
3
  module FFI
4
4
  module BitField
5
5
  # Current version of the ffi-bitfield gem.
6
- VERSION = '0.0.8'
6
+ VERSION = '0.0.10'
7
7
  end
8
8
  end
@@ -2,8 +2,8 @@
2
2
 
3
3
  require 'ffi'
4
4
  require_relative 'bit_field/version'
5
- require_relative 'bit_field/layout'
6
- require_relative 'bit_field/property'
5
+ require_relative 'bit_field/class_methods'
6
+ require_relative 'bit_field/instance_methods'
7
7
 
8
8
  module FFI
9
9
  # Subclass of FFI::Struct that supports bit fields.
@@ -29,13 +29,13 @@ module FFI
29
29
  # [] is defined in FFI::Struct
30
30
  alias get_member_value []
31
31
  alias set_member_value []=
32
- extend BitField::Layout
33
- # The Property module included in the FFI::ManagedBitStruct class is
32
+ extend BitField::ClassMethods
33
+ # The InstanceMethods module included in the FFI::ManagedBitStruct class is
34
34
  # * behind the FFI::ManagedBitStruct class, but is
35
35
  # * in FRONT of the FFI::Struct class.
36
36
  # `MStruct.ancestors`
37
- # # => [MStruct, FFI::ManagedBitStruct, FFI::BitField::Property, FFI::ManagedStruct, FFI::Struct...]
37
+ # # => [MStruct, FFI::ManagedBitStruct, FFI::BitField::InstanceMethods, FFI::ManagedStruct, FFI::Struct...]
38
38
  # So you do not need to use `prepend` instead of `include`.
39
- include BitField::Property
39
+ include BitField::InstanceMethods
40
40
  end
41
41
  end
@@ -2,8 +2,8 @@
2
2
 
3
3
  require 'ffi'
4
4
  require_relative 'bit_field/version'
5
- require_relative 'bit_field/layout'
6
- require_relative 'bit_field/property'
5
+ require_relative 'bit_field/class_methods'
6
+ require_relative 'bit_field/instance_methods'
7
7
 
8
8
  module FFI
9
9
  # Subclass of FFI::ManagedStruct that supports bit fields.
@@ -32,13 +32,13 @@ module FFI
32
32
  # [] is defined in FFI::Struct
33
33
  alias get_member_value []
34
34
  alias set_member_value []=
35
- extend BitField::Layout
36
- # The Property module included in the FFI::BitStruct class is
35
+ extend BitField::ClassMethods
36
+ # The InstanceMethods module included in the FFI::BitStruct class is
37
37
  # * behind the FFI::BitStruct class, but is
38
38
  # * in FRONT of the FFI::Struct class.
39
39
  # `YourStruct.ancestors`
40
- # # => [YourStruct, FFI::BitStruct, FFI::BitField::Property, FFI::Struct...]
40
+ # # => [YourStruct, FFI::BitStruct, FFI::BitField::InstanceMethods, FFI::Struct...]
41
41
  # So you do not need to use `prepend` instead of `include`.
42
- include BitField::Property
42
+ include BitField::InstanceMethods
43
43
  end
44
44
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ffi-bitfield
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - kojix2
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-03-21 00:00:00.000000000 Z
10
+ date: 2025-04-12 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: ffi
@@ -33,8 +33,8 @@ files:
33
33
  - LICENSE.txt
34
34
  - README.md
35
35
  - lib/ffi/bit_field.rb
36
- - lib/ffi/bit_field/layout.rb
37
- - lib/ffi/bit_field/property.rb
36
+ - lib/ffi/bit_field/class_methods.rb
37
+ - lib/ffi/bit_field/instance_methods.rb
38
38
  - lib/ffi/bit_field/version.rb
39
39
  - lib/ffi/bit_struct.rb
40
40
  - lib/ffi/managed_bit_struct.rb
@@ -1,48 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module FFI
4
- module BitField
5
- # Layout provides methods for defining bit field layouts.
6
- # This module is extended by BitStruct and ManagedBitStruct classes.
7
- module Layout
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.
23
- def bit_fields(*layout_args)
24
- # The reason for using class instance variable here instead of class variable
25
- # is not because class instance variables are clean,
26
- # but because sub-class of FFI::Struct cannot be inherited again.
27
- @bit_field_hash_table = {} unless instance_variable_defined?(:@bit_field_hash_table)
28
-
29
- parent_name = layout_args.shift.to_sym
30
- member_names = []
31
- widths = []
32
- layout_args.each_slice(2) do |name, width|
33
- member_names << name.to_sym
34
- widths << width.to_i
35
- end
36
- starts = widths.inject([0]) do |result, width|
37
- result << (result.last + width)
38
- end
39
- member_names.zip(starts, widths).each do |name, start, width|
40
- @bit_field_hash_table[name] = [parent_name, start, width]
41
- end
42
-
43
- parent_name
44
- end
45
- alias bit_field bit_fields
46
- end
47
- end
48
- end